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:
parent
16c479a77a
commit
ce7dc08514
5 changed files with 174 additions and 6 deletions
|
|
@ -13,4 +13,4 @@ Guide
|
|||
debug
|
||||
perf
|
||||
advanced
|
||||
|
||||
malloc
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
68
mps/manual/source/guide/malloc.rst
Normal file
68
mps/manual/source/guide/malloc.rst
Normal 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
74
mps/test/function/229.c
Normal 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;
|
||||
}
|
||||
|
|
@ -168,3 +168,4 @@ function/224.c
|
|||
% 225 -- no such test
|
||||
function/226.c
|
||||
function/227.c
|
||||
function/229.c
|
||||
Loading…
Add table
Add a link
Reference in a new issue