1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-26 00:34:17 -07:00

Add a section to the guide explaining how to implement malloc and free.

Copied from Perforce
 Change: 187399
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2014-10-25 22:31:07 +01:00
parent 16c479a77a
commit ce7dc08514
5 changed files with 174 additions and 6 deletions

View file

@ -13,4 +13,4 @@ Guide
debug
perf
advanced
malloc

View file

@ -266,6 +266,25 @@ code for creating the object format for the toy Scheme interpreter::
} MPS_ARGS_END(args);
if (res != MPS_RES_OK) error("Couldn't create obj format");
The keyword arguments specify the :term:`alignment` and the
:term:`format methods` required by the AMC pool class. These are
described in the following sections.
.. topics::
:ref:`topic-format`.
.. index::
single: alignment
single: alignment; object
single: Scheme; object alignment
.. _guide-lang-alignment:
Alignment
^^^^^^^^^
The argument for the keyword :c:macro:`MPS_KEY_FMT_ALIGN` is the
:term:`alignment` of objects belonging to this format. Determining the
alignment is hard to do portably, because it depends on the target
@ -294,13 +313,19 @@ memory. Here are some things you might try:
#define ALIGNMENT sizeof(mps_word_t)
The other keyword arguments specify the :term:`format methods`
required by the AMC pool class, which are described in the following
sections.
#. The MPS interface provides the type :c:type:`MPS_PF_ALIGN`, which
is the :term:`natural alignment` of the platform: the largest
alignment that might be required. So as a last resort, you can
use::
.. topics::
#define ALIGNMENT MPS_PF_ALIGN
:ref:`topic-format`.
But this may be larger than necessary and so waste space. For
example, on Windows on x86-64, :c:type:`MPS_PF_ALIGN` is 16 bytes,
but this is only necessary for SSE_ types; ordinary types on this
platform require no more than 8-byte alignment.
.. _SSE: http://msdn.microsoft.com/en-us/library/t467de55.aspx
.. index::

View file

@ -0,0 +1,68 @@
.. index::
single: malloc; implementing
single: free; implementing
.. _guide-malloc:
Implementing malloc and free
============================
The MPS function :c:func:`mps_free` is unlike the Standard C Library
function :c:func:`free` in that it takes a ``size`` argument. That's
because it's nearly always the case that either the size of an object
is known statically based on its type (for example, a structure), or
else the size of the object is easily computed from information that
needs to be stored anyway (for example, a vector), and so memory can
be saved by not storing the size separately.
But sometimes you need to interact with :term:`foreign code` which
requires :c:func:`malloc` and :c:func:`free` (or a pair of functions
with the same interface). How can you use the MPS to implement these
functions? By storing the size in a header adjacent to the object,
like this::
#include "mps.h"
static mps_pool_t malloc_pool;
typedef union {
size_t size;
char alignment[MPS_PF_ALIGN]; /* see note below */
} header_u;
void *malloc(size_t size) {
mps_res_t res;
mps_addr_t p;
header_u *header;
size += sizeof *header;
res = mps_alloc(&p, malloc_pool, size);
if (res != MPS_RES_OK)
return NULL;
header = p;
header->size = size;
return header + 1;
}
void free(void *p) {
if (p) {
header_u *header = ((header_u *)p) - 1;
mps_free(malloc_pool, header, header->size);
}
}
The ``alignment`` member of ``union header_u`` ensures that
allocations are aligned to the platform's :term:`natural alignment`
(see :ref:`guide-lang-alignment`).
The pool needs to belong to a :term:`manually managed <manual memory
management>` pool class, for example :ref:`pool-mvff` (or its
:ref:`debugging counterpart <topic-debugging>`)::
#include "mpscmvff.h"
void malloc_pool_init(mps_arena_t arena) {
mps_res_t res;
res = mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none);
if (res != RES_OK)
abort();
}

74
mps/test/function/229.c Normal file
View file

@ -0,0 +1,74 @@
/*
TEST_HEADER
id = $Id: //info.ravenbrook.com/project/mps/master/test/function/1.c#2 $
summary = test malloc and free (for the manual)
language = c
link = testlib.o
parameters = POINTERS=1000 ITERATIONS=10000
END_HEADER
*/
#include "mpscmvff.h"
#include "testlib.h"
static mps_pool_t malloc_pool;
typedef union {
size_t size;
char alignment[MPS_PF_ALIGN];
} header_u;
static void *xmalloc(size_t size)
{
mps_res_t res;
mps_addr_t p;
header_u *header;
size += sizeof *header;
res = mps_alloc(&p, malloc_pool, size);
if (res != MPS_RES_OK)
return NULL;
header = p;
header->size = size;
return header + 1;
}
static void xfree(void *p)
{
if (p) {
header_u *header = ((header_u *)p) - 1;
mps_free(malloc_pool, header, header->size);
}
}
static void test(void)
{
mps_arena_t arena;
size_t i, j;
void *p[POINTERS] = {0};
cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
"create arena");
cdie(mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none),
"create pool");
for (i = 0; i < ITERATIONS; ++i) {
j = ranint(POINTERS);
xfree(p[j]);
p[j] = xmalloc(ranint(POINTERS));
}
for (j = 0; j < POINTERS; ++j) {
xfree(p[j]);
}
asserts(mps_pool_free_size(malloc_pool) == mps_pool_total_size(malloc_pool),
"free size != total_size");
mps_pool_destroy(malloc_pool);
mps_arena_destroy(arena);
}
int main(void)
{
easy_tramp(test);
pass();
return 0;
}

View file

@ -168,3 +168,4 @@ function/224.c
% 225 -- no such test
function/226.c
function/227.c
function/229.c