From 6be8f3c087f4ccc7fd5ed447b0cb4e32b0fe898f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 1 Oct 2014 08:04:12 +0100 Subject: [PATCH 01/40] Branching master to branch/2014-10-01/finalize. Copied from Perforce Change: 187098 ServerID: perforce.ravenbrook.com From 62b29ca9cd0fe0d10c0fb15216e6d8260ea0016e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 1 Oct 2014 17:39:37 +0100 Subject: [PATCH 02/40] Test cases for mps_arena_has_addr. Copied from Perforce Change: 187102 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 8 ++++++++ mps/code/mpsicv.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/mps/code/apss.c b/mps/code/apss.c index 89604831dcf..0d198cb7573 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -87,6 +87,14 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, check_allocated_size(pool, ap, allocated); } + /* Check introspection functions */ + for (i = 0; i < NELEMS(ps); ++i) { + mps_pool_t addr_pool = NULL; + Insist(mps_arena_has_addr(arena, ps[i])); + Insist(mps_addr_pool(&addr_pool, arena, ps[i])); + Insist(addr_pool == pool); + } + mps_pool_check_fenceposts(pool); for (k=0; k Date: Thu, 2 Oct 2014 08:30:55 +0100 Subject: [PATCH 03/40] Extend finalcv test to check all the automatically managed pool classes. Check that you can't register objects for finalization in manually managed pools. Remove design.mps.poolmrg.test.promise.ut.not -- this is tested by finaltest.c. Copied from Perforce Change: 187107 ServerID: perforce.ravenbrook.com --- mps/code/finalcv.c | 76 +++++++++++++++++++++++++++++------------- mps/design/poolmrg.txt | 4 --- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index 9f22226dc17..18ea0339e1c 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -24,6 +24,12 @@ #include "mps.h" #include "mpsavm.h" #include "mpscamc.h" +#include "mpscams.h" +#include "mpscawl.h" +#include "mpsclo.h" +#include "mpscmfs.h" +#include "mpscmv.h" +#include "mpscmvff.h" #include "mpslib.h" #include "mpstd.h" #include "testlib.h" @@ -36,7 +42,7 @@ #define churnFACTOR 10 #define finalizationRATE 6 #define gcINTERVAL ((size_t)150 * 1024) -#define collectionCOUNT 3 +#define messageCOUNT 3 /* 3 words: wrapper | vector-len | first-slot */ #define vectorSIZE (3*sizeof(mps_word_t)) @@ -95,35 +101,37 @@ enum { }; -static void *test(void *arg, size_t s) +static void test(mps_arena_t arena, mps_pool_class_t pool_class) { - unsigned i; /* index */ + size_t i; /* index */ mps_ap_t ap; mps_fmt_t fmt; mps_chain_t chain; - mps_pool_t amc; + mps_pool_t pool; mps_res_t e; mps_root_t mps_root[2]; mps_addr_t nullref = NULL; int state[rootCOUNT]; - mps_arena_t arena; - void *p = NULL; mps_message_t message; + size_t messages = 0; + void *p; - arena = (mps_arena_t)arg; - (void)s; + printf("---- finalcv: pool class %s ----\n", pool_class->name); die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain), - "pool_create amc\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); + die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n"); + } MPS_ARGS_END(args); die(mps_root_create_table(&mps_root[0], arena, mps_rank_exact(), (mps_rm_t)0, root, (size_t)rootCOUNT), "root_create\n"); die(mps_root_create_table(&mps_root[1], arena, mps_rank_exact(), (mps_rm_t)0, &p, (size_t)1), "root_create\n"); - die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n"); + die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n"); /* Make registered-for-finalization objects. */ /* */ @@ -142,12 +150,10 @@ static void *test(void *arg, size_t s) } p = NULL; - die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe"); - mps_message_type_enable(arena, mps_message_type_finalization()); /* */ - while (mps_collections(arena) < collectionCOUNT) { + while (messages < messageCOUNT) { /* Perhaps cause (minor) collection */ churn(ap); @@ -197,36 +203,58 @@ static void *test(void *arg, size_t s) if (rnd() % 2 == 0) root[objind] = objaddr; mps_message_discard(arena, message); + ++ messages; } } - /* @@@@ missing */ - - mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(mps_root[1]); mps_root_destroy(mps_root[0]); - mps_pool_destroy(amc); + mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(fmt); +} - return NULL; + +/* test_fail -- check that you can't register objects for finalization + * in manually managed pools + */ + +static void test_fail(mps_arena_t arena, mps_pool_class_t pool_class) +{ + size_t size = 4096; + mps_pool_t pool; + mps_addr_t p; + + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, size); + die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n"); + } MPS_ARGS_END(args); + die(mps_alloc(&p, pool, size), "mps_alloc"); + Insist(mps_finalize(arena, &p) == MPS_RES_UNIMPL); + mps_pool_destroy(pool); } int main(int argc, char *argv[]) { mps_arena_t arena; - mps_thr_t thread; - void *r; testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); - die(mps_thread_reg(&thread, arena), "thread_reg\n"); - mps_tramp(&r, test, arena, 0); - mps_thread_dereg(thread); + + test_fail(arena, mps_class_mfs()); + test_fail(arena, mps_class_mv()); + test_fail(arena, mps_class_mvff()); + + test(arena, mps_class_amc()); + test(arena, mps_class_amcz()); + test(arena, mps_class_awl()); + test(arena, mps_class_ams()); + test(arena, mps_class_lo()); + mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); diff --git a/mps/design/poolmrg.txt b/mps/design/poolmrg.txt index 9f01ad3bca7..1460b39117c 100644 --- a/mps/design/poolmrg.txt +++ b/mps/design/poolmrg.txt @@ -619,10 +619,6 @@ All objects from the MRG pool will then be freed (thus dropping all references to the AMC objects). This will test `.promise.faithful`_ and `.promise.live`_. -_`.test.promise.ut.not`: The following part of the test has not -implemented. This is because the messaging system has not yet been -implemented. - _`.test.promise.ut.alloc`: A number of objects will be allocated in the AMC pool. From 3ecf3d50c6122b2d34837b13dddbe6d2a35f370e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 09:13:21 +0100 Subject: [PATCH 04/40] Make arenahasaddr work for all pools (not just for pools with segments). Copied from Perforce Change: 187108 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 30a65479f9b..67c053e42e8 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -1394,10 +1394,10 @@ static void ArenaTrivCompact(Arena arena, Trace trace) Bool ArenaHasAddr(Arena arena, Addr addr) { - Seg seg; + Tract tract; AVERT(Arena, arena); - return SegOfAddr(&seg, arena, addr); + return TractOfAddr(&tract, arena, addr); } From 0048f341e022c12f27eeb6577c65501340fd5b8e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 10:27:57 +0100 Subject: [PATCH 05/40] Arenafinalize now asserts that the object belongs to a finalizable (attrgc) pool. (it's a programming error to try to register a non-finalizable object for finalization.) Can't test this behaviour via the smoke tests, unfortunately. Document the performance problem with mps_definalize, so that users aren't tempted into using it inappropriately. Copied from Perforce Change: 187109 ServerID: perforce.ravenbrook.com --- mps/code/finalcv.c | 27 -------------------- mps/code/global.c | 10 +++++--- mps/manual/source/guide/advanced.rst | 32 +++++++++++++----------- mps/manual/source/topic/finalization.rst | 13 +++++++--- 4 files changed, 33 insertions(+), 49 deletions(-) diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index 18ea0339e1c..f31065edd92 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -27,9 +27,6 @@ #include "mpscams.h" #include "mpscawl.h" #include "mpsclo.h" -#include "mpscmfs.h" -#include "mpscmv.h" -#include "mpscmvff.h" #include "mpslib.h" #include "mpstd.h" #include "testlib.h" @@ -216,26 +213,6 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class) } -/* test_fail -- check that you can't register objects for finalization - * in manually managed pools - */ - -static void test_fail(mps_arena_t arena, mps_pool_class_t pool_class) -{ - size_t size = 4096; - mps_pool_t pool; - mps_addr_t p; - - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, size); - die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n"); - } MPS_ARGS_END(args); - die(mps_alloc(&p, pool, size), "mps_alloc"); - Insist(mps_finalize(arena, &p) == MPS_RES_UNIMPL); - mps_pool_destroy(pool); -} - - int main(int argc, char *argv[]) { mps_arena_t arena; @@ -245,10 +222,6 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); - test_fail(arena, mps_class_mfs()); - test_fail(arena, mps_class_mv()); - test_fail(arena, mps_class_mvff()); - test(arena, mps_class_amc()); test(arena, mps_class_amcz()); test(arena, mps_class_awl()); diff --git a/mps/code/global.c b/mps/code/global.c index 0a36ed18b2f..efffd564ad4 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -857,17 +857,19 @@ Bool ArenaStep(Globals globals, double interval, double multiplier) Res ArenaFinalize(Arena arena, Ref obj) { Res res; + Pool refpool; AVERT(Arena, arena); - AVER(ArenaHasAddr(arena, (Addr)obj)); + AVER(PoolOfAddr(&refpool, arena, (Addr)obj)); + AVER(PoolHasAttr(refpool, AttrGC)); if (!arena->isFinalPool) { - Pool pool; + Pool finalpool; - res = PoolCreate(&pool, arena, PoolClassMRG(), argsNone); + res = PoolCreate(&finalpool, arena, PoolClassMRG(), argsNone); if (res != ResOK) return res; - arena->finalPool = pool; + arena->finalPool = finalpool; arena->isFinalPool = TRUE; } diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index 0535b9b3f18..7dd4b20b63d 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -28,14 +28,6 @@ call ``close-input-file``, then the underlying file handle should still be closed when the port object :term:`dies `. This procedure is known as :term:`finalization`. -.. note:: - - It's generally a bad idea to depend on finalization to release your - resources (see the :ref:`topic-finalization-cautions` section in - :ref:`topic-finalization`). Treat it as a last resort when more - reliable mechanisms for releasing resources (like Scheme's - ``with-open-input-file``) aren't available. - Any block in an :term:`automatically managed ` :term:`pool` can be registered for finalization by calling :c:func:`mps_finalize`. In the toy Scheme interpreter, this can be done @@ -138,11 +130,20 @@ Here's an example session showing finalization taking place: not_condemned 0 clock: 3807 -The toy Scheme interpreter :dfn:`definalizes` ports by calling -:c:func:`mps_definalize` when they are closed. This is purely an -optimization: setting ``stream`` to ``NULL`` ensures that the file -handle wouldn't be closed more than once, even if the port object were -later finalized. +It's wise not to depend on finalization as the only method for +releasing resources (see the :ref:`topic-finalization-cautions` +section in :ref:`topic-finalization`), because the garbage collector +does not promise to collect particular objects at particular times, +and in any case it does so only when it can prove that the object is +:term:`dead`. So it is best to provide a reliable mechanism for +releasing the resource (here, the Scheme function +``close-input-port``), and use finalization as a backup strategy. + +But this raises the possibility that a port will be closed twice: once +via ``close-input-port`` and a second time via finalization. So it's +necessary to make ports robust against be closed multiple times. The +toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this +ensures that the file handle won't be closed more than once. .. code-block:: c :emphasize-lines: 8 @@ -154,10 +155,13 @@ later finalized. mps_addr_t port_ref = port; fclose(port->port.stream); port->port.stream = NULL; - mps_definalize(arena, &port_ref); } } +Note that because finalization messages are processed synchronously +via the message queue (and the Scheme interpreter is single-threaded) +there is no need for a lock here. + It's still possible that the toy Scheme interpreter might run out of open file handles despite having some or all of its port objects being finalizable. That's because the arena's message queue is only polled diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst index 5b65d9945dd..7edadb9e3cc 100644 --- a/mps/manual/source/topic/finalization.rst +++ b/mps/manual/source/topic/finalization.rst @@ -221,10 +221,8 @@ Finalization interface :term:`result code` if not. This function registers the block pointed to by ``*ref_p`` for - finalization. This block must have been allocated from a - :term:`pool` in ``arena``. Violations of this constraint may not - be checked by the MPS, and may be unsafe, causing the MPS to crash - in undefined ways. + finalization. This block must have been allocated from an + automatically managed :term:`pool` in ``arena``. .. note:: @@ -252,6 +250,13 @@ Finalization interface avoid placing the restriction on the :term:`client program` that the C call stack be a :term:`root`. + .. warning:: + + Definalization is not yet efficient: the current + implementation just loops over all finalized objects. If you + need efficient definalization, please :ref:`contact us + `. + .. index:: pair: finalization; message From 2a9e74ef82e0d15d9eb64bb2b06d3e02c87249e1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 11:08:37 +0100 Subject: [PATCH 06/40] Add test case for registering an unfinalizable object for finalization. Copied from Perforce Change: 187110 ServerID: perforce.ravenbrook.com --- mps/test/function/228.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 mps/test/function/228.c diff --git a/mps/test/function/228.c b/mps/test/function/228.c new file mode 100644 index 00000000000..3b6e817a040 --- /dev/null +++ b/mps/test/function/228.c @@ -0,0 +1,40 @@ +/* +TEST_HEADER + id = $Id$ + summary = can't register unfinalizable objects for finalization + language = c + link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c +END_HEADER +*/ + +#include "testlib.h" +#include "mpscmvff.h" +#include "mpsavm.h" + +static void test(void) +{ + mps_arena_t arena; + mps_pool_t pool; + mps_addr_t p; + + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "arena_create"); + die(mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none), + "pool_create"); + die(mps_alloc(&p, pool, 4096), "alloc"); + die(mps_finalize(arena, &p), "finalize"); + + mps_pool_destroy(pool); + mps_arena_destroy(arena); +} + + +int main(void) +{ + test(); + pass(); + return 0; +} From 0292613b0cce2bd9a350178c206266f29197f803 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 11:20:43 +0100 Subject: [PATCH 07/40] Release notes for job003865 and job003866. Copied from Perforce Change: 187112 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index fc9cc438c55..e7718a1cbf1 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -17,6 +17,22 @@ Interface changes but is deprecated. +Other changes +------------- + +#. Unfinalizable objects can no longer be registered for finalization. + Previously the objects would be registered but never finalized. See + job003865_. + + .. _job003865: https://www.ravenbrook.com/project/mps/issue/job003865/ + +#. :c:func:`mps_arena_has_addr` now returns the correct result for + objects allocated from the :ref:`pool-mfs`, :ref:`pool-mv`, and + :ref:`pool-mvff` pools. See job003866_. + + .. _job003866: https://www.ravenbrook.com/project/mps/issue/job003866/ + + .. _release-notes-1.114: Release 1.114.0 From 0aa611f22c467ca190b207bc7b2136df81a9efec Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 13:49:28 +0100 Subject: [PATCH 08/40] Don't call mps_definalize in the example scheme interpreter: it's not actually an optimization because of the inefficient implementation. Copied from Perforce Change: 187123 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 10 ---------- mps/example/scheme/scheme.c | 10 ---------- mps/manual/source/guide/advanced.rst | 1 - 3 files changed, 21 deletions(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 82b541256d5..f73bf06512a 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -991,22 +991,12 @@ static char *symbol_name(obj_t symbol) } -/* port_close -- close and definalize a port %%MPS - * - * Ports objects are registered for finalization when they are created - * (see make_port). When closed, we definalize them. This is purely an - * optimization: it would be harmless to finalize them because setting - * 'stream' to NULL prevents the stream from being closed multiple - * times. See topic/finalization. - */ static void port_close(obj_t port) { assert(TYPE(port) == TYPE_PORT); if(port->port.stream != NULL) { - mps_addr_t port_ref = port; fclose(port->port.stream); port->port.stream = NULL; - mps_definalize(arena, &port_ref); } } diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 66112f8be5e..794fdfa77d4 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -1017,22 +1017,12 @@ static void table_delete(obj_t tbl, obj_t key) } -/* port_close -- close and definalize a port %%MPS - * - * Ports objects are registered for finalization when they are created - * (see make_port). When closed, we definalize them. This is purely an - * optimization: it would be harmless to finalize them because setting - * 'stream' to NULL prevents the stream from being closed multiple - * times. See topic/finalization. - */ static void port_close(obj_t port) { assert(TYPE(port) == TYPE_PORT); if(port->port.stream != NULL) { - mps_addr_t port_ref = port; fclose(port->port.stream); port->port.stream = NULL; - mps_definalize(arena, &port_ref); } } diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index 7dd4b20b63d..4b6331a2234 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -152,7 +152,6 @@ ensures that the file handle won't be closed more than once. { assert(TYPE(port) == TYPE_PORT); if(port->port.stream != NULL) { - mps_addr_t port_ref = port; fclose(port->port.stream); port->port.stream = NULL; } From 6e4cf0ad4714db0c2cbdf69828c81480244fd18c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 13:51:31 +0100 Subject: [PATCH 09/40] Restore condition on collections so that test will terminate even if finalization messages are not delivered. Copied from Perforce Change: 187124 ServerID: perforce.ravenbrook.com --- mps/code/finalcv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index f31065edd92..2be7f083735 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -39,6 +39,7 @@ #define churnFACTOR 10 #define finalizationRATE 6 #define gcINTERVAL ((size_t)150 * 1024) +#define collectionCOUNT 3 #define messageCOUNT 3 /* 3 words: wrapper | vector-len | first-slot */ @@ -150,7 +151,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class) mps_message_type_enable(arena, mps_message_type_finalization()); /* */ - while (messages < messageCOUNT) { + while (messages < messageCOUNT && mps_collections(arena) < collectionCOUNT) { /* Perhaps cause (minor) collection */ churn(ap); From 71c23bb40aa1d8a5a4492aa0808f3849c9b80f2a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 22:16:11 +0100 Subject: [PATCH 10/40] Need to call easy_tramp to get correct assertion handling. Copied from Perforce Change: 187154 ServerID: perforce.ravenbrook.com --- mps/test/function/228.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/test/function/228.c b/mps/test/function/228.c index 3b6e817a040..baa69a7cd7e 100644 --- a/mps/test/function/228.c +++ b/mps/test/function/228.c @@ -7,6 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= global.c + assertcond = PoolHasAttr(refpool, AttrGC) END_HEADER */ @@ -34,7 +35,7 @@ static void test(void) int main(void) { - test(); + easy_tramp(test); pass(); return 0; } From d0ba77de474c3abac3e8ad14bda2b2cdbfcf6709 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 11:24:29 +0100 Subject: [PATCH 11/40] Branching master to branch/2014-10-25/thread. Copied from Perforce Change: 187391 ServerID: perforce.ravenbrook.com From abbdcfc59f91b23ef34e1c92d71d2020f63e8991 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 17:41:42 +0100 Subject: [PATCH 12/40] Assert if a thread dies while registered, but make a best effort to continue working after the assertion, by marking the thread as dead and moving it to a ring of dead threads. Copied from Perforce Change: 187393 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 4 ++ mps/code/mpm.h | 1 + mps/code/mpmst.h | 1 + mps/code/shield.c | 4 +- mps/code/th.h | 11 ++-- mps/code/than.c | 6 +- mps/code/thix.c | 91 +++++++++++++++++------------- mps/code/thw3.c | 66 ++++++++++++---------- mps/code/thw3.h | 1 + mps/code/thw3i3.c | 13 +++-- mps/code/thw3i6.c | 13 +++-- mps/code/thxc.c | 46 ++++++++++----- mps/design/thread-manager.txt | 35 ++++++++++-- mps/manual/source/topic/thread.rst | 4 ++ 14 files changed, 187 insertions(+), 109 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index df0095d3195..d60e925fdb3 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -153,6 +153,7 @@ Bool GlobalsCheck(Globals arenaGlobals) } CHECKD_NOSIG(Ring, &arena->threadRing); + CHECKD_NOSIG(Ring, &arena->deadRing); CHECKL(BoolCheck(arena->insideShield)); CHECKL(arena->shCacheLimit <= ShieldCacheSIZE); @@ -277,6 +278,7 @@ Res GlobalsInit(Globals arenaGlobals) arenaGlobals->rememberedSummaryIndex = 0; RingInit(&arena->threadRing); + RingInit(&arena->deadRing); arena->threadSerial = (Serial)0; RingInit(&arena->formatRing); arena->formatSerial = (Serial)0; @@ -405,6 +407,7 @@ void GlobalsFinish(Globals arenaGlobals) RingFinish(&arena->chainRing); RingFinish(&arena->messageRing); RingFinish(&arena->threadRing); + RingFinish(&arena->deadRing); for(rank = RankMIN; rank < RankLIMIT; ++rank) RingFinish(&arena->greyRing[rank]); RingFinish(&arenaGlobals->rootRing); @@ -495,6 +498,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) AVER(RingIsSingle(&arena->chainRing)); AVER(RingIsSingle(&arena->messageRing)); AVER(RingIsSingle(&arena->threadRing)); + AVER(RingIsSingle(&arena->deadRing)); AVER(RingIsSingle(&arenaGlobals->rootRing)); for(rank = RankMIN; rank < RankLIMIT; ++rank) AVER(RingIsSingle(&arena->greyRing[rank])); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 6b3730495d6..a3c5a8bbf6c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -520,6 +520,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob) #define ArenaThreadRing(arena) (&(arena)->threadRing) +#define ArenaDeadRing(arena) (&(arena)->deadRing) #define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */ #define ArenaTrace(arena, ti) (&(arena)->trace[ti]) #define ArenaZoneShift(arena) ((arena)->zoneShift) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index a7749aa738d..01dbf16b732 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -755,6 +755,7 @@ typedef struct mps_arena_s { /* thread fields () */ RingStruct threadRing; /* ring of attached threads */ + RingStruct deadRing; /* ring of dead threads */ Serial threadSerial; /* serial of next thread */ /* shield fields () */ diff --git a/mps/code/shield.c b/mps/code/shield.c index 55625664ca7..88ee8751331 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -83,7 +83,7 @@ void (ShieldSuspend)(Arena arena) AVER(arena->insideShield); if (!arena->suspended) { - ThreadRingSuspend(ArenaThreadRing(arena)); + ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = TRUE; } } @@ -263,7 +263,7 @@ void (ShieldLeave)(Arena arena) /* Ensuring the mutator is running at this point * guarantees inv.outside.running */ if (arena->suspended) { - ThreadRingResume(ArenaThreadRing(arena)); + ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = FALSE; } arena->insideShield = FALSE; diff --git a/mps/code/th.h b/mps/code/th.h index 8c7da150fd0..8f7996cc0b5 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -47,13 +47,14 @@ extern void ThreadDeregister(Thread thread, Arena arena); /* ThreadRingSuspend/Resume * - * These functions suspend/resume the threads on the ring. - * If the current thread is among them, it is not suspended, - * nor is any attempt to resume it made. + * These functions suspend/resume the threads on the ring. If the + * current thread is among them, it is not suspended, nor is any + * attempt to resume it made. Threads that can't be suspended/resumed + * because they are dead are moved to deadRing. */ -extern void ThreadRingSuspend(Ring threadRing); -extern void ThreadRingResume(Ring threadRing); +extern void ThreadRingSuspend(Ring threadRing, Ring deadRing); +extern void ThreadRingResume(Ring threadRing, Ring deadRing); /* ThreadRingThread diff --git a/mps/code/than.c b/mps/code/than.c index 8c5af222898..f1fb21006d8 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -86,14 +86,16 @@ void ThreadDeregister(Thread thread, Arena arena) } -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { AVERT(Ring, threadRing); + AVERT(Ring, deadRing); } -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { AVERT(Ring, threadRing); + AVERT(Ring, deadRing); } Thread ThreadRingThread(Ring threadRing) diff --git a/mps/code/thix.c b/mps/code/thix.c index d32a7dd6601..be1b1f770ae 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -12,10 +12,10 @@ * * ASSUMPTIONS * - * .error.resume: PThreadextResume is assumed to succeed unless the thread - * has been destroyed. - * .error.suspend: PThreadextSuspend is assumed to succeed unless the thread - * has been destroyed. In this case, the suspend context is set to NULL; + * .error.resume: PThreadextResume is assumed to succeed unless the + * thread has been terminated. + * .error.suspend: PThreadextSuspend is assumed to succeed unless the + * thread has been terminated. * * .stack.full-descend: assumes full descending stack. * i.e. stack pointer points to the last allocated location; @@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* threads attached to arena */ + Bool alive; /* thread believed to be alive? */ PThreadextStruct thrextStruct; /* PThreads extension */ pthread_t id; /* Pthread object of thread */ - MutatorFaultContext mfc; /* Context if thread is suspended */ + MutatorFaultContext mfc; /* Context if suspended, NULL if not */ } ThreadStruct; @@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread) CHECKU(Arena, thread->arena); CHECKL(thread->serial < thread->arena->threadSerial); CHECKD_NOSIG(Ring, &thread->arenaRing); + CHECKL(BoolCheck(thread->alive)); CHECKD(PThreadext, &thread->thrextStruct); return TRUE; } @@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; + thread->alive = TRUE; thread->mfc = NULL; PThreadextInit(&thread->thrextStruct, thread->id); @@ -130,69 +133,80 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* mapThreadRing -- map over threads on ring calling a function on each one - * except the current thread +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are moved to deadRing. */ -static void mapThreadRing(Ring threadRing, void (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread)) { Ring node, next; pthread_t self; AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); self = pthread_self(); RING_FOR(node, threadRing, next) { Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(! pthread_equal(self, thread->id)) /* .thread.id */ - (*func)(thread); + AVER(thread->alive); + if (!pthread_equal(self, thread->id) /* .thread.id */ + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */ +/* ThreadRingSuspend -- suspend all threads on a ring, except the + * current one. + */ - -static void threadSuspend(Thread thread) +static Bool threadSuspend(Thread thread) { - /* .error.suspend */ - /* In the error case (PThreadextSuspend returning ResFAIL), we */ - /* assume the thread has been destroyed. */ - /* In which case we simply continue. */ + /* .error.suspend: if PThreadextSuspend fails, we assume the thread + * has been terminated. */ Res res; + AVER(thread->mfc == NULL); res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc); - if(res != ResOK) - thread->mfc = NULL; + AVER(res == ResOK); + AVER(thread->mfc != NULL); + return res == ResOK; } -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - mapThreadRing(threadRing, threadSuspend); + mapThreadRing(threadRing, deadRing, threadSuspend); } /* ThreadRingResume -- resume all threads on a ring (expect the current one) */ -static void threadResume(Thread thread) +static Bool threadResume(Thread thread) { - /* .error.resume */ - /* If the previous suspend failed (thread->mfc == NULL), */ - /* or in the error case (PThreadextResume returning ResFAIL), */ - /* assume the thread has been destroyed. */ - /* In which case we simply continue. */ - if(thread->mfc != NULL) { - (void)PThreadextResume(&thread->thrextStruct); - thread->mfc = NULL; - } + Res res; + /* .error.resume: If PThreadextResume fails, we assume the thread + * has been terminated. */ + AVER(thread->mfc != NULL); + res = PThreadextResume(&thread->thrextStruct); + AVER(res == ResOK); + thread->mfc = NULL; + return res == ResOK; } -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - mapThreadRing(threadRing, threadResume); + mapThreadRing(threadRing, deadRing, threadResume); } @@ -231,20 +245,16 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) self = pthread_self(); if(pthread_equal(self, thread->id)) { /* scan this thread's stack */ + AVER(thread->alive); res = StackScan(ss, stackBot); if(res != ResOK) return res; - } else { + } else if (thread->alive) { MutatorFaultContext mfc; Addr *stackBase, *stackLimit, stackPtr; mfc = thread->mfc; - if(mfc == NULL) { - /* .error.suspend */ - /* We assume that the thread must have been destroyed. */ - /* We ignore the situation by returning immediately. */ - return ResOK; - } + AVER(mfc != NULL); stackPtr = MutatorFaultContextSP(mfc); /* .stack.align */ @@ -280,6 +290,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " id $U\n", (WriteFU)thread->id, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, NULL); diff --git a/mps/code/thw3.c b/mps/code/thw3.c index eda4c139b19..b8b8b106680 100644 --- a/mps/code/thw3.c +++ b/mps/code/thw3.c @@ -109,6 +109,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; + thread->alive = TRUE; AVERT(Thread, thread); @@ -138,60 +139,66 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* Map over threads on ring calling f on each one except the - * current thread. +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are moved to deadRing. */ -static void mapThreadRing(Ring ring, void (*f)(Thread thread)) + +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { - Ring node; + Ring node, next; DWORD id; + AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); + id = GetCurrentThreadId(); - node = RingNext(ring); - while(node != ring) { - Ring next = RingNext(node); - Thread thread; - - thread = RING_ELT(Thread, arenaRing, node); + RING_FOR(node, threadRing, next) { + Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(id != thread->id) /* .thread.id */ - (*f)(thread); - - node = next; + AVER(thread->alive); + if (id != thread->id /* .thread.id */ + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -static void suspend(Thread thread) +static Bool suspendThread(Thread thread) { /* .thread.handle.susp-res */ /* .error.suspend */ - /* In the error case (SuspendThread returning 0xFFFFFFFF), we */ - /* assume the thread has been destroyed (as part of process shutdown). */ - /* In which case we simply continue. */ + /* In the error case (SuspendThread returning -1), we */ + /* assume the thread has been terminated. */ /* [GetLastError appears to return 5 when SuspendThread is called */ - /* on a destroyed thread, but I'm not sufficiently confident of this */ + /* on a terminated thread, but I'm not sufficiently confident of this */ /* to check -- drj 1998-04-09] */ - (void)SuspendThread(thread->handle); + return SuspendThread(thread->handle) != (DWORD)-1; } -void ThreadRingSuspend(Ring ring) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - mapThreadRing(ring, suspend); + mapThreadRing(threadRing, deadRing, suspendThread); } -static void resume(Thread thread) +static Bool resumeThread(Thread thread) { /* .thread.handle.susp-res */ /* .error.resume */ - /* In the error case (ResumeThread returning 0xFFFFFFFF), we */ - /* assume the thread has been destroyed (as part of process shutdown). */ - /* In which case we simply continue. */ - (void)ResumeThread(thread->handle); + /* In the error case (ResumeThread returning -1), we */ + /* assume the thread has been terminated. */ + return ResumeThread(thread->handle) != (DWORD)-1; } -void ThreadRingResume(Ring ring) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - mapThreadRing(ring, resume); + mapThreadRing(threadRing, deadRing, resumeThread); } @@ -220,6 +227,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " handle $W\n", (WriteFW)thread->handle, " id $U\n", (WriteFU)thread->id, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, diff --git a/mps/code/thw3.h b/mps/code/thw3.h index 7e3cd68e2f1..b19bfccadba 100644 --- a/mps/code/thw3.h +++ b/mps/code/thw3.h @@ -26,6 +26,7 @@ typedef struct mps_thr_s { /* Win32 thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* threads attached to arena */ + Bool alive; /* thread believed to be alive? */ HANDLE handle; /* Handle of thread, see * */ DWORD id; /* Thread id of thread */ diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index 33424b6cf54..20e694ddc82 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) id = GetCurrentThreadId(); - if(id != thread->id) { /* .thread.id */ + if (id == thread->id) { /* .thread.id */ + /* scan this thread's stack */ + AVER(thread->alive); + res = StackScan(ss, stackBot); + if(res != ResOK) + return res; + } else if (thread->alive) { CONTEXT context; BOOL success; Addr *stackBase, *stackLimit, stackPtr; @@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) (Addr *)((char *)&context + sizeof(CONTEXT))); if(res != ResOK) return res; - - } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot); - if(res != ResOK) - return res; } return ResOK; diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index 9b0eae55db6..a13a031ec22 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) id = GetCurrentThreadId(); - if(id != thread->id) { /* .thread.id */ + if (id == thread->id) { /* .thread.id */ + /* scan this thread's stack */ + AVER(thread->alive); + res = StackScan(ss, stackBot); + if(res != ResOK) + return res; + } else if (thread->alive) { CONTEXT context; BOOL success; Addr *stackBase, *stackLimit, stackPtr; @@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) (Addr *)((char *)&context + sizeof(CONTEXT))); if(res != ResOK) return res; - - } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot); - if(res != ResOK) - return res; } return ResOK; diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 6aeffef6568..b4d7c4188f0 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -36,6 +36,7 @@ typedef struct mps_thr_s { /* OS X / Mach thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* attaches to arena */ + Bool alive; /* thread believed to be alive? */ thread_port_t port; /* thread kernel port */ } ThreadStruct; @@ -46,6 +47,7 @@ Bool ThreadCheck(Thread thread) CHECKU(Arena, thread->arena); CHECKL(thread->serial < thread->arena->threadSerial); CHECKD_NOSIG(Ring, &thread->arenaRing); + CHECKL(BoolCheck(thread->alive)); CHECKL(MACH_PORT_VALID(thread->port)); return TRUE; } @@ -78,6 +80,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; + thread->alive = TRUE; thread->port = mach_thread_self(); thread->sig = ThreadSig; AVERT(Thread, thread); @@ -108,62 +111,73 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* mapThreadRing -- map over threads on ring calling a function on each one - * except the current thread +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are marked as dead and moved to deadRing. */ -static void mapThreadRing(Ring threadRing, void (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { Ring node, next; mach_port_t self; AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); self = mach_thread_self(); AVER(MACH_PORT_VALID(self)); RING_FOR(node, threadRing, next) { Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(thread->port != self) - (*func)(thread); + AVER(thread->alive); + if (thread->port != self + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -static void threadSuspend(Thread thread) +static Bool threadSuspend(Thread thread) { kern_return_t kern_return; kern_return = thread_suspend(thread->port); /* No rendezvous is necessary: thread_suspend "prevents the thread * from executing any more user-level instructions" */ AVER(kern_return == KERN_SUCCESS); + return kern_return == KERN_SUCCESS; } -static void threadResume(Thread thread) +static Bool threadResume(Thread thread) { kern_return_t kern_return; kern_return = thread_resume(thread->port); /* Mach has no equivalent of EAGAIN. */ AVER(kern_return == KERN_SUCCESS); + return kern_return == KERN_SUCCESS; } /* ThreadRingSuspend -- suspend all threads on a ring, except the * current one. */ -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - AVERT(Ring, threadRing); - mapThreadRing(threadRing, threadSuspend); + mapThreadRing(threadRing, deadRing, threadSuspend); } /* ThreadRingResume -- resume all threads on a ring, except the * current one. */ -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - AVERT(Ring, threadRing); - mapThreadRing(threadRing, threadResume); + mapThreadRing(threadRing, deadRing, threadResume); } Thread ThreadRingThread(Ring threadRing) @@ -199,17 +213,18 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) AVER(MACH_PORT_VALID(self)); if (thread->port == self) { /* scan this thread's stack */ + AVER(thread->alive); res = StackScan(ss, stackBot); if(res != ResOK) return res; - } else { + } else if (thread->alive) { MutatorFaultContextStruct mfcStruct; THREAD_STATE_S threadState; Addr *stackBase, *stackLimit, stackPtr; mach_msg_type_number_t count; kern_return_t kern_return; - /* Note: We could get the thread state and check the suspend cound in + /* Note: We could get the thread state and check the suspend count in order to assert that the thread is suspended, but it's probably unnecessary and is a lot of work to check a static condition. */ @@ -257,6 +272,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " port $U\n", (WriteFU)thread->port, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, NULL); diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index efe6bcee9e9..48cbb912533 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -54,6 +54,15 @@ which might provoke a collection. See request.dylan.160252_.) .. _request.dylan.160252: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160252/ +_`.req.thread.die`: It would be nice if the MPS coped with threads +that die while registered. (This makes it easier for a client program +to interface with foreign code that terminates threads without the +client program being given an opportunity to deregister them. See +request.dylan.160022_ and request.mps.160093_.) + +.. _request.dylan.160022: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160022 +.. _request.mps.160093: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160093/ + Design ------ @@ -70,6 +79,22 @@ thread that might refer to, read from, or write to memory in automatically managed pool classes is registered with the MPS. This is documented in the manual under ``mps_thread_reg()``. +_`.sol.thread.term`: The thread manager cannot reliably detect that a +thread has terminated. The reason is that threading systems do not +guarantee behaviour in this case. For example, POSIX_ says, "A +conforming implementation is free to reuse a thread ID after its +lifetime has ended. If an application attempts to use a thread ID +whose lifetime has ended, the behavior is undefined." For this reason, +the documentation for ``mps_thread_dereg()`` specifies that it is an +error if a thread dies while registered. + +.. _POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_02 + +_`.sol.thread.term.attempt`: Nonetheless, the thread manager makes a +"best effort" to continue running after detecting a terminated thread, +by moving the thread to a ring of dead threads, and avoiding scanning +it. This might allow a malfunctioning client program to limp along. + Interface --------- @@ -112,14 +137,16 @@ Otherwise, return a result code indicating the cause of the error. _`.if.deregister`: Remove ``thread`` from the list of threads managed by the arena and free it. -``void ThreadRingSuspend(Ring threadRing)`` +``void ThreadRingSuspend(Ring threadRing, Ring deadRing)`` _`.if.ring.suspend`: Suspend all the threads on ``threadRing``, except -for the current thread. +for the current thread. If any threads are discovered to have +terminated, move them to ``deadRing``. -``void ThreadRingResume(Ring threadRing)`` +``void ThreadRingResume(Ring threadRing, Ring deadRing)`` -_`.if.ring.resume`: Resume all the threads on ``threadRing``. +_`.if.ring.resume`: Resume all the threads on ``threadRing``. If any +threads are discovered to have terminated, move them to ``deadRing``. ``Thread ThreadRingThread(Ring threadRing)`` diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index fe16b1e450d..0a4156613ac 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -100,6 +100,7 @@ Signal and exception handling issues for co-operating: if you are in this situation, please :ref:`contact us `. + .. index:: single: thread; interface @@ -142,6 +143,9 @@ Thread interface It is recommended that all threads be registered with all arenas. + It is an error if a thread terminates while it is registered. The + client program must call :c:func:`mps_thread_dereg` first. + .. c:function:: void mps_thread_dereg(mps_thr_t thr) From 3fdbf1deb55341f717debc696e18f4bb7cec5a25 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 11:01:11 +0000 Subject: [PATCH 13/40] Emphasize the right line in the finalization example. Copied from Perforce Change: 187466 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/advanced.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index 4b6331a2234..c40db2d0774 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -146,7 +146,7 @@ toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this ensures that the file handle won't be closed more than once. .. code-block:: c - :emphasize-lines: 8 + :emphasize-lines: 6 static void port_close(obj_t port) { From 89baddefe801bb6ddc72330c8c31927bbd456108 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 19 Jun 2015 12:08:35 +0100 Subject: [PATCH 14/40] Document the assertion failure for an attempt to finalize an unfinalizable reference. Copied from Perforce Change: 187966 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index e65f6eafebd..fe515c9ca40 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -260,6 +260,13 @@ this documentation. :c:type:`mps_fmt_t` for this argument. +``global.c: PoolHasAttr(pool, AttrGC)`` + + The client program called :c:func:`mps_finalize` on a reference + that does not belong to an :term:`automatically managed ` :term:`pool`. + + ``lockix.c: res == 0`` ``lockw3.c: lock->claims == 0`` From e84a0670d75397265025e925f9b900d3c6bce6f3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 11 Aug 2015 08:35:53 +0100 Subject: [PATCH 15/40] Test case function/228.c is passing. Copied from Perforce Change: 188123 ServerID: perforce.ravenbrook.com --- mps/test/testsets/passing | 1 + 1 file changed, 1 insertion(+) diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 4b0a0cbe1b5..e3de6f383f3 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -167,3 +167,4 @@ function/223.c function/224.c % 225 -- no such test function/226.c +function/228.c From ce822c30f90681d6bddfc04bd0834805de2d8f78 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Aug 2015 12:31:03 +0100 Subject: [PATCH 16/40] Keyword argument mps_key_rank is optional when creating an allocation point for an snc pool. Copied from Perforce Change: 188178 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/snc.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 49a43fe37ab..1138bf5375b 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -39,7 +39,7 @@ SNC properties * Supports allocation via :term:`allocation points` only. If an allocation point is created in an SNC pool, the call to - :c:func:`mps_ap_create_k` requires one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Does not support deallocation via :c:func:`mps_free`. @@ -112,11 +112,11 @@ SNC interface } MPS_ARGS_END(args); When creating an :term:`allocation point` on an SNC pool, - :c:func:`mps_ap_create_k` requires one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: - * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies - the :term:`rank` of references in objects allocated on this - allocation point. It must be :c:func:`mps_rank_exact`. + * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: From 1b58d72cf9fa9b69e863df96e3c00169d5c89758 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 13:05:33 +0100 Subject: [PATCH 17/40] Correct rest syntax for bulleted list. Copied from Perforce Change: 188192 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/snc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 1138bf5375b..d39a392c614 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -115,8 +115,8 @@ SNC interface :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default - :c:func:`mps_rank_exact`) specifies the :term:`rank` of references - in objects allocated on this allocation point. + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: From 01bdf07d1a19519529c5faf29d3edbe8c01cbc4e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 13:06:05 +0100 Subject: [PATCH 18/40] Add note about choice of base/client pointer representation. Copied from Perforce Change: 188193 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/format.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 2fe2b4a4e30..7db5c8a1178 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -179,6 +179,20 @@ There are some cautions to be observed when using in-band headers: #. Not all :term:`pool classes` support objects with in-band headers. See the documentation for the pool class. +.. note:: + + A :term:`client program` that allocates objects with + :term:`in-band headers` has to make a choice about how to + represent references to those objects. It can represent them using + :term:`base pointers` (which is convenient for allocation, since + :c:func:`mps_reserve` returns a base pointer, but requires + decoding when scanning) or using :term:`client pointers` (which is + convenient for scanning, since the :term:`scan method` takes a + client pointer, but requires encoding on allocation). Either + approach will work, but :term:`client pointers` are normally the + better choice, since scanning is normally more + performance-critical than allocation. + .. index:: pair: object format; cautions From eab8b05a85c96f42253854a5b28b8de723be792b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 14:00:44 +0100 Subject: [PATCH 19/40] Design.mps.bootstrap Copied from Perforce Change: 188195 ServerID: perforce.ravenbrook.com --- mps/design/bootstrap.txt | 127 +++++++++++++++++++++++++++++ mps/design/index.txt | 2 + mps/manual/source/design/index.rst | 1 + 3 files changed, 130 insertions(+) create mode 100644 mps/design/bootstrap.txt diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt new file mode 100644 index 00000000000..7eb79df1475 --- /dev/null +++ b/mps/design/bootstrap.txt @@ -0,0 +1,127 @@ +.. mode: -*- rst -*- + +Bootstrapping +============= + +:Tag: design.mps.bootstrap +:Author: Gareth Rees +:Date: 2015-09-01 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: bootsrap; design + + +Introduction +------------ + +_`.intro`: This explains how the MPS gets started. + +_`.readership`: Any MPS developer. + +_`.overview`: The job of the MPS is to allocate memory to a program. +Before it can allocate memory, the MPS needs to create data structures +to represent its internal state. But before it can create those data +structures, it needs to allocate memory to store them in. This +bootstrapping problem affects the MPS at several points, which are +listed here, together with their solutions. + + +Bootstrapping problems +---------------------- + +Virtual memory descriptor +......................... + +_`.vm`: Before address space can be mapped into main memory, the +virtual memory descriptor must be initialized. But before the virtual +memory descriptor can be initialized, some address space must be +mapped into main memory in order to store it. See +`design.vm.req.bootstrap`_. + +_`.vm.sol`: The virtual memory descriptor is allocated initially on +the stack, and then copied into its place in the chunk after the +memory for it has been mapped. See `design.vm.sol.bootstrap`_. + +.. _design.vm.req.bootstrap: vm#req.bootstrap +.. _design.vm.sol.bootstrap: vm#sol.bootstrap + + +Arena descriptor +................ + +_`.arena`: Before chunks of address space can be reserved and mapped, +the virtual memory arena descriptor must be initialized (so that the +chunks can be added to the arena's chunk tree). But before a virtual +memory arena descriptor can be initialized, address space must be +reserved and mapped in order to store it. + +_`.arena.sol`: A small amount of address space is reserved and mapped +directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system) +in order to provide enough memory for the arena descriptor. + + +Arena's free land +................. + +_`.land`: Before the arena can allocate memory, a range of addresses +must be inserted into the arena's free land (so that the free land can +hand out memory from this range). But before addresses can be inserted +into the arena's free land, the arena must be able to allocate memory +(to store the nodes in the tree representing those addresses). + +_`.land.sol`: The arena has two "back door" mechanisms and uses them +in combination. First, there is a mechanism for allocating a block of +memory directly from a chunk, bypassing the free land; second, the MFS +pool class has a mechanism for extending it with a block of memory. + + +Document History +---------------- + +- 2015-09-01 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2015 Ravenbrook Limited. All rights reserved. +. This is an open source license. Contact +Ravenbrook for commercial licensing options. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +#. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +#. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +#. Redistributions in any form must be accompanied by information on how + to obtain complete source code for this software and any + accompanying software that uses this software. The source code must + either be included in the distribution or be available for no more than + the cost of distribution plus a nominal fee, and must be freely + redistributable under reasonable conditions. For an executable file, + complete source code means the source code for all modules it contains. + It does not include source code for modules or files that typically + accompany the major components of the operating system on which the + executable file runs. + +**This software is provided by the copyright holders and contributors +"as is" and any express or implied warranties, including, but not +limited to, the implied warranties of merchantability, fitness for a +particular purpose, or non-infringement, are disclaimed. In no event +shall the copyright holders and contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or +services; loss of use, data, or profits; or business interruption) +however caused and on any theory of liability, whether in contract, +strict liability, or tort (including negligence or otherwise) arising in +any way out of the use of this software, even if advised of the +possibility of such damage.** diff --git a/mps/design/index.txt b/mps/design/index.txt index 9f4abf7b4f4..7e48b625319 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -44,6 +44,7 @@ alloc-frame_ Allocation frame protocol an_ Generic modules arena_ Arena arenavm_ Virtual memory arena +bootstrap_ Bootstrapping bt_ Bit tables buffer_ Allocation buffers and allocation points cbs_ Coalescing block structures @@ -122,6 +123,7 @@ writef_ The WriteF function .. _an: an .. _arena: arena .. _arenavm: arenavm +.. _bootstrap: bootstrap .. _bt: bt .. _buffer: buffer .. _cbs: cbs diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 907c9986bb1..b8da67a4333 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -8,6 +8,7 @@ Design abq an + bootstrap cbs config critical-path From 87fabe9ef036575a796b5fa9d0ae75c44a7bd90a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 4 Sep 2015 16:51:33 +0100 Subject: [PATCH 20/40] Correct the manual about the assertion you get when destroying a pool without destroying all the allocation points first. Copied from Perforce Change: 188243 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index e13e79a9735..784533d66fa 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -304,8 +304,15 @@ this documentation. The client program destroyed an MPS data structure without having destroyed all the data structures that it owns first. For example, it destroyed an arena without first destroying all pools in that - arena, or it destroyed a pool without first destroying all - allocation points created on that pool. + arena, or it destroyed a thread without first destroying all + roots using that thread. + + +``seg.c: gcseg->buffer == NULL`` + + The client program destroyed pool without first destroying all the + allocation points created on that pool. The allocation points must + be destroyed first. ``trace.c: ss->rank < RankEXACT`` From 6521d927eb562923349731311ed2a2dde115e434 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 4 Sep 2015 20:15:36 +0100 Subject: [PATCH 21/40] Add accesssetcheck and check accessset arguments. Copied from Perforce Change: 188251 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 14 ++++++++++++-- mps/code/mpm.h | 5 +++-- mps/code/pool.c | 6 +++--- mps/code/poolabs.c | 10 +++++----- mps/code/poolawl.c | 5 +++-- mps/code/protan.c | 7 +++---- mps/code/protix.c | 5 +++-- mps/code/protw3.c | 5 +++-- mps/code/root.c | 4 ++-- mps/code/shield.c | 7 +++++-- mps/code/trace.c | 5 +++-- 11 files changed, 45 insertions(+), 28 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index d3c32a66daf..aba1ac2f5cb 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -1,7 +1,7 @@ /* mpm.c: GENERAL MPM SUPPORT * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Miscellaneous support for the implementation of the MPM * and pool classes. @@ -137,6 +137,16 @@ Bool AlignCheck(Align align) } +/* AccessSetCheck -- check that an access set is valid */ + +Bool AccessSetCheck(AccessSet mode) +{ + CHECKL(mode < ((ULongest)1 << AccessLIMIT)); + UNUSED(mode); /* see .check.unused */ + return TRUE; +} + + #endif /* defined(AVER_AND_CHECK) */ @@ -638,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index a5ac16b41a2..b8cb8c250ee 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1,7 +1,7 @@ /* mpm.h: MEMORY POOL MANAGER DEFINITIONS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .trans.bufferinit: The Buffer data structure has an Init field and @@ -46,6 +46,7 @@ extern Bool FunCheck(Fun f); extern Bool ShiftCheck(Shift shift); extern Bool AttrCheck(Attr attr); extern Bool RootVarCheck(RootVar rootVar); +extern Bool AccessSetCheck(AccessSet mode); /* Address/Size Interface -- see */ @@ -1052,7 +1053,7 @@ extern LandClass LandClassGet(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/pool.c b/mps/code/pool.c index 945a846edcb..f939bca84e9 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -1,7 +1,7 @@ /* pool.c: POOL IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * DESIGN @@ -328,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* Can't check mode as there is no check method */ + AVERT(AccessSet, mode); /* Can't check MutatorFaultContext as there is no check method */ return (*pool->class->access)(pool, seg, addr, mode, context); @@ -694,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 712f24152e5..30f5d0f999e 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -1,7 +1,7 @@ /* poolabs.c: ABSTRACT POOL CLASSES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * PURPOSE @@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(mode); UNUSED(context); @@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(addr); @@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ arena = PoolArena(pool); @@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 01ca12ea46f..5bb0e6b9025 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1,7 +1,7 @@ /* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -1206,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); + AVERT(AccessSet, mode); /* Attempt scanning a single reference if permitted */ if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { @@ -1375,7 +1376,7 @@ static Bool AWLCheck(AWL awl) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protan.c b/mps/code/protan.c index 1959e42395b..0e4771f18da 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -1,7 +1,7 @@ /* protan.c: ANSI MEMORY PROTECTION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -36,8 +36,7 @@ Size ProtGranularity(void) void ProtSet(Addr base, Addr limit, AccessSet pm) { AVER(base < limit); - /* .improve.protset.check: There is nor AccessSetCheck, so we */ - /* don't check it. */ + AVERT(AccessSet, pm); UNUSED(pm); NOOP; } @@ -74,7 +73,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index ea674ae53d5..a243b009491 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -1,7 +1,7 @@ /* protix.c: PROTECTION FOR UNIX * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between * OS X, FreeBSD, and Linux. @@ -66,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */ + AVERT(AccessSet, mode); /* Convert between MPS AccessSet and UNIX PROT thingies. In this function, AccessREAD means protect against read accesses @@ -122,7 +123,7 @@ Size ProtGranularity(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 30c3edc0975..a8dddd74fe2 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -1,7 +1,7 @@ /* protw3.c: PROTECTION FOR WIN32 * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); + AVERT(AccessSet, mode); newProtect = PAGE_EXECUTE_READWRITE; if((mode & AccessWRITE) != 0) @@ -140,7 +141,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/root.c b/mps/code/root.c index 02f48b38e44..7a3e1205be2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -139,7 +139,7 @@ Bool RootCheck(Root root) CHECKL(root->protBase != (Addr)0); CHECKL(root->protLimit != (Addr)0); CHECKL(root->protBase < root->protLimit); - /* there is no AccessSetCheck */ + CHECKL(AccessSetCheck(root->pm)); } else { CHECKL(root->protBase == (Addr)0); CHECKL(root->protLimit == (Addr)0); @@ -558,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr) void RootAccess(Root root, AccessSet mode) { AVERT(Root, root); - /* Can't AVERT mode. */ + AVERT(AccessSet, mode); AVER((root->pm & mode) != AccessSetEMPTY); AVER(mode == AccessWRITE); /* only write protection supported */ diff --git a/mps/code/shield.c b/mps/code/shield.c index 55625664ca7..8b73f8f488c 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -1,7 +1,7 @@ /* shield.c: SHIELD IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * See: idea.shield, design.mps.shield. * @@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); + AVERT_CRITICAL(AccessSet, mode); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); @@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* can't check seg. Nor can we check arena as that checks the */ /* segs in the cache. */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ @@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { /* Don't check seg or arena, see .seg.broken */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == mode); /* synced(seg) is not changed by the following * preserving inv.unsynced.suspended @@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/trace.c b/mps/code/trace.c index 7aeb70305c7..7e918513279 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,7 +1,7 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. + * Copyright (c) 2001-2015 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * @@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) AVERT(Arena, arena); AVERT(Seg, seg); + AVERT(AccessSet, mode); /* If it's a read access, then the segment must be grey for a trace */ /* which is flipped. */ @@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited + * Copyright (C) 2001-2015 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. From 000df4fd79e46e365b57cfb2c9e6d5c874c6d883 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Sep 2015 16:13:29 +0100 Subject: [PATCH 22/40] Improve documentation of commit limit for a client arena. Copied from Perforce Change: 188285 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 106a1a40de2..29d942a29f2 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -155,9 +155,11 @@ Client arenas It also accepts two optional keyword arguments: * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is - the commit limit in :term:`bytes (1)`. See - :c:func:`mps_arena_commit_limit` for details. The default commit - limit is the maximum value of the :c:type:`size_t` type. + the maximum amount of memory, in :term:`bytes (1)`, that the MPS + will use out of the provided chunk (or chunks, if the arena is + extended). See :c:func:`mps_arena_commit_limit` for details. The + default commit limit is the maximum value of the + :c:type:`size_t` type. * :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`, default 8192) is the granularity with which the arena will @@ -256,7 +258,8 @@ Virtual memory arenas efficient garbage collection will become. * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is - the commit limit in :term:`bytes (1)`. See + the maximum amount of main memory, in :term:`bytes (1)`, that + the MPS will obtain from the operating system. See :c:func:`mps_arena_commit_limit` for details. The default commit limit is the maximum value of the :c:type:`size_t` type. @@ -336,11 +339,15 @@ Arena properties ``arena`` is the arena to return the commit limit for. - Returns the commit limit in :term:`bytes (1)`. The commit limit - controls how much main memory the MPS will obtain from the - operating system. The function :c:func:`mps_arena_committed` - returns the current committed memory; this never exceeds the - commit limit. + Returns the commit limit in :term:`bytes (1)`. + + For a :term:`client arena`, this this the maximum amount of + memory, in :term:`bytes (1)`, that the MPS will use out of the + chunks provided by the client to the arena. + + For a :term:`virtual memory arena`, this is the maximum amount of + memory that the MPS will map to RAM via the operating system's + virtual memory interface. The commit limit can be changed by passing the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to From 537af4b0dcb4aeb87c90f7b7fec1ea90d07b62d9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Sep 2015 16:21:27 +0100 Subject: [PATCH 23/40] Rename mps_key_arena_commit_limit and mps_key_arena_spare_commit_limit as mps_key_commit_limit and mps_key_spare_commit_limit respectively, as suggested by nb in review. Copied from Perforce Change: 188286 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 2 +- mps/code/amcsshe.c | 2 +- mps/code/amcssth.c | 2 +- mps/code/amsss.c | 2 +- mps/code/apss.c | 2 +- mps/code/arena.c | 12 ++-- mps/code/locusss.c | 2 +- mps/code/mps.h | 12 ++-- mps/code/mpsicv.c | 2 +- mps/manual/source/release.rst | 4 +- mps/manual/source/topic/arena.rst | 18 +++--- mps/manual/source/topic/deprecated.rst | 2 +- mps/manual/source/topic/keyword.rst | 78 +++++++++++++------------- mps/test/function/120.c | 2 +- mps/test/function/165.c | 8 +-- mps/test/function/231.c | 4 +- 16 files changed, 77 insertions(+), 77 deletions(-) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 83d67dcba58..294ce224b15 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -312,7 +312,7 @@ int main(int argc, char *argv[]) MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, scale * testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, grainSize); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, scale * testArenaSIZE); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, scale * testArenaSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); mps_message_type_enable(arena, mps_message_type_gc()); diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c index adfad3729e5..bd3ea73d068 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -251,7 +251,7 @@ int main(int argc, char *argv[]) MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE)); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); mps_message_type_enable(arena, mps_message_type_gc()); diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 043330ebb74..3eea28df075 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -292,7 +292,7 @@ static void test_arena(int mode) MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE)); if (mode == ModeCOMMIT) - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); mps_message_type_enable(arena, mps_message_type_gc()); diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 15686e5d15d..223bd205aea 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -209,7 +209,7 @@ int main(int argc, char *argv[]) MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE)); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); diff --git a/mps/code/apss.c b/mps/code/apss.c index e1317b3fb73..1fe460df9ba 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE)); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE); test(mps_arena_class_vm(), args, &fenceOptions); } MPS_ARGS_END(args); diff --git a/mps/code/arena.c b/mps/code/arena.c index e5d2901683e..4206ec9ab72 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -207,9 +207,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) if (ArgPick(&arg, args, MPS_KEY_ARENA_ZONED)) zoned = arg.val.b; - if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT)) + if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT)) commitLimit = arg.val.size; - if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT)) + if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) spareCommitLimit = arg.val.size; arena->class = class; @@ -289,11 +289,11 @@ ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool); /* ArenaCreate -- create the arena and call initializers */ -ARG_DEFINE_KEY(ARENA_COMMIT_LIMIT, Size); ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size); ARG_DEFINE_KEY(ARENA_SIZE, Size); -ARG_DEFINE_KEY(ARENA_SPARE_COMMIT_LIMIT, Size); ARG_DEFINE_KEY(ARENA_ZONED, Bool); +ARG_DEFINE_KEY(COMMIT_LIMIT, Size); +ARG_DEFINE_KEY(SPARE_COMMIT_LIMIT, Size); static Res arenaFreeLandInit(Arena arena) { @@ -395,13 +395,13 @@ Res ArenaConfigure(Arena arena, ArgList args) AVERT(Arena, arena); AVERT(ArgList, args); - if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT)) { + if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT)) { Size limit = arg.val.size; res = ArenaSetCommitLimit(arena, limit); if (res != ResOK) return res; } - if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT)) { + if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) { Size limit = arg.val.size; (void)ArenaSetSpareCommitLimit(arena, limit); } diff --git a/mps/code/locusss.c b/mps/code/locusss.c index 742e5ee779b..b3769dd674a 100644 --- a/mps/code/locusss.c +++ b/mps/code/locusss.c @@ -219,7 +219,7 @@ static void runArenaTest(size_t size, MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size); MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, size - chunkSize); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, size - chunkSize); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "mps_arena_create"); } MPS_ARGS_END(args); diff --git a/mps/code/mps.h b/mps/code/mps.h index b8882335581..10207eb6e94 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -155,18 +155,12 @@ extern const struct mps_key_s _mps_key_ARGS_END; #define MPS_KEY_ARGS_END (&_mps_key_ARGS_END) extern mps_arg_s mps_args_none[]; -extern const struct mps_key_s _mps_key_ARENA_COMMIT_LIMIT; -#define MPS_KEY_ARENA_COMMIT_LIMIT (&_mps_key_ARENA_COMMIT_LIMIT) -#define MPS_KEY_ARENA_COMMIT_LIMIT_FIELD size extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE; #define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE) #define MPS_KEY_ARENA_GRAIN_SIZE_FIELD size extern const struct mps_key_s _mps_key_ARENA_SIZE; #define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE) #define MPS_KEY_ARENA_SIZE_FIELD size -extern const struct mps_key_s _mps_key_ARENA_SPARE_COMMIT_LIMIT; -#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT (&_mps_key_ARENA_SPARE_COMMIT_LIMIT) -#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT_FIELD size extern const struct mps_key_s _mps_key_ARENA_ZONED; #define MPS_KEY_ARENA_ZONED (&_mps_key_ARENA_ZONED) #define MPS_KEY_ARENA_ZONED_FIELD b @@ -182,6 +176,12 @@ extern const struct mps_key_s _mps_key_GEN; extern const struct mps_key_s _mps_key_RANK; #define MPS_KEY_RANK (&_mps_key_RANK) #define MPS_KEY_RANK_FIELD rank +extern const struct mps_key_s _mps_key_COMMIT_LIMIT; +#define MPS_KEY_COMMIT_LIMIT (&_mps_key_COMMIT_LIMIT) +#define MPS_KEY_COMMIT_LIMIT_FIELD size +extern const struct mps_key_s _mps_key_SPARE_COMMIT_LIMIT; +#define MPS_KEY_SPARE_COMMIT_LIMIT (&_mps_key_SPARE_COMMIT_LIMIT) +#define MPS_KEY_SPARE_COMMIT_LIMIT_FIELD size extern const struct mps_key_s _mps_key_EXTEND_BY; #define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY) diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 9f546c8678c..c1ea620c810 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -348,7 +348,7 @@ static void arena_commit_test(mps_arena_t arena) } while (res == MPS_RES_OK); die_expect(res, MPS_RES_COMMIT_LIMIT, "Commit limit allocation"); MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, limit); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, limit); die(mps_arena_configure(arena, args), "commit_limit_set after"); } MPS_ARGS_END(args); res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE); diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index b7f580c7286..5a862a6bc47 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -18,9 +18,9 @@ New features requests from the :term:`arena`. #. The function :c:func:`mps_arena_create_k` accepts two new - :term:`keyword arguments`. :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` + :term:`keyword arguments`. :c:macro:`MPS_KEY_COMMIT_LIMIT` sets the :term:`commit limit` for the arena, and - :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` sets the :term:`spare + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` sets the :term:`spare commit limit` for the arena. #. The new function :c:func:`mps_arena_configure` provides a diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 29d942a29f2..7c9f580adde 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -154,7 +154,7 @@ Client arenas It also accepts two optional keyword arguments: - * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is + * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is the maximum amount of memory, in :term:`bytes (1)`, that the MPS will use out of the provided chunk (or chunks, if the arena is extended). See :c:func:`mps_arena_commit_limit` for details. The @@ -188,7 +188,7 @@ Client arenas When configuring a client arena, :c:func:`mps_arena_configure` accepts the :term:`keyword argument` - :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` as described above. + :c:macro:`MPS_KEY_COMMIT_LIMIT` as described above. .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -257,7 +257,7 @@ Virtual memory arenas more times it has to extend its address space, the less efficient garbage collection will become. - * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is + * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is the maximum amount of main memory, in :term:`bytes (1)`, that the MPS will obtain from the operating system. See :c:func:`mps_arena_commit_limit` for details. The default commit @@ -274,7 +274,7 @@ Virtual memory arenas that's smaller than the operating system page size, the MPS rounds it up to the page size and continues. - * :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` (type + * :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` (type :c:type:`size_t`, default 0) is the spare commit limit in :term:`bytes (1)`. See :c:func:`mps_arena_spare_commit_limit` for details. @@ -314,8 +314,8 @@ Virtual memory arenas When configuring a virtual memory arena, :c:func:`mps_arena_configure` accepts the :term:`keyword - arguments` :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` and - :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` as described above. + arguments` :c:macro:`MPS_KEY_COMMIT_LIMIT` and + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` as described above. .. index:: @@ -350,7 +350,7 @@ Arena properties virtual memory interface. The commit limit can be changed by passing the - :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to + :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The commit limit cannot be set to a value that is lower than the number of bytes that the MPS is using. If an attempt is made to @@ -470,7 +470,7 @@ Arena properties the MPS is allowed to have. The spare commit limit can be changed by passing the - :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword argument` to :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. Setting it to a value lower than the current amount of spare committed memory causes spare @@ -499,7 +499,7 @@ Arena properties :c:func:`mps_arena_commit_limit`. The amount of "spare committed" memory can be limited passing the - :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword argument` to :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The value of the limit can be retrieved with :c:func:`mps_arena_spare_commit_limit`. This is diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 329f90d48dc..5a3f9900bf1 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -29,7 +29,7 @@ Deprecated in version 1.115 .. deprecated:: - Pass the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword + Pass the :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 6d321eab491..a2d100d1672 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -82,45 +82,45 @@ now :c:macro:`MPS_KEY_ARGS_END`. The type of :term:`keyword argument` keys. Must take one of the following values: - =========================================== ========================================================= ========================================================== - Keyword Type & field in ``arg.val`` See - =========================================== ========================================================= ========================================================== - :c:macro:`MPS_KEY_ARGS_END` *none* *see above* - :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` - :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` - :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` - :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` - :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` - :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` - :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` - =========================================== ========================================================= ========================================================== + ======================================== ========================================================= ========================================================== + Keyword Type & field in ``arg.val`` See + ======================================== ========================================================= ========================================================== + :c:macro:`MPS_KEY_ARGS_END` *none* *see above* + :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` + :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` + :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` + :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` + :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` + :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` + :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` + ======================================== ========================================================= ========================================================== .. c:function:: MPS_ARGS_BEGIN(args) diff --git a/mps/test/function/120.c b/mps/test/function/120.c index 77609e3e37f..032fa722c3f 100644 --- a/mps/test/function/120.c +++ b/mps/test/function/120.c @@ -41,7 +41,7 @@ static void test(void) { * RES_COMMIT_LIMIT. */ MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024); report_res("create", mps_arena_create_k(&arena, mps_arena_class_vm(), args)); } MPS_ARGS_END(args); diff --git a/mps/test/function/165.c b/mps/test/function/165.c index e542cc111a7..da0734ba279 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -37,7 +37,7 @@ static void test(void) MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024*1024*40); - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 1024ul*1024ul*100ul); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 1024ul*1024ul*100ul); cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "create arena"); } MPS_ARGS_END(args); @@ -60,7 +60,7 @@ static void test(void) /* Set the spare commit limit to 0MB */ MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 0); + MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 0); cdie(mps_arena_configure(arena, args), "mps_arena_configure"); } MPS_ARGS_END(args); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); @@ -75,7 +75,7 @@ static void test(void) /* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */ MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, -1); + MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, -1); cdie(mps_arena_configure(arena, args), "mps_arena_configure"); } MPS_ARGS_END(args); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); @@ -88,7 +88,7 @@ static void test(void) /* Reducing the spare committed limit should return most of the spare */ MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 1024*1024); + MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 1024*1024); cdie(mps_arena_configure(arena, args), "mps_arena_configure"); } MPS_ARGS_END(args); com2 = mps_arena_committed(arena); diff --git a/mps/test/function/231.c b/mps/test/function/231.c index e0620fd09b3..ac13e02d4a1 100644 --- a/mps/test/function/231.c +++ b/mps/test/function/231.c @@ -19,7 +19,7 @@ static void test(void) mps_arena_t arena; MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024); report_res("create1", mps_arena_create_k(&arena, mps_arena_class_vm(), args)); } MPS_ARGS_END(args); @@ -28,7 +28,7 @@ static void test(void) mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none)); MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024); + MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024); report_res("configure", mps_arena_configure(arena, args)); } MPS_ARGS_END(args); From 5d3379f84c44cf7a723ac2fac9353766bda77553 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Sep 2015 16:36:48 +0100 Subject: [PATCH 24/40] Add a return value to arenasetsparecommitlimit, as suggested by nb in review. Copied from Perforce Change: 188287 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 8 +++++--- mps/code/mpm.h | 2 +- mps/code/mpsi.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 4206ec9ab72..a317f16343e 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -403,7 +403,9 @@ Res ArenaConfigure(Arena arena, ArgList args) } if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) { Size limit = arg.val.size; - (void)ArenaSetSpareCommitLimit(arena, limit); + res = ArenaSetSpareCommitLimit(arena, limit); + if (res != ResOK) + return res; } return (*arena->class->configure)(arena, args); @@ -1339,7 +1341,7 @@ Size ArenaSpareCommitLimit(Arena arena) return arena->spareCommitLimit; } -void ArenaSetSpareCommitLimit(Arena arena, Size limit) +Res ArenaSetSpareCommitLimit(Arena arena, Size limit) { AVERT(Arena, arena); /* Can't check limit, as all possible values are allowed. */ @@ -1351,7 +1353,7 @@ void ArenaSetSpareCommitLimit(Arena arena, Size limit) } EVENT2(SpareCommitLimitSet, arena, limit); - return; + return ResOK; } /* Used by arenas which don't use spare committed memory */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ae528e784d8..2a8482ad95e 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -620,7 +620,7 @@ extern Size ArenaSpareCommitted(Arena arena); extern Size ArenaCommitLimit(Arena arena); extern Res ArenaSetCommitLimit(Arena arena, Size limit); extern Size ArenaSpareCommitLimit(Arena arena); -extern void ArenaSetSpareCommitLimit(Arena arena, Size limit); +extern Res ArenaSetSpareCommitLimit(Arena arena, Size limit); extern Size ArenaNoPurgeSpare(Arena arena, Size size); extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 8ee89ac3923..d9bdc80da8d 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -204,7 +204,7 @@ mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit) void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit) { ArenaEnter(arena); - ArenaSetSpareCommitLimit(arena, limit); + (void)ArenaSetSpareCommitLimit(arena, limit); ArenaLeave(arena); return; From 012de550deb8f277cf77080c8f6d4adbf14dfbe8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Sep 2015 16:38:55 +0100 Subject: [PATCH 25/40] Alphabetize list of keywords; spare commit limit does not do anything for the client arena. Copied from Perforce Change: 188288 ServerID: perforce.ravenbrook.com --- mps/design/arena.txt | 14 +++++++------- mps/manual/source/topic/keyword.rst | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/design/arena.txt b/mps/design/arena.txt index a72bfbcb09c..2a94bb05b39 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -432,13 +432,13 @@ bytes; ``spareCommitLimit`` records the limit (set by the user) on the amount of spare committed memory. ``spareCommitted`` is modified by the arena class but its value is used by the generic arena code. There are two uses: a getter function for this value is provided through the -MPS interface (``mps_arena_spare_commit_limit_set()``), and by the -``SetSpareCommitLimit()`` function to determine whether the amount of -spare committed memory needs to be reduced. ``spareCommitLimit`` is -manipulated by generic arena code, however the associated semantics -are the responsibility of the class. It is the class's responsibility -to ensure that it doesn't use more spare committed bytes than the -value in ``spareCommitLimit``. +MPS interface (``mps_arena_spare_commit_limit()``), and by the +``ArenaSetSpareCommitLimit()`` function to determine whether the +amount of spare committed memory needs to be reduced. +``spareCommitLimit`` is manipulated by generic arena code, however the +associated semantics are the responsibility of the class. It is the +class's responsibility to ensure that it doesn't use more spare +committed bytes than the value in ``spareCommitLimit``. _`.spare-commit-limit`: The function ``ArenaSetSpareCommitLimit()`` sets the ``spareCommitLimit`` field. If the limit is set to a value lower diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index a2d100d1672..ddbfbfd57ac 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -89,12 +89,11 @@ now :c:macro:`MPS_KEY_ARGS_END`. :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` @@ -119,6 +118,7 @@ now :c:macro:`MPS_KEY_ARGS_END`. :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm` :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` ======================================== ========================================================= ========================================================== From ffc148c00814b83cbb4d4c1e92d92b9fd233b4a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Sep 2015 20:59:10 +0100 Subject: [PATCH 26/40] Add more assertions. Copied from Perforce Change: 188304 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 784533d66fa..1120b868897 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -265,6 +265,41 @@ this documentation. :c:type:`mps_fmt_t` for this argument. +``global.c: RingIsSingle(&arena->chainRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`generation chains` belonging to the + arena. It is necessary to call :c:func:`mps_chain_destroy` first. + + +``global.c: RingIsSingle(&arena->formatRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`object formats` belonging to the arena. + It is necessary to call :c:func:`mps_fmt_destroy` first. + + +``global.c: RingIsSingle(&arena->rootRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`roots` belonging to the arena. + It is necessary to call :c:func:`mps_root_destroy` first. + + +``global.c: RingIsSingle(&arena->threadRing)`` + + The client program called :c:func:`mps_arena_destroy` without + deregistering all the :term:`threads` belonging to the arena. + It is necessary to call :c:func:`mps_thread_dereg` first. + + +``global.c: RingLength(&arenaGlobals->poolRing) == 5`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`pools` belonging to the arena. + It is necessary to call :c:func:`mps_pool_destroy` first. + + ``lockix.c: res == 0`` ``lockw3.c: lock->claims == 0`` @@ -299,13 +334,12 @@ this documentation. condition? -``ring.c: ring->next == ring`` +``poolsnc.c: foundSeg`` - The client program destroyed an MPS data structure without having - destroyed all the data structures that it owns first. For example, - it destroyed an arena without first destroying all pools in that - arena, or it destroyed a thread without first destroying all - roots using that thread. + The client program passed an incorrect ``frame`` argument to + :c:func:`mps_ap_frame_pop`. This argument must be the result from + a previous call to :c:func:`mps_ap_frame_push` on the same + allocation point. ``seg.c: gcseg->buffer == NULL`` From b5fe5356ec2bac4f190cbf8d58541eca970233e9 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Tue, 13 Oct 2015 15:19:12 +0100 Subject: [PATCH 27/40] Improve documentation of mps_fix_call(): the called function must use mps_scan_begin and mps_scan_end itself. Copied from Perforce Change: 188410 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/scanning.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index c9f71e3b503..6b4c4a1d396 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -361,9 +361,9 @@ Scanning interface .. c:function:: MPS_FIX_CALL(ss, call) - Call a function from within a :term:`scan method`, between - :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, passing - the :term:`scan state` correctly. + Call a function to do some scanning, from within a :term:`scan + method`, between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, passing the :term:`scan state` correctly. ``ss`` is the scan state that was passed to the scan method. @@ -377,6 +377,9 @@ Scanning interface must wrap the call with :c:func:`MPS_FIX_CALL` to ensure that the scan state is passed correctly. + The function being called must use :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END` appropriately. + In example below, the scan method ``obj_scan`` fixes the object's ``left`` and ``right`` references, but delegates the scanning of references inside the object's ``data`` member to the function @@ -406,9 +409,11 @@ Scanning interface .. warning:: - Use of :c:func:`MPS_FIX_CALL` is best avoided, as it forces - values out of registers. The gains in simplicity of the code - need to be measured against the loss in performance. + Use of :c:func:`MPS_FIX_CALL` is best avoided, as it may + force values out of registers (depending on compiler + optimisations such as inlining). The gains in simplicity of + the code ought to be measured against the loss in + performance. .. index:: From 65bd8e550f6ce3bca6a008bc00d74cc6d8433206 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 21 Dec 2015 11:06:06 +0000 Subject: [PATCH 28/40] Making lack of section numbers consistent. Improving attributions. Copied from Perforce Change: 188846 ServerID: perforce.ravenbrook.com --- mps/design/guide.hex.trans.txt | 40 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index 95c533f6bc8..8120f6e53e5 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -22,10 +22,11 @@ hexadecimal digits. _`.readership`: This document is intended for anyone devising arbitrary constants which may appear in hex-dumps. -_`.sources`: This transliteration was supplied by RHSK in -`mail.richardk.1997-04-07.13-44`_. - -.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt +_`.sources`: This transliteration was supplied by Richard Kistruck +[RHSK-1997-04-07]_ based on magic number encodings for object signatures +used by Richard Brooksby [RB-1996-02-12]_, the existence of which was +inspired by the structure marking used in the Multics operating system +[THVV-1995]_. Transliteration @@ -78,8 +79,8 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common letter that it deserves it. -4. Notes --------- +Notes +----- _`.change`: This transliteration differs from the old transliteration used for signatures (see design.mps.sig_), as follows: J:6->1; @@ -106,6 +107,33 @@ selected (by capitalisation), e.g.:: #define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */ +References +---------- + +.. [RB-1996-02-12] + "Signature magic numbers" (e-mail message); + `Richard Brooksby`_; + Harlequin; + 1996-12-02 12:05:30Z. + +.. _`Richard Brooksby`: mailto:rb@ravenbrook.com + +.. [RHSK-1997-04-07] + "Alpha-to-Hex v1.0 beta"; + Richard Kistruck; + Ravenbrook; + 1997-04-07 14:42:02+0100; + . + +.. [THVV-1995] + "Structure Marking"; + Tom Van Vleck; + multicians.org_; + . + +.. _multicians.org: http://www.multicians.org/ + + Document History ---------------- 2013-05-10 RB_ Converted to reStructuredText and imported to MPS design. From 2aacdd3867004fecf1f445d765f8b7c02d8bbc04 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 14 Jan 2016 17:34:49 +0000 Subject: [PATCH 29/40] Using os-provided getopt_long where available, since it doesn't compile cleanly on os x. The getopt_long code promises that the argv array is const, but permutes it. (This problem is mentioned in the man page.) We have trouble getting this past our strict compiler options, especially under Xcode. Copied from Perforce Change: 188909 ServerID: perforce.ravenbrook.com --- mps/code/djbench.c | 7 ++++++- mps/code/gcbench.c | 7 ++++++- mps/code/mps.xcodeproj/project.pbxproj | 8 -------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mps/code/djbench.c b/mps/code/djbench.c index 33cf1d4bdb9..fbc6dcabc1c 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -13,10 +13,15 @@ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, stderr */ #include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */ #include /* CLOCKS_PER_SEC, clock */ diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 2ae97104930..6d7f3339667 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -7,13 +7,18 @@ */ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" #include "mpm.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, printf, putchars, sscanf, stderr, stdout */ #include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ #include /* clock, CLOCKS_PER_SEC */ diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 21abc599f2c..30aad557d3b 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -285,7 +285,6 @@ 3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; - 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; }; @@ -327,7 +326,6 @@ 31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; }; 6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; }; 6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; }; 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; @@ -1635,8 +1633,6 @@ 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; }; 318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; }; 318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; }; - 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; }; - 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; }; 31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; }; 31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; }; 31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; }; @@ -2267,8 +2263,6 @@ 318DA8C21892B0B20089718C /* Benchmarks */ = { isa = PBXGroup; children = ( - 318DA8D01892B13B0089718C /* getopt.h */, - 318DA8D11892B13B0089718C /* getoptl.c */, 318DA8CE1892B1210089718C /* djbench.c */, 6313D46618A3FDC900EB03EF /* gcbench.c */, ); @@ -3909,7 +3903,6 @@ files = ( 318DA8D31892B27E0089718C /* testlib.c in Sources */, 6313D47318A4028E00EB03EF /* djbench.c in Sources */, - 318DA8D21892B13B0089718C /* getoptl.c in Sources */, 22561A9A18F426BB00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4018,7 +4011,6 @@ 6313D47418A4029200EB03EF /* gcbench.c in Sources */, 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */, 6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */, - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */, 22561A9B18F426F300372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From eac348d664282b12d2e38c94254adf8fa2738f11 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 19 Jan 2016 16:22:39 +0000 Subject: [PATCH 30/40] Catch-up merge from masters. Copied from Perforce Change: 188921 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- mps/code/.p4ignore | 2 + mps/code/amcss.c | 24 +- mps/code/amcssth.c | 208 ++++--- mps/code/ananmv.nmk | 3 +- mps/code/arena.c | 206 ++++--- mps/code/arenacl.c | 68 ++- mps/code/arenavm.c | 48 +- mps/code/buffer.c | 8 +- mps/code/cbs.c | 6 +- mps/code/comm.gmk | 7 +- mps/code/{commpost.nmk => comm.nmk} | 337 ++++++++++- mps/code/commpre.nmk | 369 ------------ mps/code/djbench.c | 7 +- mps/code/freelist.c | 22 +- mps/code/gcbench.c | 7 +- mps/code/global.c | 3 +- mps/code/land.c | 16 +- mps/code/ld.c | 17 +- mps/code/mpm.c | 14 +- mps/code/mpm.h | 8 +- mps/code/mpmst.h | 4 +- mps/code/mpmtypes.h | 1 - mps/code/mps.c | 1 - mps/code/mps.xcodeproj/project.pbxproj | 28 +- mps/code/mpsi.c | 11 +- mps/code/mv.nmk | 2 +- mps/code/pc.nmk | 2 +- mps/code/pool.c | 6 +- mps/code/poolabs.c | 10 +- mps/code/poolawl.c | 5 +- mps/code/poolmv.c | 13 +- mps/code/protan.c | 7 +- mps/code/protix.c | 5 +- mps/code/protw3.c | 5 +- mps/code/reserv.c | 1 + mps/code/root.c | 19 +- mps/code/seg.c | 14 +- mps/code/shield.c | 7 +- mps/code/splay.c | 11 +- mps/code/trace.c | 5 +- mps/code/traceanc.c | 5 +- mps/code/tract.c | 11 +- mps/code/tract.h | 6 +- mps/code/tree.c | 11 +- mps/code/w3i3mv.nmk | 6 +- mps/code/w3i3pc.nmk | 6 +- mps/code/w3i6mv.nmk | 7 +- mps/code/w3i6pc.nmk | 8 +- mps/design/an.txt | 216 +++++++ mps/design/bootstrap.txt | 127 ++++ mps/design/cbs.txt | 4 +- mps/design/exec-env.txt | 189 ++++++ mps/design/guide.hex.trans.txt | 40 +- mps/design/guide.review.txt | 96 +++ mps/design/index.txt | 12 +- mps/design/io.txt | 8 +- mps/design/land.txt | 14 +- mps/design/lib.txt | 10 +- mps/design/lock.txt | 8 +- mps/design/prmc.txt | 2 +- mps/design/prot.txt | 17 +- mps/design/protan.txt | 135 ----- mps/design/sp.txt | 9 +- mps/design/splay-rotate-left.svg | 4 +- mps/design/splay-rotate-right.svg | 4 +- mps/design/ss.txt | 2 +- mps/design/testthr.txt | 2 +- mps/design/type.txt | 4 +- mps/design/vm.txt | 4 +- mps/design/writef.txt | 46 +- mps/manual/build.txt | 3 +- mps/manual/source/_templates/links.html | 4 +- mps/manual/source/design/index.rst | 5 + mps/manual/source/design/old.rst | 2 - mps/manual/source/glossary/b.rst | 17 +- mps/manual/source/glossary/index.rst | 1 + mps/manual/source/glossary/m.rst | 6 +- mps/manual/source/glossary/r.rst | 2 +- mps/manual/source/guide/index.rst | 2 +- mps/manual/source/guide/lang.rst | 35 +- mps/manual/source/guide/malloc.rst | 70 +++ mps/manual/source/pool/amc.rst | 20 +- mps/manual/source/pool/amcz.rst | 13 +- mps/manual/source/pool/ams.rst | 35 +- mps/manual/source/pool/awl.rst | 21 +- mps/manual/source/pool/lo.rst | 9 - mps/manual/source/pool/mfs.rst | 13 +- mps/manual/source/pool/mv.rst | 64 +- mps/manual/source/pool/mvff.rst | 100 +--- mps/manual/source/pool/mvt.rst | 52 +- mps/manual/source/pool/snc.rst | 30 +- mps/manual/source/release.rst | 148 ++++- mps/manual/source/topic/allocation.rst | 28 +- mps/manual/source/topic/arena.rst | 187 +----- mps/manual/source/topic/deprecated.rst | 745 ++++++++++++++++++++++++ mps/manual/source/topic/error.rst | 111 ++-- mps/manual/source/topic/format.rst | 154 +---- mps/manual/source/topic/index.rst | 2 + mps/manual/source/topic/interface.rst | 7 +- mps/manual/source/topic/keyword.rst | 82 ++- mps/manual/source/topic/plinth.rst | 10 + mps/manual/source/topic/pool.rst | 40 +- mps/manual/source/topic/porting.rst | 137 +++-- mps/manual/source/topic/scanning.rst | 44 +- mps/manual/source/topic/telemetry.rst | 35 -- mps/manual/source/topic/thread.rst | 44 -- mps/test/README | 19 +- mps/test/argerr/111.c | 4 + mps/test/argerr/143.c | 4 + mps/test/argerr/146.c | 17 +- mps/test/argerr/147.c | 8 +- mps/test/argerr/148.c | 8 +- mps/test/argerr/149.c | 6 +- mps/test/argerr/150.c | 6 +- mps/test/argerr/151.c | 6 +- mps/test/argerr/35.c | 2 +- mps/test/argerr/36.c | 11 +- mps/test/conerr/22.c | 2 +- mps/test/conerr/26.c | 2 +- mps/test/conerr/3.c | 6 +- mps/test/function/103.c | 4 +- mps/test/function/120.c | 12 +- mps/test/function/121.c | 50 +- mps/test/function/137.c | 8 +- mps/test/function/139.c | 8 +- mps/test/function/144.c | 8 +- mps/test/function/150.c | 7 +- mps/test/function/158.c | 8 +- mps/test/function/159.c | 8 +- mps/test/function/160.c | 7 +- mps/test/function/161.c | 7 +- mps/test/function/162.c | 7 +- mps/test/function/163.c | 8 +- mps/test/function/18.c | 8 +- mps/test/function/19.c | 6 +- mps/test/function/20.c | 3 +- mps/test/function/21.c | 3 +- mps/test/function/22.c | 3 +- mps/test/function/224.c | 2 +- mps/test/function/226.c | 6 +- mps/test/function/227.c | 19 +- mps/test/function/229.c | 74 +++ mps/test/function/23.c | 10 +- mps/test/function/96.c | 8 +- mps/test/test/script/clib | 6 +- mps/test/test/script/headread | 2 +- mps/test/test/script/options | 2 +- mps/test/test/script/runtest | 2 +- mps/test/testsets/argerr | 22 +- mps/test/testsets/conerr | 18 +- mps/test/testsets/passing | 2 + mps/tool/testrun.bat | 10 +- mps/tool/testrun.sh | 80 ++- 154 files changed, 3259 insertions(+), 2100 deletions(-) rename mps/code/{commpost.nmk => comm.nmk} (64%) delete mode 100644 mps/code/commpre.nmk create mode 100644 mps/design/an.txt create mode 100644 mps/design/bootstrap.txt create mode 100644 mps/design/exec-env.txt create mode 100644 mps/design/guide.review.txt delete mode 100644 mps/design/protan.txt create mode 100644 mps/manual/source/guide/malloc.rst create mode 100644 mps/manual/source/topic/deprecated.rst create mode 100644 mps/test/function/229.c diff --git a/mps/Makefile.in b/mps/Makefile.in index 1495a0fc313..fe33a4d49f6 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -73,7 +73,7 @@ install: @INSTALL_TARGET@ test-make-build: $(MAKE) $(TARGET_OPTS) testci $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool clean testansi - $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll + $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpollnone test-xcode-build: $(XCODEBUILD) -config Debug -target testci diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 6cb34b80f0c..2864ba7793f 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -10,7 +10,9 @@ lii3gc lii6gc lii6ll w3i3mv +w3i3pc w3i6mv +w3i6pc xci3gc xci6ll # Visual Studio junk diff --git a/mps/code/amcss.c b/mps/code/amcss.c index bc0d8861149..3b15f7fb967 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -45,14 +45,14 @@ static mps_ap_t ap; static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; static size_t scale; /* Overall scale factor. */ +static unsigned long nCollsStart; +static unsigned long nCollsDone; /* report -- report statistics from any messages */ static void report(mps_arena_t arena) { - static int nCollsStart = 0; - static int nCollsDone = 0; mps_message_type_t type; while(mps_message_queue_type(&type, arena)) { @@ -62,7 +62,7 @@ static void report(mps_arena_t arena) if (type == mps_message_type_gc_start()) { nCollsStart += 1; - printf("\n{\n Collection %d started. Because:\n", nCollsStart); + printf("\n{\n Collection %lu started. Because:\n", nCollsStart); printf(" %s\n", mps_message_gc_start_why(arena, message)); printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message)); @@ -74,7 +74,7 @@ static void report(mps_arena_t arena) condemned = mps_message_gc_condemned_size(arena, message); not_condemned = mps_message_gc_not_condemned_size(arena, message); - printf("\n Collection %d finished:\n", nCollsDone); + printf("\n Collection %lu finished:\n", nCollsDone); printf(" live %"PRIuLONGEST"\n", (ulongest_t)live); printf(" condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); @@ -94,10 +94,12 @@ static void report(mps_arena_t arena) static mps_addr_t make(size_t rootsCount) { + static unsigned long calls = 0; size_t length = rnd() % (scale * avLEN); size_t size = (length+2) * sizeof(mps_word_t); mps_addr_t p; mps_res_t res; + ++ calls; do { MPS_RESERVE_BLOCK(res, p, ap, size); @@ -167,6 +169,8 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); + nCollsStart = 0; + nCollsDone = 0; collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); @@ -174,20 +178,18 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, ramping = 1; objs = 0; while (collections < collectionsCOUNT) { - mps_word_t c; size_t r; - c = mps_collections(arena); - if (collections != c) { + report(arena); + if (collections != nCollsStart) { if (!described) { die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe"); described = TRUE; } - collections = c; - report(arena); + collections = nCollsStart; - printf("%lu objects (mps_collections says: %"PRIuLONGEST")\n", objs, - (ulongest_t)c); + printf("%lu objects (nCollsStart=%"PRIuLONGEST")\n", objs, + (ulongest_t)collections); /* test mps_arena_has_addr */ { diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 59b48ff27c4..c6e2d214b5d 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -59,33 +59,9 @@ static mps_gen_param_s testChain[genCOUNT] = { static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; -/* report - report statistics from any terminated GCs */ - -static void report(mps_arena_t arena) -{ - mps_message_t message; - static int nCollections = 0; - - while (mps_message_get(&message, arena, mps_message_type_gc())) { - size_t live, condemned, not_condemned; - - live = mps_message_gc_live_size(arena, message); - condemned = mps_message_gc_condemned_size(arena, message); - not_condemned = mps_message_gc_not_condemned_size(arena, message); - - printf("\nCollection %d finished:\n", ++nCollections); - printf("live %"PRIuLONGEST"\n", (ulongest_t)live); - printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); - printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - - mps_message_discard(arena, message); - } -} - +static mps_word_t collections; static mps_arena_t arena; -static mps_fmt_t format; -static mps_chain_t chain; static mps_root_t exactRoot, ambigRoot; static unsigned long objs = 0; @@ -123,32 +99,6 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, } -/* init -- initialize roots and chain */ - -static void init(void) -{ - size_t i; - - die(dylan_fmt(&format, arena), "fmt_create"); - die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - for(i = 0; i < exactRootsCOUNT; ++i) - exactRoots[i] = objNULL; - for(i = 0; i < ambigRootsCOUNT; ++i) - ambigRoots[i] = rnd_addr(); - - die(mps_root_create_table_masked(&exactRoot, arena, - mps_rank_exact(), (mps_rm_t)0, - &exactRoots[0], exactRootsCOUNT, - (mps_word_t)1), - "root_create_table(exact)"); - die(mps_root_create_table(&ambigRoot, arena, - mps_rank_ambig(), (mps_rm_t)0, - &ambigRoots[0], ambigRootsCOUNT), - "root_create_table(ambig)"); -} - - /* churn -- create an object and install into roots */ static void churn(mps_ap_t ap, size_t roots_count) @@ -207,10 +157,11 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void test_pool(mps_pool_t pool, size_t roots_count, int mode) +static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, + int mode) { size_t i; - mps_word_t collections, rampSwitch; + mps_word_t rampSwitch; mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp(); int ramping; mps_ap_t ap, busy_ap; @@ -219,8 +170,12 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) closure_s cl; int walked = FALSE, ramped = FALSE; + printf("\n------ mode: %s pool: %s-------\n", + mode == ModeWALK ? "WALK" : "COMMIT", name); + cl.pool = pool; cl.roots_count = roots_count; + collections = 0; for (i = 0; i < NELEMS(kids); ++i) testthr_create(&kids[i], kid_thread, &cl); @@ -231,72 +186,85 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); - collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)"); ramping = 1; while (collections < collectionsCOUNT) { - mps_word_t c; - size_t r; + mps_message_type_t type; - c = mps_collections(arena); + if (mps_message_queue_type(&type, arena)) { + mps_message_t msg; + mps_bool_t b = mps_message_get(&msg, arena, type); + Insist(b); /* we just checked there was one */ - if (collections != c) { - collections = c; - printf("\nCollection %lu started, %lu objects, committed=%lu.\n", - (unsigned long)c, objs, (unsigned long)mps_arena_committed(arena)); - report(arena); + if (type == mps_message_type_gc()) { + size_t live = mps_message_gc_live_size(arena, msg); + size_t condemned = mps_message_gc_condemned_size(arena, msg); + size_t not_condemned = mps_message_gc_not_condemned_size(arena, msg); - for (i = 0; i < exactRootsCOUNT; ++i) - cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), - "all roots check"); + printf("\nCollection %lu finished:\n", collections++); + printf("live %"PRIuLONGEST"\n", (ulongest_t)live); + printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); + printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) { - unsigned long object_count = 0; - mps_arena_park(arena); - mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0); - mps_arena_release(arena); - printf("stepped on %lu objects.\n", object_count); - walked = TRUE; - } - if (collections >= rampSwitch && !ramped) { - int begin_ramp = !ramping - || /* Every other time, switch back immediately. */ (collections & 1); + } else if (type == mps_message_type_gc_start()) { + printf("\nCollection %lu started, %lu objects, committed=%lu.\n", + (unsigned long)collections, objs, + (unsigned long)mps_arena_committed(arena)); - rampSwitch += rampSIZE; - if (ramping) { - die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); - die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)"); - ramping = 0; - /* kill half of the roots */ - for(i = 0; i < exactRootsCOUNT; i += 2) { - if (exactRoots[i] != objNULL) { - cdie(dylan_check(exactRoots[i]), "ramp kill check"); - exactRoots[i] = objNULL; + for (i = 0; i < exactRootsCOUNT; ++i) + cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), + "all roots check"); + + if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) + { + unsigned long count = 0; + mps_arena_park(arena); + mps_arena_formatted_objects_walk(arena, test_stepper, &count, 0); + mps_arena_release(arena); + printf("stepped on %lu objects.\n", count); + walked = TRUE; + } + if (collections >= rampSwitch && !ramped) { + /* Every other time, switch back immediately. */ + int begin_ramp = !ramping || (collections & 1); + + rampSwitch += rampSIZE; + if (ramping) { + die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); + die(mps_ap_alloc_pattern_end(busy_ap, ramp), + "pattern end (busy_ap)"); + ramping = 0; + /* kill half of the roots */ + for(i = 0; i < exactRootsCOUNT; i += 2) { + if (exactRoots[i] != objNULL) { + cdie(dylan_check(exactRoots[i]), "ramp kill check"); + exactRoots[i] = objNULL; + } } } + if (begin_ramp) { + die(mps_ap_alloc_pattern_begin(ap, ramp), + "pattern rebegin (ap)"); + die(mps_ap_alloc_pattern_begin(busy_ap, ramp), + "pattern rebegin (busy_ap)"); + ramping = 1; + } } - if (begin_ramp) { - die(mps_ap_alloc_pattern_begin(ap, ramp), - "pattern rebegin (ap)"); - die(mps_ap_alloc_pattern_begin(busy_ap, ramp), - "pattern rebegin (busy_ap)"); - ramping = 1; - } + ramped = TRUE; } - ramped = TRUE; + + mps_message_discard(arena, msg); } churn(ap, roots_count); - - r = (size_t)rnd(); - - if (r % initTestFREQ == 0) - *(int*)busy_init = -1; /* check that the buffer is still there */ - + { + size_t r = (size_t)rnd(); + if (r % initTestFREQ == 0) + *(int*)busy_init = -1; /* check that the buffer is still there */ + } if (objs % 1024 == 0) { - report(arena); putchar('.'); fflush(stdout); } @@ -312,6 +280,9 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) static void test_arena(int mode) { + size_t i; + mps_fmt_t format; + mps_chain_t chain; mps_thr_t thread; mps_root_t reg_root; mps_pool_t amc_pool, amcz_pool; @@ -325,7 +296,25 @@ static void test_arena(int mode) if (mode == ModeCOMMIT) die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); mps_message_type_enable(arena, mps_message_type_gc()); - init(); + mps_message_type_enable(arena, mps_message_type_gc_start()); + + die(dylan_fmt(&format, arena), "fmt_create"); + die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); + + for(i = 0; i < exactRootsCOUNT; ++i) + exactRoots[i] = objNULL; + for(i = 0; i < ambigRootsCOUNT; ++i) + ambigRoots[i] = rnd_addr(); + + die(mps_root_create_table_masked(&exactRoot, arena, + mps_rank_exact(), (mps_rm_t)0, + &exactRoots[0], exactRootsCOUNT, + (mps_word_t)1), + "root_create_table(exact)"); + die(mps_root_create_table(&ambigRoot, arena, + mps_rank_ambig(), (mps_rm_t)0, + &ambigRoots[0], ambigRootsCOUNT), + "root_create_table(ambig)"); die(mps_thread_reg(&thread, arena), "thread_reg"); die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, marker, 0), "root_create"); @@ -335,8 +324,8 @@ static void test_arena(int mode) die(mps_pool_create(&amcz_pool, arena, mps_class_amcz(), format, chain), "pool_create(amcz)"); - test_pool(amc_pool, exactRootsCOUNT, mode); - test_pool(amcz_pool, 0, mode); + test_pool("AMC", amc_pool, exactRootsCOUNT, mode); + test_pool("AMCZ", amcz_pool, 0, mode); mps_arena_park(arena); mps_pool_destroy(amc_pool); @@ -347,7 +336,6 @@ static void test_arena(int mode) mps_root_destroy(ambigRoot); mps_chain_destroy(chain); mps_fmt_destroy(format); - report(arena); mps_arena_destroy(arena); } @@ -367,18 +355,18 @@ int main(int argc, char *argv[]) * Copyright (c) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * 3. Redistributions in any form must be accompanied by information on how * to obtain complete source code for this software and any accompanying * software that uses this software. The source code must either be @@ -389,7 +377,7 @@ int main(int argc, char *argv[]) * include source code for modules or files that typically accompany the * major components of the operating system on which the executable file * runs. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk index 41d80a0671a..a8017020b5a 100644 --- a/mps/code/ananmv.nmk +++ b/mps/code/ananmv.nmk @@ -16,9 +16,8 @@ MPMPF = \ [than] \ [vman] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/arena.c b/mps/code/arena.c index 6c6b5220229..a54cae0cb60 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -41,6 +41,7 @@ Bool ArenaGrainSizeCheck(Size size) static void ArenaTrivCompact(Arena arena, Trace trace); static void arenaFreePage(Arena arena, Addr base, Pool pool); +static void arenaFreeLandFinish(Arena arena); /* ArenaTrivDescribe -- produce trivial description of an arena */ @@ -85,7 +86,6 @@ DEFINE_CLASS(AbstractArenaClass, class) class->varargs = ArgTrivVarargs; class->init = NULL; class->finish = NULL; - class->reserved = NULL; class->purgeSpare = ArenaNoPurgeSpare; class->extend = ArenaNoExtend; class->grow = ArenaNoGrow; @@ -113,7 +113,6 @@ Bool ArenaClassCheck(ArenaClass class) CHECKL(FUNCHECK(class->varargs)); CHECKL(FUNCHECK(class->init)); CHECKL(FUNCHECK(class->finish)); - CHECKL(FUNCHECK(class->reserved)); CHECKL(FUNCHECK(class->purgeSpare)); CHECKL(FUNCHECK(class->extend)); CHECKL(FUNCHECK(class->grow)); @@ -142,9 +141,12 @@ Bool ArenaCheck(Arena arena) CHECKD(Reservoir, &arena->reservoirStruct); } - /* Can't check that limit>=size because we may call ArenaCheck */ - /* while the size is being adjusted. */ - + /* .reserved.check: Would like to check that arena->committed <= + * arena->reserved, but that isn't always true in the VM arena. + * Memory is committed early on when VMChunkCreate calls vmArenaMap + * (to provide a place for the chunk struct) but is not recorded as + * reserved until ChunkInit calls ArenaChunkInsert. + */ CHECKL(arena->committed <= arena->commitLimit); CHECKL(arena->spareCommitted <= arena->committed); @@ -206,6 +208,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) arena->class = class; + arena->reserved = (Size)0; arena->committed = (Size)0; /* commitLimit may be overridden by init (but probably not */ /* as there's not much point) */ @@ -236,10 +239,11 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) arena->sig = ArenaSig; AVERT(Arena, arena); - /* Initialise a pool to hold the arena's CBS blocks. This pool can't be - allowed to extend itself using ArenaAlloc because it is used during - ArenaAlloc, so MFSExtendSelf is set to FALSE. Failures to extend are - handled where the Land is used. */ + /* Initialise a pool to hold the CBS blocks for the arena's free + * land. This pool can't be allowed to extend itself using + * ArenaAlloc because it is used to implement ArenaAlloc, so + * MFSExtendSelf is set to FALSE. Failures to extend are handled + * where the free land is used: see arenaFreeLandInsertExtend. */ MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct)); @@ -251,18 +255,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) if (res != ResOK) goto failMFSInit; - /* Initialise the freeLand. */ - MPS_ARGS_BEGIN(liArgs) { - MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); - res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, - ArenaGrainSize(arena), arena, liArgs); - } MPS_ARGS_END(liArgs); - AVER(res == ResOK); /* no allocation, no failure expected */ - if (res != ResOK) - goto failLandInit; - /* Note that although freeLand is initialised, it doesn't have any memory - for its blocks, so hasFreeLand remains FALSE until later. */ - /* initialize the reservoir, */ res = ReservoirInit(&arena->reservoirStruct, arena); if (res != ResOK) @@ -272,8 +264,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) return ResOK; failReservoirInit: - LandFinish(ArenaFreeLand(arena)); -failLandInit: PoolFinish(ArenaCBSBlockPool(arena)); failMFSInit: GlobalsFinish(ArenaGlobals(arena)); @@ -299,6 +289,43 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size); ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size); ARG_DEFINE_KEY(ARENA_ZONED, Bool); +static Res arenaFreeLandInit(Arena arena) +{ + Res res; + + AVERT(Arena, arena); + AVER(!arena->hasFreeLand); + AVER(arena->primary != NULL); + + /* Initialise the free land. */ + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); + res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, + ArenaGrainSize(arena), arena, liArgs); + } MPS_ARGS_END(liArgs); + AVER(res == ResOK); /* no allocation, no failure expected */ + if (res != ResOK) + goto failLandInit; + + /* With the primary chunk initialised we can add page memory to the + * free land that describes the free address space in the primary + * chunk. */ + res = ArenaFreeLandInsert(arena, + PageIndexBase(arena->primary, + arena->primary->allocBase), + arena->primary->limit); + if (res != ResOK) + goto failFreeLandInsert; + + arena->hasFreeLand = TRUE; + return ResOK; + +failFreeLandInsert: + LandFinish(ArenaFreeLand(arena)); +failLandInit: + return res; +} + Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) { Arena arena; @@ -324,15 +351,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) goto failStripeSize; } - /* With the primary chunk initialised we can add page memory to the freeLand - that describes the free address space in the primary chunk. */ - res = ArenaFreeLandInsert(arena, - PageIndexBase(arena->primary, - arena->primary->allocBase), - arena->primary->limit); + res = arenaFreeLandInit(arena); if (res != ResOK) - goto failPrimaryLand; - arena->hasFreeLand = TRUE; + goto failFreeLandInit; res = ControlInit(arena); if (res != ResOK) @@ -349,7 +370,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) failGlobalsCompleteCreate: ControlFinish(arena); failControlInit: -failPrimaryLand: + arenaFreeLandFinish(arena); +failFreeLandInit: failStripeSize: (*class->finish)(arena); failInit: @@ -390,6 +412,20 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size, arenaFreePage(PoolArena(pool), base, pool); } +static void arenaFreeLandFinish(Arena arena) +{ + AVERT(Arena, arena); + AVER(arena->hasFreeLand); + + /* The CBS block pool can't free its own memory via ArenaFree because + * that would use the free land. */ + MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, + UNUSED_POINTER, UNUSED_SIZE); + + arena->hasFreeLand = FALSE; + LandFinish(ArenaFreeLand(arena)); +} + void ArenaDestroy(Arena arena) { AVERT(Arena, arena); @@ -399,19 +435,11 @@ void ArenaDestroy(Arena arena) /* Empty the reservoir - see */ ReservoirSetLimit(ArenaReservoir(arena), 0); - arena->poolReady = FALSE; ControlFinish(arena); - /* We must tear down the freeLand before the chunks, because pages - containing CBS blocks might be allocated in those chunks. */ - AVER(arena->hasFreeLand); - arena->hasFreeLand = FALSE; - LandFinish(ArenaFreeLand(arena)); - - /* The CBS block pool can't free its own memory via ArenaFree because - that would use the freeLand. */ - MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, - UNUSED_POINTER, UNUSED_SIZE); + /* We must tear down the free land before the chunks, because pages + * containing CBS blocks might be allocated in those chunks. */ + arenaFreeLandFinish(arena); /* Call class-specific finishing. This will call ArenaFinish. */ (*arena->class->finish)(arena); @@ -427,6 +455,7 @@ Res ControlInit(Arena arena) Res res; AVERT(Arena, arena); + AVER(!arena->poolReady); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY); res = PoolInit(MVPool(&arena->controlPoolStruct), arena, @@ -444,6 +473,7 @@ Res ControlInit(Arena arena) void ControlFinish(Arena arena) { AVERT(Arena, arena); + AVER(arena->poolReady); arena->poolReady = FALSE; PoolFinish(MVPool(&arena->controlPoolStruct)); } @@ -454,7 +484,6 @@ void ControlFinish(Arena arena) Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth) { Res res; - Size reserved; if (!TESTT(Arena, arena)) return ResFAIL; @@ -476,20 +505,9 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth) return res; } - /* Note: this Describe clause calls a function */ - reserved = ArenaReserved(arena); res = WriteF(stream, depth + 2, - "reserved $W <-- " - "total size of address-space reserved\n", - (WriteFW)reserved, - NULL); - if (res != ResOK) - return res; - - res = WriteF(stream, depth + 2, - "committed $W <-- " - "total bytes currently stored (in RAM or swap)\n", - (WriteFW)arena->committed, + "reserved $W\n", (WriteFW)arena->reserved, + "committed $W\n", (WriteFW)arena->committed, "commitLimit $W\n", (WriteFW)arena->commitLimit, "spareCommitted $W\n", (WriteFW)arena->spareCommitted, "spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit, @@ -669,7 +687,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth) } -/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring */ +/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring, + * update the total reserved address space, and set the primary chunk + * if not already set. + */ void ArenaChunkInsert(Arena arena, Chunk chunk) { Bool inserted; @@ -687,6 +708,8 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) { arena->chunkTree = updatedTree; RingAppend(&arena->chunkRing, &chunk->arenaRing); + arena->reserved += ChunkReserved(chunk); + /* As part of the bootstrap, the first created chunk becomes the primary chunk. This step allows ArenaFreeLandInsert to allocate pages. */ if (arena->primary == NULL) @@ -694,6 +717,31 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) { } +/* ArenaChunkRemoved -- chunk was removed from the arena and is being + * finished, so update the total reserved address space, and unset the + * primary chunk if necessary. + */ + +void ArenaChunkRemoved(Arena arena, Chunk chunk) +{ + Size size; + + AVERT(Arena, arena); + AVERT(Chunk, chunk); + + size = ChunkReserved(chunk); + AVER(arena->reserved >= size); + arena->reserved -= size; + + if (chunk == arena->primary) { + /* The primary chunk must be the last chunk to be removed. */ + AVER(RingIsSingle(&arena->chunkRing)); + AVER(arena->reserved == 0); + arena->primary = NULL; + } +} + + /* arenaAllocPage -- allocate one page from the arena * * This is a primitive allocator used to allocate pages for the arena @@ -781,7 +829,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena) return res; MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaGrainSize(arena)); - RangeInit(pageRangeReturn, pageBase, AddrAdd(pageBase, ArenaGrainSize(arena))); + RangeInitSize(pageRangeReturn, pageBase, ArenaGrainSize(arena)); return ResOK; } @@ -801,15 +849,19 @@ static void arenaExcludePage(Arena arena, Range pageRange) } -/* arenaLandInsert -- add range to arena's land, maybe extending block pool +/* arenaFreeLandInsertExtend -- add range to arena's free land, maybe + * extending block pool * - * The arena's land can't get memory in the usual way because it is - * used in the basic allocator, so we allocate pages specially. + * The arena's free land can't get memory for its block pool in the + * usual way (via ArenaAlloc), because it is the mechanism behind + * ArenaAlloc! So we extend the block pool via a back door (see + * arenaExtendCBSBlockPool). * * Only fails if it can't get a page for the block pool. */ -static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) +static Res arenaFreeLandInsertExtend(Range rangeReturn, Arena arena, + Range range) { Res res; @@ -835,16 +887,18 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory +/* arenaFreeLandInsertSteal -- add range to arena's free land, maybe + * stealing memory * - * See arenaLandInsert. This function may only be applied to mapped - * pages and may steal them to store Land nodes if it's unable to - * allocate space for CBS blocks. + * See arenaFreeLandInsertExtend. This function may only be applied to + * mapped pages and may steal them to store Land nodes if it's unable + * to allocate space for CBS blocks. * * IMPORTANT: May update rangeIO. */ -static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) +static void arenaFreeLandInsertSteal(Range rangeReturn, Arena arena, + Range rangeIO) { Res res; @@ -852,7 +906,7 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) AVERT(Arena, arena); AVERT(Range, rangeIO); - res = arenaLandInsert(rangeReturn, arena, rangeIO); + res = arenaFreeLandInsertExtend(rangeReturn, arena, rangeIO); if (res != ResOK) { Addr pageBase; @@ -881,7 +935,8 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool +/* ArenaFreeLandInsert -- add range to arena's free land, maybe extending + * block pool * * The inserted block of address space may not abut any existing block. * This restriction ensures that we don't coalesce chunks and allocate @@ -896,7 +951,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) AVERT(Arena, arena); RangeInit(&range, base, limit); - res = arenaLandInsert(&oldRange, arena, &range); + res = arenaFreeLandInsertExtend(&oldRange, arena, &range); if (res != ResOK) return res; @@ -911,7 +966,8 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) } -/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool +/* ArenaFreeLandDelete -- remove range from arena's free land, maybe + * extending block pool * * This is called from ChunkFinish in order to remove address space from * the arena. @@ -1003,7 +1059,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, failMark: { - Res insertRes = arenaLandInsert(&oldRange, arena, &range); + Res insertRes = arenaFreeLandInsertExtend(&oldRange, arena, &range); AVER(insertRes == ResOK); /* We only just deleted it. */ /* If the insert does fail, we lose some address space permanently. */ } @@ -1215,7 +1271,7 @@ void ArenaFree(Addr base, Size size, Pool pool) RangeInit(&range, base, limit); - arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */ + arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */ (*arena->class->free)(RangeBase(&range), RangeSize(&range), pool); @@ -1231,7 +1287,7 @@ allDeposited: Size ArenaReserved(Arena arena) { AVERT(Arena, arena); - return (*arena->class->reserved)(arena); + return arena->reserved; } Size ArenaCommitted(Arena arena) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 857c4608e11..cd5c24fe46a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -81,8 +81,15 @@ static Bool ClientChunkCheck(ClientChunk clChunk) ATTRIBUTE_UNUSED static Bool ClientArenaCheck(ClientArena clientArena) { + Arena arena; + CHECKS(ClientArena, clientArena); - CHECKD(Arena, ClientArena2Arena(clientArena)); + arena = ClientArena2Arena(clientArena); + CHECKD(Arena, arena); + /* See */ + CHECKL(arena->committed <= arena->reserved); + CHECKL(arena->spareCommitted == 0); + return TRUE; } @@ -125,12 +132,13 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena, chunk = ClientChunk2Chunk(clChunk); res = ChunkInit(chunk, arena, alignedBase, - AddrAlignDown(limit, ArenaGrainSize(arena)), boot); + AddrAlignDown(limit, ArenaGrainSize(arena)), + AddrOffset(base, limit), boot); if (res != ResOK) goto failChunkInit; - ClientArena2Arena(clientArena)->committed += - AddrOffset(base, PageIndexBase(chunk, chunk->allocBase)); + arena->committed += ChunkPagesToSize(chunk, chunk->allocBase); + BootBlockFinish(boot); clChunk->sig = ClientChunkSig; @@ -176,8 +184,10 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot) static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS) { + Arena arena; Chunk chunk; ClientChunk clChunk; + Size size; AVERT(Tree, tree); AVER(closureP == UNUSED_POINTER); @@ -187,8 +197,15 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS) chunk = ChunkOfTree(tree); AVERT(Chunk, chunk); + arena = ChunkArena(chunk); + AVERT(Arena, arena); clChunk = Chunk2ClientChunk(chunk); AVERT(ClientChunk, clChunk); + AVER(chunk->pages == clChunk->freePages); + + size = ChunkPagesToSize(chunk, chunk->allocBase); + AVER(arena->committed >= size); + arena->committed -= size; clChunk->sig = SigInvalid; ChunkFinish(chunk); @@ -257,7 +274,7 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) AVER(base != (Addr)0); AVERT(ArenaGrainSize, grainSize); - if (size < grainSize * MPS_WORD_SHIFT) + if (size < grainSize * MPS_WORD_WIDTH) /* Not enough room for a full complement of zones. */ return ResMEMORY; @@ -324,6 +341,10 @@ static void ClientArenaFinish(Arena arena) clientArena->sig = SigInvalid; + /* Destroying the chunks should leave nothing behind. */ + AVER(arena->reserved == 0); + AVER(arena->committed == 0); + ArenaFinish(arena); /* */ } @@ -348,27 +369,6 @@ static Res ClientArenaExtend(Arena arena, Addr base, Size size) } -/* ClientArenaReserved -- return the amount of reserved address space */ - -static Size ClientArenaReserved(Arena arena) -{ - Size size; - Ring node, nextNode; - - AVERT(Arena, arena); - - size = 0; - /* .req.extend.slow */ - RING_FOR(node, &arena->chunkRing, nextNode) { - Chunk chunk = RING_ELT(Chunk, arenaRing, node); - AVERT(Chunk, chunk); - size += ChunkSize(chunk); - } - - return size; -} - - /* ClientArenaPagesMarkAllocated -- Mark the pages allocated */ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk, @@ -376,9 +376,12 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk, Pool pool) { Index i; + ClientChunk clChunk; AVERT(Arena, arena); AVERT(Chunk, chunk); + clChunk = Chunk2ClientChunk(chunk); + AVERT(ClientChunk, clChunk); AVER(chunk->allocBase <= baseIndex); AVER(pages > 0); AVER(baseIndex + pages <= chunk->pages); @@ -387,15 +390,17 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk, for (i = 0; i < pages; ++i) PageAlloc(chunk, baseIndex + i, pool); - Chunk2ClientChunk(chunk)->freePages -= pages; + arena->committed += ChunkPagesToSize(chunk, pages); + AVER(clChunk->freePages >= pages); + clChunk->freePages -= pages; return ResOK; } -/* ClientFree - free a region in the arena */ +/* ClientArenaFree - free a region in the arena */ -static void ClientFree(Addr base, Size size, Pool pool) +static void ClientArenaFree(Addr base, Size size, Pool pool) { Arena arena; Chunk chunk = NULL; /* suppress "may be used uninitialized" */ @@ -436,6 +441,8 @@ static void ClientFree(Addr base, Size size, Pool pool) AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex)); BTResRange(chunk->allocTable, baseIndex, limitIndex); + AVER(arena->committed >= size); + arena->committed -= size; clChunk->freePages += pages; } @@ -451,10 +458,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->varargs = ClientArenaVarargs; this->init = ClientArenaInit; this->finish = ClientArenaFinish; - this->reserved = ClientArenaReserved; this->extend = ClientArenaExtend; this->pagesMarkAllocated = ClientArenaPagesMarkAllocated; - this->free = ClientFree; + this->free = ClientArenaFree; this->chunkInit = ClientChunkInit; this->chunkFinish = ClientChunkFinish; AVERT(ArenaClass, this); diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 54b7ef7ba25..ba34a7c70ef 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -323,7 +323,8 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size) /* Copy VM descriptor into its place in the chunk. */ VMCopy(VMChunkVM(vmChunk), vm); - res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, boot); + res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, + VMReserved(VMChunkVM(vmChunk)), boot); if (res != ResOK) goto failChunkInit; @@ -560,6 +561,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) res = ArenaInit(arena, class, grainSize, args); if (res != ResOK) goto failArenaInit; + arena->reserved = VMReserved(vm); arena->committed = VMMapped(vm); /* Copy VM descriptor into its place in the arena. */ @@ -640,6 +642,7 @@ static void VMArenaFinish(Arena arena) RingFinish(&vmArena->spareRing); /* Destroying the chunks should leave only the arena's own VM. */ + AVER(arena->reserved == VMReserved(VMArenaVM(vmArena))); AVER(arena->committed == VMMapped(VMArenaVM(vmArena))); vmArena->sig = SigInvalid; @@ -654,25 +657,6 @@ static void VMArenaFinish(Arena arena) } -/* VMArenaReserved -- return the amount of reserved address space - * - * Add up the reserved space from all the chunks. - */ - -static Size VMArenaReserved(Arena arena) -{ - Size reserved; - Ring node, next; - - reserved = 0; - RING_FOR(node, &arena->chunkRing, next) { - VMChunk vmChunk = Chunk2VMChunk(RING_ELT(Chunk, arenaRing, node)); - reserved += VMReserved(VMChunkVM(vmChunk)); - } - return reserved; -} - - /* vmArenaChunkSize -- choose chunk size for arena extension * * .vmchunk.overhead: This code still lacks a proper estimate of @@ -723,7 +707,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) chunkSize = vmArenaChunkSize(vmArena, size); EVENT3(vmArenaExtendStart, size, chunkSize, - VMArenaReserved(VMArena2Arena(vmArena))); + ArenaReserved(VMArena2Arena(vmArena))); /* .chunk-create.fail: If we fail, try again with a smaller size */ { @@ -737,17 +721,17 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) if (chunkSize < chunkMin) chunkSize = chunkMin; + res = ResRESOURCE; for(;; chunkSize = chunkHalf) { chunkHalf = chunkSize / 2; sliceSize = chunkHalf / fidelity; AVER(sliceSize > 0); /* remove slices, down to chunkHalf but no further */ - res = ResRESOURCE; for(; chunkSize > chunkHalf; chunkSize -= sliceSize) { if(chunkSize < chunkMin) { EVENT2(vmArenaExtendFail, chunkMin, - VMArenaReserved(VMArena2Arena(vmArena))); + ArenaReserved(VMArena2Arena(vmArena))); return res; } res = VMChunkCreate(&newChunk, vmArena, chunkSize); @@ -758,7 +742,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) } vmArenaGrow_Done: - EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena))); + EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena))); vmArena->extended(VMArena2Arena(vmArena), newChunk->base, AddrOffset(newChunk->base, newChunk->limit)); @@ -806,16 +790,23 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI) Size before = VMMapped(VMChunkVM(vmChunk)); Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk)); Res res = SparseArrayMap(&vmChunk->pages, basePI, limitPI); - arena->committed += VMMapped(VMChunkVM(vmChunk)) - before; + Size after = VMMapped(VMChunkVM(vmChunk)); + AVER(before <= after); + arena->committed += after - before; return res; } static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI) { + Size size, after; Size before = VMMapped(VMChunkVM(vmChunk)); Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk)); SparseArrayUnmap(&vmChunk->pages, basePI, limitPI); - arena->committed += VMMapped(VMChunkVM(vmChunk)) - before; + after = VMMapped(VMChunkVM(vmChunk)); + AVER(after <= before); + size = before - after; + AVER(arena->committed >= size); + arena->committed -= size; } @@ -1144,7 +1135,7 @@ static void VMCompact(Arena arena, Trace trace) AVERT(VMArena, vmArena); AVERT(Trace, trace); - vmem1 = VMArenaReserved(arena); + vmem1 = ArenaReserved(arena); /* Destroy chunks that are completely free, but not the primary * chunk. See @@ -1154,7 +1145,7 @@ static void VMCompact(Arena arena, Trace trace) { Size vmem0 = trace->preTraceArenaReserved; - Size vmem2 = VMArenaReserved(arena); + Size vmem2 = ArenaReserved(arena); /* VMCompact event: emit for all client-requested collections, */ /* plus any others where chunks were gained or lost during the */ @@ -1204,7 +1195,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->varargs = VMArenaVarargs; this->init = VMArenaInit; this->finish = VMArenaFinish; - this->reserved = VMArenaReserved; this->purgeSpare = VMPurgeSpare; this->grow = VMArenaGrow; this->free = VMFree; diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 4c30ed3d8a7..edef611c217 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -19,10 +19,8 @@ * * TRANSGRESSIONS * - * .trans.mod: There are several instances where pool structures are - * directly accessed by this module because does not provide - * an adequate (or adequately documented) interface. They bear this - * tag. + * .trans.mod: pool->bufferSerial is directly accessed by this module + * because does not provide an interface. */ #include "mpm.h" @@ -221,7 +219,7 @@ static Res BufferInit(Buffer buffer, BufferClass class, } buffer->fillSize = 0.0; buffer->emptySize = 0.0; - buffer->alignment = pool->alignment; /* .trans.mod */ + buffer->alignment = PoolAlignment(pool); buffer->base = (Addr)0; buffer->initAtFlip = (Addr)0; /* In the next three assignments we really mean zero, not NULL, because diff --git a/mps/code/cbs.c b/mps/code/cbs.c index d98a92cb8c4..0b30b68acb1 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1,7 +1,7 @@ /* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of coalescing block * structures. @@ -1069,7 +1069,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, AVERT(CBS, cbs); AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass)); /* AVERT(ZoneSet, zoneSet); */ - AVER(BoolCheck(high)); + AVERT(Bool, high); landFind = high ? cbsFindLast : cbsFindFirst; splayFind = high ? SplayFindLast : SplayFindFirst; @@ -1208,7 +1208,7 @@ DEFINE_LAND_CLASS(CBSZonedLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 2eb68381a3f..c82caa4576e 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -36,7 +36,6 @@ # NOISY if defined and non-empty, causes commands to be emitted # MPMPF platform-dependent C sources for the "mpm" part # MPMS assembler sources for the "mpm" part (.s files) -# MPMPS pre-processor assembler sources for the "mpm" part (.S files) # # %%PART: When adding a new part, add a new parameter above for the # files included in the part. @@ -309,12 +308,12 @@ all: $(ALL_TARGETS) # testci = continuous integration tests, must be known good # testall = all test cases, for ensuring quality of a release # testansi = tests that run on the generic ("ANSI") platform -# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE +# testpollnone = tests that run on the generic platform with CONFIG_POLL_NONE -TEST_SUITES=testrun testci testall testansi testpoll +TEST_SUITES=testrun testci testall testansi testpollnone $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) - ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" + ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)" # These convenience targets allow one to type "make foo" to build target diff --git a/mps/code/commpost.nmk b/mps/code/comm.nmk similarity index 64% rename from mps/code/commpost.nmk rename to mps/code/comm.nmk index 1d2783a7bbb..a59132ff354 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/comm.nmk @@ -1,11 +1,330 @@ -# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*- +# -*- makefile -*- +# +# comm.nmk: COMMON NMAKE FRAGMENT # # $Id$ # Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # -# Second common makefile fragment for w3*mv.nmk. See commpre.nmk +# This makefile fragment is included in more specific makefiles for +# platforms which use nmake. +# +# %%PART: When adding a new part, add a new parameter for the files included +# in the part +# Parameters: +# PFM platform code, e.g. "w3i3mv" +# PFMDEFS /D options to define platforms preprocessor symbols +# to the compiler. Avoid using this if possible, as it +# prevents the MPS being built with a simple command like +# "cl mps.c". +# MPMCOMMON list of sources which make up the "mpm" part for all +# platforms. Each source is stripped of its .c extension +# and surrounded with [brackets]. +# MPMPF as above for the current platform. +# PLINTH as above for the "plinth" part +# AMC as above for the "amc" part +# AMS as above for the "ams" part +# LO as above for the "lo" part +# POOLN as above for the "pooln" part +# SNC as above for the "snc" part +# POOLS as above for all pools included in the target +# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS +# DW as above for the "dw" part +# FMTTEST as above for the "fmttest" part +# FMTSCHEME as above for the "fmtscheme" part +# TESTLIB as above for the "testlib" part +# TESTTHR as above for the "testthr" part +# NOISY if defined, causes command to be emitted +# +# +# EDITING +# +# To add new targets. varieties, and parts: +# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile +# and follow the instructions. +# + + +# TARGETS +# +# +# %%TARGET: When adding a new target, add it to one of the variables +# in this section. Library components go in LIB_TARGETS. + +LIB_TARGETS=mps.lib + +# Test cases go in TEST_TARGETS. + +TEST_TARGETS=\ + abqtest.exe \ + airtest.exe \ + amcss.exe \ + amcsshe.exe \ + amcssth.exe \ + amsss.exe \ + amssshe.exe \ + apss.exe \ + arenacv.exe \ + awlut.exe \ + awluthe.exe \ + awlutth.exe \ + btcv.exe \ + bttest.exe \ + djbench.exe \ + exposet0.exe \ + expt825.exe \ + finalcv.exe \ + finaltest.exe \ + fotest.exe \ + gcbench.exe \ + landtest.exe \ + locbwcss.exe \ + lockcov.exe \ + lockut.exe \ + locusss.exe \ + locv.exe \ + messtest.exe \ + mpmss.exe \ + mpsicv.exe \ + mv2test.exe \ + nailboardtest.exe \ + poolncv.exe \ + qs.exe \ + sacss.exe \ + segsmss.exe \ + steptest.exe \ + teletest.exe \ + walkt0.exe \ + zcoll.exe \ + zmess.exe + +# Stand-alone programs go in EXTRA_TARGETS if they should always be +# built, or in OPTIONAL_TARGETS if they should only be built if + +EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe +OPTIONAL_TARGETS=mpseventsql.exe + +# This target records programs that we were once able to build but +# can't at the moment: +# +# replay -- depends on the EPVM pool. + +UNBUILDABLE_TARGETS=replay.exe + +ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) + + +# PARAMETERS +# +# +# %%PART: When adding a new part, add the sources for the new part here. + +MPMCOMMON=\ + [abq] \ + [arena] \ + [arenacl] \ + [arenavm] \ + [arg] \ + [boot] \ + [bt] \ + [buffer] \ + [cbs] \ + [dbgpool] \ + [dbgpooli] \ + [event] \ + [failover] \ + [format] \ + [freelist] \ + [global] \ + [land] \ + [ld] \ + [locus] \ + [message] \ + [meter] \ + [mpm] \ + [mpsi] \ + [nailboard] \ + [pool] \ + [poolabs] \ + [poolmfs] \ + [poolmrg] \ + [poolmv2] \ + [poolmv] \ + [protocol] \ + [range] \ + [ref] \ + [reserv] \ + [ring] \ + [root] \ + [sa] \ + [sac] \ + [seg] \ + [shield] \ + [splay] \ + [ss] \ + [table] \ + [trace] \ + [traceanc] \ + [tract] \ + [tree] \ + [version] \ + [vm] \ + [walk] +PLINTH = [mpsliban] [mpsioan] +AMC = [poolamc] +AMS = [poolams] [poolamsi] +AWL = [poolawl] +LO = [poollo] +MVFF = [poolmvff] +POOLN = [pooln] +SNC = [poolsnc] +FMTDY = [fmtdy] [fmtno] +FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] +FMTSCHEME = [fmtscheme] +TESTLIB = [testlib] [getoptl] +TESTTHR = [testthrw3] +POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) +MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) + + +# CHECK PARAMETERS +# +# +# %%PART: When adding a new part, add checks for the parameter with the +# sources for the new part. + +!IFNDEF PFM +!ERROR comm.nmk: PFM not defined +!ENDIF +!IFNDEF MPM +!ERROR comm.nmk: MPM not defined +!ENDIF +!IFNDEF MPMCOMMON +!ERROR comm.nmk: MPMCOMMON not defined +!ENDIF +!IFNDEF MPMPF +!ERROR comm.nmk: MPMPF not defined +!ENDIF +!IFNDEF PLINTH +!ERROR comm.nmk: PLINTH not defined +!ENDIF +!IFNDEF LO +!ERROR comm.nmk: LO not defined +!ENDIF +!IFNDEF AMC +!ERROR comm.nmk: AMC not defined +!ENDIF +!IFNDEF AMS +!ERROR comm.nmk: AMS not defined +!ENDIF +!IFNDEF POOLN +!ERROR comm.nmk: POOLN not defined +!ENDIF +!IFNDEF SNC +!ERROR comm.nmk: SNC not defined +!ENDIF +!IFNDEF FMTDY +!ERROR comm.nmk: FMTDY not defined +!ENDIF +!IFNDEF FMTTEST +!ERROR comm.nmk: FMTTEST not defined +!ENDIF +!IFNDEF FMTSCHEME +!ERROR comm.nmk: FMTSCHEME not defined +!ENDIF +!IFNDEF TESTLIB +!ERROR comm.nmk: TESTLIB not defined +!ENDIF +!IFNDEF TESTTHR +!ERROR comm.nmk: TESTTHR not defined +!ENDIF + + +# DECLARATIONS + + +!IFDEF NOISY +ECHO = rem +!ELSE +.SILENT: +ECHO = echo +!ENDIF + + +# C FLAGS + +CFLAGSTARGETPRE = +CFLAGSTARGETPOST = +CRTFLAGSHOT = +CRTFLAGSCOOL = +LINKFLAGSHOT = +LINKFLAGSCOOL = + +CFLAGSSQLPRE = /nologo $(PFMDEFS) +CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) +CFLAGSSQLPOST = +CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) + +# Flags for use in the variety combinations +CFLAGSHOT = /O2 +# (above /O2 (maximise speed) used to be set to /Ox +# (maximise optimisations) in for tool versions before VS 9) +# We used to have /GZ here (stack probe). +# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 +# It is ignored on earlier versions of the cl tool. +# /GZ here generates a dependency on the C library and when we are +# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: +# unresolved external symbol __chkesp). See +# http://support.microsoft.com/kb/q191669/ +CFLAGSCOOL = +CFLAGSINTERNAL = /Zi +CFLAGSEXTERNAL = + +# The combinations of variety +# %%VARIETY: When adding a new variety, define a macro containing the set +# of flags for the new variety. +CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) +CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) +CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) + +# Microsoft documentation is not very clear on the point of using both +# optimization and debug information + +# LINKER FLAGS +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LINKER = link +LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE +LINKFLAGSINTERNAL = /DEBUG +# ( Internal flags used to be set to /DEBUG:full ) +LINKFLAGSEXTERNAL = /RELEASE + +LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) +LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) +LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) + +#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv + +# Library manager +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LIBMAN = lib # can't call this LIB - it screws the environment +LIBFLAGSCOMMON = + +LIBFLAGSRASH = +LIBFLAGSHOT = +LIBFLAGSCOOL = + +# Browser database manager [not used at present] +#BSC = bscmake +#BSCFLAGS = /nologo /n + + +# == Common definitions == +# %%PART: When adding a new part, add it here, unless it's platform-specific +# [It is not possible use a macro, like $(PFM), in a substitution, +# hence all parts end up being platform-specific.] # == Pseudo-targets == @@ -56,10 +375,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun testci testall testansi testpoll +# testrun testci testall testansi testpollnone # Runs automated test cases. -testrun testci testall testansi testpoll: $(TEST_TARGETS) +testrun testci testall testansi testpollnone: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE @@ -382,18 +701,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: -# +# # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. -# +# # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. -# +# # 3. Redistributions in any form must be accompanied by information on how # to obtain complete source code for this software and any accompanying # software that uses this software. The source code must either be @@ -404,7 +723,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # include source code for modules or files that typically accompany the # major components of the operating system on which the executable file # runs. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk deleted file mode 100644 index b622ff25741..00000000000 --- a/mps/code/commpre.nmk +++ /dev/null @@ -1,369 +0,0 @@ -# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1 -# -# $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. -# -# DESCRIPTION -# -# .description: This makefile fragment is included in more specific -# makefiles for platforms which use the "mv" builder. This is -# the first of two common makefile fragements (the other is commpost.nmk). -# Alas, due to shortcomings in nmake, it is not possible to use only one -# common fragment. -# -# %%PART: When adding a new part, add a new parameter for the files included -# in the part -# Parameters: -# PFM platform code, e.g. "w3i3mv" -# PFMDEFS /D options to define platforms preprocessor symbols -# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC" -# MPMCOMMON list of sources which make up the "mpm" part for all -# platforms. Each source is stripped of its .c extension -# and surrounded with [brackets]. -# MPM as above, plus sources for the "mpm" part for the current -# platform. -# PLINTH as above for the "plinth" part -# AMC as above for the "amc" part -# AMS as above for the "ams" part -# LO as above for the "lo" part -# POOLN as above for the "pooln" part -# SNC as above for the "snc" part -# DW as above for the "dw" part -# FMTTEST as above for the "fmttest" part -# FMTSCHEME as above for the "fmtscheme" part -# TESTLIB as above for the "testlib" part -# TESTTHR as above for the "testthr" part -# NOISY if defined, causes command to be emitted -# -# -# EDITING -# -# To add new targets. varieties, and parts: -# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile -# and follow the instructions. -# - - -# TARGETS -# -# -# %%TARGET: When adding a new target, add it to one of the variables -# in this section. Library components go in LIB_TARGETS. - -LIB_TARGETS=mps.lib - -# Test cases go in TEST_TARGETS. - -TEST_TARGETS=\ - abqtest.exe \ - airtest.exe \ - amcss.exe \ - amcsshe.exe \ - amcssth.exe \ - amsss.exe \ - amssshe.exe \ - apss.exe \ - arenacv.exe \ - awlut.exe \ - awluthe.exe \ - awlutth.exe \ - btcv.exe \ - bttest.exe \ - djbench.exe \ - exposet0.exe \ - expt825.exe \ - finalcv.exe \ - finaltest.exe \ - fotest.exe \ - gcbench.exe \ - landtest.exe \ - locbwcss.exe \ - lockcov.exe \ - lockut.exe \ - locusss.exe \ - locv.exe \ - messtest.exe \ - mpmss.exe \ - mpsicv.exe \ - mv2test.exe \ - nailboardtest.exe \ - poolncv.exe \ - qs.exe \ - sacss.exe \ - segsmss.exe \ - steptest.exe \ - teletest.exe \ - walkt0.exe \ - zcoll.exe \ - zmess.exe - -# Stand-alone programs go in EXTRA_TARGETS if they should always be -# built, or in OPTIONAL_TARGETS if they should only be built if - -EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe -OPTIONAL_TARGETS=mpseventsql.exe - -# This target records programs that we were once able to build but -# can't at the moment: -# -# replay -- depends on the EPVM pool. - -UNBUILDABLE_TARGETS=replay.exe - -ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) - - -# PARAMETERS -# -# -# %%PART: When adding a new part, add the sources for the new part here. - -MPMCOMMON=\ - [abq] \ - [arena] \ - [arenacl] \ - [arenavm] \ - [arg] \ - [boot] \ - [bt] \ - [buffer] \ - [cbs] \ - [dbgpool] \ - [dbgpooli] \ - [event] \ - [failover] \ - [format] \ - [freelist] \ - [global] \ - [land] \ - [ld] \ - [locus] \ - [message] \ - [meter] \ - [mpm] \ - [mpsi] \ - [nailboard] \ - [pool] \ - [poolabs] \ - [poolmfs] \ - [poolmrg] \ - [poolmv2] \ - [poolmv] \ - [protocol] \ - [range] \ - [ref] \ - [reserv] \ - [ring] \ - [root] \ - [sa] \ - [sac] \ - [seg] \ - [shield] \ - [splay] \ - [ss] \ - [table] \ - [trace] \ - [traceanc] \ - [tract] \ - [tree] \ - [version] \ - [vm] \ - [walk] -PLINTH = [mpsliban] [mpsioan] -AMC = [poolamc] -AMS = [poolams] [poolamsi] -AWL = [poolawl] -LO = [poollo] -MVFF = [poolmvff] -POOLN = [pooln] -SNC = [poolsnc] -FMTDY = [fmtdy] [fmtno] -FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] -FMTSCHEME = [fmtscheme] -TESTLIB = [testlib] [getoptl] -TESTTHR = [testthrw3] -POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) -MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) - - -# CHECK PARAMETERS -# -# -# %%PART: When adding a new part, add checks for the parameter with the -# sources for the new part. - -!IFNDEF PFM -!ERROR commpre.nmk: PFM not defined -!ENDIF -!IFNDEF PFMDEFS -!ERROR commpre.nmk: PFMDEFS not defined -!ENDIF -!IFNDEF MPM -!ERROR commpre.nmk: MPM not defined -!ENDIF -!IFNDEF MPMCOMMON -!ERROR commpre.nmk: MPMCOMMON not defined -!ENDIF -!IFNDEF MPMPF -!ERROR commpre.nmk: MPMPF not defined -!ENDIF -!IFNDEF PLINTH -!ERROR commpre.nmk: PLINTH not defined -!ENDIF -!IFNDEF LO -!ERROR commpre.nmk: LO not defined -!ENDIF -!IFNDEF AMC -!ERROR commpre.nmk: AMC not defined -!ENDIF -!IFNDEF AMS -!ERROR commpre.nmk: AMS not defined -!ENDIF -!IFNDEF POOLN -!ERROR commpre.nmk: POOLN not defined -!ENDIF -!IFNDEF SNC -!ERROR commpre.nmk: SNC not defined -!ENDIF -!IFNDEF FMTDY -!ERROR commpre.nmk: FMTDY not defined -!ENDIF -!IFNDEF FMTTEST -!ERROR commpre.nmk: FMTTEST not defined -!ENDIF -!IFNDEF FMTSCHEME -!ERROR commpre.nmk: FMTSCHEME not defined -!ENDIF -!IFNDEF TESTLIB -!ERROR commpre.nmk: TESTLIB not defined -!ENDIF -!IFNDEF TESTTHR -!ERROR commpre.nmk: TESTTHR not defined -!ENDIF - - -# DECLARATIONS - - -!IFDEF NOISY -ECHO = rem -!ELSE -.SILENT: -ECHO = echo -!ENDIF - - -# C FLAGS - -CFLAGSTARGETPRE = -CFLAGSTARGETPOST = -CRTFLAGSHOT = -CRTFLAGSCOOL = -LINKFLAGSHOT = -LINKFLAGSCOOL = - -CFLAGSSQLPRE = /nologo $(PFMDEFS) -CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) -CFLAGSSQLPOST = -CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) - -# Flags for use in the variety combinations -CFLAGSHOT = /O2 -# (above /O2 (maximise speed) used to be set to /Ox -# (maximise optimisations) in for tool versions before VS 9) -# We used to have /GZ here (stack probe). -# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 -# It is ignored on earlier versions of the cl tool. -# /GZ here generates a dependency on the C library and when we are -# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: -# unresolved external symbol __chkesp). See -# http://support.microsoft.com/kb/q191669/ -CFLAGSCOOL = -CFLAGSINTERNAL = /Zi -CFLAGSEXTERNAL = - -# The combinations of variety -# %%VARIETY: When adding a new variety, define a macro containing the set -# of flags for the new variety. -CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) -CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) -CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) - -# Microsoft documentation is not very clear on the point of using both -# optimization and debug information - -# LINKER FLAGS -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LINKER = link -LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE -LINKFLAGSINTERNAL = /DEBUG -# ( Internal flags used to be set to /DEBUG:full ) -LINKFLAGSEXTERNAL = /RELEASE - -LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) -LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) -LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) - -#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv - -# Library manager -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LIBMAN = lib # can't call this LIB - it screws the environment -LIBFLAGSCOMMON = - -LIBFLAGSRASH = -LIBFLAGSHOT = -LIBFLAGSCOOL = - -# Browser database manager [not used at present] -#BSC = bscmake -#BSCFLAGS = /nologo /n - - -# == Common definitions == -# %%PART: When adding a new part, add it here, unless it's platform-specific -# [It is not possible use a macro, like $(PFM), in a substitution, -# hence all parts end up being platform-specific.] - - -# C. COPYRIGHT AND LICENSE -# -# Copyright (C) 2001-2014 Ravenbrook Limited . -# All rights reserved. This is an open source license. Contact -# Ravenbrook for commercial licensing options. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Redistributions in any form must be accompanied by information on how -# to obtain complete source code for this software and any accompanying -# software that uses this software. The source code must either be -# included in the distribution or be available for no more than the cost -# of distribution plus a nominal fee, and must be freely redistributable -# under reasonable conditions. For an executable file, complete source -# code means the source code for all modules it contains. It does not -# include source code for modules or files that typically accompany the -# major components of the operating system on which the executable file -# runs. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mps/code/djbench.c b/mps/code/djbench.c index 33cf1d4bdb9..fbc6dcabc1c 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -13,10 +13,15 @@ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, stderr */ #include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */ #include /* CLOCKS_PER_SEC, clock */ diff --git a/mps/code/freelist.c b/mps/code/freelist.c index a9e482550f3..6eddc3dff83 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -1,7 +1,7 @@ /* freelist.c: FREE LIST ALLOCATOR IMPLEMENTATION * * $Id$ - * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2015 Ravenbrook Limited. See end of file for license. * * .sources: . */ @@ -18,11 +18,11 @@ SRCID(freelist, "$Id$"); typedef union FreelistBlockUnion { - struct { + struct FreelistBlockSmall { FreelistBlock next; /* tagged with low bit 1 */ /* limit is (char *)this + freelistAlignment(fl) */ } small; - struct { + struct FreelistBlockLarge { FreelistBlock next; /* not tagged (low bit 0) */ Addr limit; } large; @@ -101,6 +101,9 @@ static Bool FreelistBlockCheck(FreelistBlock block) CHECKL(freelistBlockNext(block) == freelistEND || block < freelistBlockNext(block)); CHECKL(freelistBlockIsSmall(block) || (Addr)block < block->large.limit); + /* Would like to CHECKL(!freelistBlockIsSmall(block) || + * freelistBlockSize(fl, block) == freelistAlignment(fl)) but we + * don't have 'fl' here. This is checked in freelistBlockSetLimit. */ return TRUE; } @@ -139,6 +142,7 @@ static void freelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit) } else { AVER(size >= sizeof(block->small)); block->small.next = freelistTagSet(block->small.next); + AVER(freelistBlockSize(fl, block) == freelistAlignment(fl)); } AVER(freelistBlockLimit(fl, block) == limit); } @@ -170,6 +174,9 @@ Bool FreelistCheck(Freelist fl) CHECKS(Freelist, fl); land = FreelistLand(fl); CHECKD(Land, land); + CHECKL(AlignCheck(FreelistMinimumAlignment)); + CHECKL(sizeof(struct FreelistBlockSmall) < sizeof(struct FreelistBlockLarge)); + CHECKL(sizeof(struct FreelistBlockSmall) <= freelistAlignment(fl)); /* See */ CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment)); CHECKL((fl->list == freelistEND) == (fl->listSize == 0)); @@ -236,12 +243,14 @@ static Size freelistSize(Land land) * Otherwise, if next is freelistEND, make prev the last block in the list. * Otherwise, make next follow prev in the list. * Update the count of blocks by 'delta'. - + * * It is tempting to try to simplify this code by putting a * FreelistBlockUnion into the FreelistStruct and so avoiding the * special case on prev. But the problem with that idea is that we * can't guarantee that such a sentinel would respect the isolated - * range invariant, and so it would still have to be special-cases. + * range invariant (it would have to be at a lower address than the + * first block in the free list, which the MPS has no mechanism to + * enforce), and so it would still have to be special-cased. */ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, @@ -781,6 +790,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth, "Freelist $P {\n", (WriteFP)fl, " listSize = $U\n", (WriteFU)fl->listSize, + " size = $U\n", (WriteFU)fl->size, NULL); b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2); @@ -815,7 +825,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013-2014 Ravenbrook Limited . + * Copyright (C) 2013-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 2ae97104930..6d7f3339667 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -7,13 +7,18 @@ */ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" #include "mpm.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, printf, putchars, sscanf, stderr, stdout */ #include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ #include /* clock, CLOCKS_PER_SEC */ diff --git a/mps/code/global.c b/mps/code/global.c index d60e925fdb3..164798d9695 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -657,7 +657,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context) res = PoolAccess(SegPool(seg), seg, addr, mode, context); AVER(res == ResOK); /* Mutator can't continue unless this succeeds */ } else { - /* Protection was already cleared: nothing to do now. */ + /* Protection was already cleared, for example by another thread + or a fault in a nested exception handler: nothing to do now. */ } EVENT4(ArenaAccess, arena, count, addr, mode); ArenaLeave(arena); diff --git a/mps/code/land.c b/mps/code/land.c index 7dbc7845b5b..18d446288f8 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -1,7 +1,7 @@ /* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION * * $Id$ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license. * * .design: */ @@ -282,7 +282,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, @@ -306,7 +306,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, @@ -330,7 +330,7 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, @@ -470,7 +470,7 @@ Bool LandClassCheck(LandClass class) static Res landTrivInit(Land land, ArgList args) { AVERT(Land, land); - AVER(ArgListCheck(args)); + AVERT(ArgList, args); UNUSED(args); return ResOK; } @@ -555,7 +555,7 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size AVER(oldRangeReturn != NULL); AVERT(Land, land); UNUSED(size); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); return ResUNIMPL; } @@ -567,7 +567,7 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang AVERT(Land, land); UNUSED(size); UNUSED(zoneSet); - AVER(BoolCheck(high)); + AVERT(Bool, high); return ResUNIMPL; } @@ -606,7 +606,7 @@ DEFINE_CLASS(LandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/ld.c b/mps/code/ld.c index 3c55c27fccd..c9e79f8a762 100644 --- a/mps/code/ld.c +++ b/mps/code/ld.c @@ -1,7 +1,7 @@ /* ld.c: LOCATION DEPENDENCY IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .def: A location dependency records the fact that the bit-patterns * of some references will be used directly (most likely for @@ -92,6 +92,15 @@ void LDReset(mps_ld_t ld, Arena arena) * occured since the epoch recorded in the dependency. If the location * were used first only the new location of the reference would end up * in the set. + * + * .add.no-arena-check: Add does not check that the address belongs to + * the arena because this would require taking the arena lock. We + * would rather that this function be lock-free even if some errors + * are not detected. + * + * .add.no-align-check: Add does not check that the address is + * aligned, for the same reason as .add.check: it can't find out which + * pool the address belongs to without taking the lock. */ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) { @@ -153,6 +162,10 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena) * .stale.conservative: In fact we just ignore the address and test if * any dependency is stale. This is conservatively correct (no false * negatives) but provides a hook for future improvement. + * + * .stale.no-arena-check: See .add.no-arena-check. + * + * .stale.no-align-check: See .add.no-align-check. */ Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr) { @@ -225,7 +238,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.c b/mps/code/mpm.c index d3c32a66daf..aba1ac2f5cb 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -1,7 +1,7 @@ /* mpm.c: GENERAL MPM SUPPORT * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Miscellaneous support for the implementation of the MPM * and pool classes. @@ -137,6 +137,16 @@ Bool AlignCheck(Align align) } +/* AccessSetCheck -- check that an access set is valid */ + +Bool AccessSetCheck(AccessSet mode) +{ + CHECKL(mode < ((ULongest)1 << AccessLIMIT)); + UNUSED(mode); /* see .check.unused */ + return TRUE; +} + + #endif /* defined(AVER_AND_CHECK) */ @@ -638,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index a3c5a8bbf6c..af2cde97ff1 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1,7 +1,7 @@ /* mpm.h: MEMORY POOL MANAGER DEFINITIONS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .trans.bufferinit: The Buffer data structure has an Init field and @@ -46,6 +46,7 @@ extern Bool FunCheck(Fun f); extern Bool ShiftCheck(Shift shift); extern Bool AttrCheck(Attr attr); extern Bool RootVarCheck(RootVar rootVar); +extern Bool AccessSetCheck(AccessSet mode); /* Address/Size Interface -- see */ @@ -562,13 +563,14 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier); extern void ArenaClamp(Globals globals); extern void ArenaRelease(Globals globals); extern void ArenaPark(Globals globals); -extern void ArenaExposeRemember(Globals globals, int remember); +extern void ArenaExposeRemember(Globals globals, Bool remember); extern void ArenaRestoreProtection(Globals globals); extern Res ArenaStartCollect(Globals globals, int why); extern Res ArenaCollect(Globals globals, int why); extern Bool ArenaHasAddr(Arena arena, Addr addr); extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr); extern void ArenaChunkInsert(Arena arena, Chunk chunk); +extern void ArenaChunkRemoved(Arena arena, Chunk chunk); extern void ArenaSetEmergency(Arena arena, Bool emergency); extern Bool ArenaEmergency(Arena arean); @@ -1052,7 +1054,7 @@ extern LandClass LandClassGet(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 01dbf16b732..a798cc71fc4 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -526,7 +526,6 @@ typedef struct mps_arena_class_s { ArenaVarargsMethod varargs; ArenaInitMethod init; ArenaFinishMethod finish; - ArenaReservedMethod reserved; ArenaPurgeSpareMethod purgeSpare; ArenaExtendMethod extend; ArenaGrowMethod grow; @@ -714,7 +713,8 @@ typedef struct mps_arena_s { ReservoirStruct reservoirStruct; /* */ - Size committed; /* amount of committed RAM */ + Size reserved; /* total reserved address space */ + Size committed; /* total committed memory */ Size commitLimit; /* client-configurable commit limit */ Size spareCommitted; /* Amount of memory in hysteresis fund */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index a69b2b79ebe..a6030e4c1e5 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -120,7 +120,6 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs); typedef Res (*ArenaInitMethod)(Arena *arenaReturn, ArenaClass class, ArgList args); typedef void (*ArenaFinishMethod)(Arena arena); -typedef Size (*ArenaReservedMethod)(Arena arena); typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size); typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size); typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size); diff --git a/mps/code/mps.c b/mps/code/mps.c index d31a1f60a0a..95919d9680c 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -214,7 +214,6 @@ #include "mpsiw3.c" /* Windows interface layer extras */ /* Windows on 64-bit Intel with Microsoft Visual Studio */ -/* ssw3i6.asm is also required, but can't be included here */ #elif defined(MPS_PF_W3I6MV) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index c83a1026d6e..30aad557d3b 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -43,16 +43,16 @@ name = testall; productName = testrun; }; - 2215A9C1192A47D500E9E2CE /* testpoll */ = { + 2215A9C1192A47D500E9E2CE /* testpollnone */ = { isa = PBXAggregateTarget; - buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */; + buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */; buildPhases = ( 2215A9C4192A47D500E9E2CE /* ShellScript */, ); dependencies = ( 2215A9C2192A47D500E9E2CE /* PBXTargetDependency */, ); - name = testpoll; + name = testpollnone; productName = testrun; }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { @@ -285,7 +285,6 @@ 3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; - 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; }; @@ -327,7 +326,6 @@ 31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; }; 6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; }; 6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; }; 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; @@ -1635,8 +1633,6 @@ 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; }; 318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; }; 318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; }; - 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; }; - 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; }; 31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; }; 31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; }; 31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; }; @@ -2267,8 +2263,6 @@ 318DA8C21892B0B20089718C /* Benchmarks */ = { isa = PBXGroup; children = ( - 318DA8D01892B13B0089718C /* getopt.h */, - 318DA8D11892B13B0089718C /* getoptl.c */, 318DA8CE1892B1210089718C /* djbench.c */, 6313D46618A3FDC900EB03EF /* gcbench.c */, ); @@ -3403,7 +3397,7 @@ 2215A9B9192A47CE00E9E2CE /* testall */, 2215A9B1192A47C500E9E2CE /* testansi */, 2215A9A9192A47BB00E9E2CE /* testci */, - 2215A9C1192A47D500E9E2CE /* testpoll */, + 2215A9C1192A47D500E9E2CE /* testpollnone */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, @@ -3468,7 +3462,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9B4192A47C500E9E2CE /* ShellScript */ = { @@ -3482,7 +3476,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9BC192A47CE00E9E2CE /* ShellScript */ = { @@ -3496,7 +3490,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9C4192A47D500E9E2CE /* ShellScript */ = { @@ -3510,7 +3504,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { @@ -3524,7 +3518,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -3909,7 +3903,6 @@ files = ( 318DA8D31892B27E0089718C /* testlib.c in Sources */, 6313D47318A4028E00EB03EF /* djbench.c in Sources */, - 318DA8D21892B13B0089718C /* getoptl.c in Sources */, 22561A9A18F426BB00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4018,7 +4011,6 @@ 6313D47418A4029200EB03EF /* gcbench.c in Sources */, 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */, 6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */, - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */, 22561A9B18F426F300372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5810,7 +5802,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = { + 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */ = { isa = XCConfigurationList; buildConfigurations = ( 2215A9C6192A47D500E9E2CE /* Debug */, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c00da18c201..283fbc6123e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1,14 +1,14 @@ /* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * .purpose: This code bridges between the MPS interface to C, * , and the internal MPM interfaces, as defined by * . .purpose.check: It performs checking of the C client's * usage of the MPS Interface. .purpose.thread: It excludes multiple - * threads from the MPM by locking the Arena (see .thread-safety). + * threads from the MPM by locking the Arena (see ). * * .design: * @@ -248,7 +248,7 @@ void mps_arena_park(mps_arena_t arena) void mps_arena_expose(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 0); + ArenaExposeRemember(ArenaGlobals(arena), FALSE); ArenaLeave(arena); } @@ -256,7 +256,7 @@ void mps_arena_expose(mps_arena_t arena) void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 1); + ArenaExposeRemember(ArenaGlobals(arena), TRUE); ArenaLeave(arena); } @@ -1384,6 +1384,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, AVER(mps_reg_scan != NULL); AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */ AVER(reg_scan_p != NULL); /* stackBot */ + AVER(AddrIsAligned(reg_scan_p, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); @@ -2005,7 +2006,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mv.nmk b/mps/code/mv.nmk index d0759bad532..6abd37d810e 100644 --- a/mps/code/mv.nmk +++ b/mps/code/mv.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Microsoft # Visual C/C+ compiler. It defines the compiler-specific variables -# that the common nmake file fragment () requires. +# that the common nmake fragment (comm.nmk) requires. CC = cl LIBMAN = lib diff --git a/mps/code/pc.nmk b/mps/code/pc.nmk index e52addfba4c..fdcf1235d37 100644 --- a/mps/code/pc.nmk +++ b/mps/code/pc.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Pelles C # compiler. It defines the compiler-specific variables that the common -# nmake file fragment () requires. +# nmake fragment (comm.nmk) requires. CC = pocc LIBMAN = polib diff --git a/mps/code/pool.c b/mps/code/pool.c index 945a846edcb..f939bca84e9 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -1,7 +1,7 @@ /* pool.c: POOL IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * DESIGN @@ -328,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* Can't check mode as there is no check method */ + AVERT(AccessSet, mode); /* Can't check MutatorFaultContext as there is no check method */ return (*pool->class->access)(pool, seg, addr, mode, context); @@ -694,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 712f24152e5..30f5d0f999e 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -1,7 +1,7 @@ /* poolabs.c: ABSTRACT POOL CLASSES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * PURPOSE @@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(mode); UNUSED(context); @@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(addr); @@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ arena = PoolArena(pool); @@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 01ca12ea46f..5bb0e6b9025 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1,7 +1,7 @@ /* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -1206,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); + AVERT(AccessSet, mode); /* Attempt scanning a single reference if permitted */ if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { @@ -1375,7 +1376,7 @@ static Bool AWLCheck(AWL awl) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 709dfb6bf7b..19b3c2bb443 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -1,7 +1,7 @@ /* poolmv.c: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * **** RESTRICTION: This pool may not allocate from the arena control @@ -260,7 +260,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failBlockPoolInit; spanExtendBy = sizeof(MVSpanStruct) * (maxSize/extendBy); @@ -270,7 +270,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failSpanPoolInit; mv->extendBy = extendBy; mv->avgSize = avgSize; @@ -284,6 +284,11 @@ static Res MVInit(Pool pool, ArgList args) AVERT(MV, mv); EVENT5(PoolInitMV, pool, arena, extendBy, avgSize, maxSize); return ResOK; + +failSpanPoolInit: + PoolFinish(mvBlockPool(mv)); +failBlockPoolInit: + return res; } @@ -913,7 +918,7 @@ Bool MVCheck(MV mv) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protan.c b/mps/code/protan.c index 1959e42395b..0e4771f18da 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -1,7 +1,7 @@ /* protan.c: ANSI MEMORY PROTECTION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -36,8 +36,7 @@ Size ProtGranularity(void) void ProtSet(Addr base, Addr limit, AccessSet pm) { AVER(base < limit); - /* .improve.protset.check: There is nor AccessSetCheck, so we */ - /* don't check it. */ + AVERT(AccessSet, pm); UNUSED(pm); NOOP; } @@ -74,7 +73,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index ea674ae53d5..a243b009491 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -1,7 +1,7 @@ /* protix.c: PROTECTION FOR UNIX * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between * OS X, FreeBSD, and Linux. @@ -66,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */ + AVERT(AccessSet, mode); /* Convert between MPS AccessSet and UNIX PROT thingies. In this function, AccessREAD means protect against read accesses @@ -122,7 +123,7 @@ Size ProtGranularity(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 30c3edc0975..a8dddd74fe2 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -1,7 +1,7 @@ /* protw3.c: PROTECTION FOR WIN32 * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); + AVERT(AccessSet, mode); newProtect = PAGE_EXECUTE_READWRITE; if((mode & AccessWRITE) != 0) @@ -140,7 +141,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/reserv.c b/mps/code/reserv.c index b0d431c3f9c..91a2fd52559 100644 --- a/mps/code/reserv.c +++ b/mps/code/reserv.c @@ -100,6 +100,7 @@ Bool ReservoirCheck(Reservoir reservoir) } CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena)); CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena)); + CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit); return TRUE; } diff --git a/mps/code/root.c b/mps/code/root.c index bd9afec57d4..7a3e1205be2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -1,7 +1,7 @@ /* root.c: ROOT IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the root datatype. * @@ -139,7 +139,7 @@ Bool RootCheck(Root root) CHECKL(root->protBase != (Addr)0); CHECKL(root->protLimit != (Addr)0); CHECKL(root->protBase < root->protLimit); - /* there is no AccessSetCheck */ + CHECKL(AccessSetCheck(root->pm)); } else { CHECKL(root->protBase == (Addr)0); CHECKL(root->protLimit == (Addr)0); @@ -263,7 +263,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, AVERT(Arena, arena); AVERT(Rank, rank); AVER(base != 0); - AVER(base < limit); + AVER(AddrIsAligned(base, sizeof(Word))); + AVER(base < limit); + AVER(AddrIsAligned(limit, sizeof(Word))); theUnion.table.base = base; theUnion.table.limit = limit; @@ -315,6 +317,13 @@ Res RootCreateReg(Root *rootReturn, Arena arena, return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion); } +/* RootCreateFmt -- create root from block of formatted objects + * + * .fmt.no-align-check: Note that we don't check the alignment of base + * and limit. That's because we're only given the scan function, so we + * don't know the format's alignment requirements. + */ + Res RootCreateFmt(Root *rootReturn, Arena arena, Rank rank, RootMode mode, mps_fmt_scan_t scan, Addr base, Addr limit) @@ -549,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr) void RootAccess(Root root, AccessSet mode) { AVERT(Root, root); - /* Can't AVERT mode. */ + AVERT(AccessSet, mode); AVER((root->pm & mode) != AccessSetEMPTY); AVER(mode == AccessWRITE); /* only write protection supported */ @@ -698,7 +707,7 @@ Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/seg.c b/mps/code/seg.c index ab7414eaf4a..7007bca62b7 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1,7 +1,7 @@ /* seg.c: SEGMENTS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .design: The design for this module is . * @@ -529,7 +529,7 @@ Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next) AVER_CRITICAL(segReturn != NULL); /* .seg.critical */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Pool, pool); - AVER_CRITICAL(RingCheck(next)); + AVERT_CRITICAL(Ring, next); if (next == PoolSegRing(pool)) { if (!PoolNext(&pool, arena, pool) || @@ -1224,7 +1224,7 @@ static void gcSegSetGrey(Seg seg, TraceSet grey) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(grey)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */ AVER(seg->rankSet != RankSetEMPTY); gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); @@ -1264,7 +1264,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white) Addr addr, limit; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(white)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, white); /* .seg.method.check */ gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); AVER_CRITICAL(&gcseg->segStruct == seg); @@ -1307,7 +1307,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1378,7 +1378,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1701,7 +1701,7 @@ void SegClassMixInNoSplitMerge(SegClass class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/shield.c b/mps/code/shield.c index 88ee8751331..0dfc1945db6 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -1,7 +1,7 @@ /* shield.c: SHIELD IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * See: idea.shield, design.mps.shield. * @@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); + AVERT_CRITICAL(AccessSet, mode); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); @@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* can't check seg. Nor can we check arena as that checks the */ /* segs in the cache. */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ @@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { /* Don't check seg or arena, see .seg.broken */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == mode); /* synced(seg) is not changed by the following * preserving inv.unsynced.suspended @@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/splay.c b/mps/code/splay.c index 658faa7dd25..ed46c7a4ba4 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1,7 +1,7 @@ /* splay.c: SPLAY TREE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Splay trees are used to manage potentially unbounded * collections of ordered things. In the MPS these are usually @@ -9,10 +9,9 @@ * * .source: * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ @@ -1402,7 +1401,7 @@ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/trace.c b/mps/code/trace.c index 7aeb70305c7..7e918513279 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,7 +1,7 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. + * Copyright (c) 2001-2015 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * @@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) AVERT(Arena, arena); AVERT(Seg, seg); + AVERT(AccessSet, mode); /* If it's a read access, then the segment must be grey for a trace */ /* which is flipped. */ @@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited + * Copyright (C) 2001-2015 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index 77fe772d587..ede8d012fe8 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) RememberedSummaryBlock newBlock; int res; - res = ControlAlloc(&p, arena, sizeof *newBlock, 0); + res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE); if(res != ResOK) { return res; } @@ -704,12 +704,13 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) protection state or not (for later restoration with ArenaRestoreProtection). */ -void ArenaExposeRemember(Globals globals, int remember) +void ArenaExposeRemember(Globals globals, Bool remember) { Seg seg; Arena arena; AVERT(Globals, globals); + AVERT(Bool, remember); ArenaPark(globals); diff --git a/mps/code/tract.c b/mps/code/tract.c index 5d3bffe9721..9aa815f47ba 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -167,7 +167,8 @@ Bool ChunkCheck(Chunk chunk) /* ChunkInit -- initialize generic part of chunk */ -Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot) +Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved, + BootBlock boot) { Size size; Count pages; @@ -192,6 +193,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot) chunk->pageShift = pageShift = SizeLog2(chunk->pageSize); chunk->base = base; chunk->limit = limit; + chunk->reserved = reserved; size = ChunkSize(chunk); chunk->pages = pages = size >> pageShift; @@ -262,17 +264,16 @@ void ChunkFinish(Chunk chunk) PageIndexBase(chunk, chunk->allocBase), chunk->limit); + ArenaChunkRemoved(arena, chunk); + chunk->sig = SigInvalid; TreeFinish(&chunk->chunkTree); RingRemove(&chunk->arenaRing); - if (chunk->arena->primary == chunk) - chunk->arena->primary = NULL; - /* Finish all other fields before class finish, because they might be */ /* unmapped there. */ - (chunk->arena->class->chunkFinish)(chunk); + (*arena->class->chunkFinish)(chunk); } diff --git a/mps/code/tract.h b/mps/code/tract.h index 07906ad5756..ce7c602a176 100644 --- a/mps/code/tract.h +++ b/mps/code/tract.h @@ -148,6 +148,9 @@ typedef struct ChunkStruct { BT allocTable; /* page allocation table */ Page pageTable; /* the page table */ Count pageTablePages; /* number of pages occupied by page table */ + Size reserved; /* reserved address space for chunk (including overhead + such as losses due to alignment): must not change + (or arena reserved calculation will break) */ } ChunkStruct; @@ -159,10 +162,11 @@ typedef struct ChunkStruct { #define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift)) #define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi]) #define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree) +#define ChunkReserved(chunk) RVALUE((chunk)->reserved) extern Bool ChunkCheck(Chunk chunk); extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, - BootBlock boot); + Size reserved, BootBlock boot); extern void ChunkFinish(Chunk chunk); extern Compare ChunkCompare(Tree tree, TreeKey key); extern TreeKey ChunkKey(Tree tree); diff --git a/mps/code/tree.c b/mps/code/tree.c index fb651ed5919..f87e8364ea7 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -1,7 +1,7 @@ /* tree.c: BINARY TREE IMPLEMENTATION * * $Id$ - * Copyright (C) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (C) 2014-2015 Ravenbrook Limited. See end of file for license. * * Simple binary trees with utilities, for use as building blocks. * Keep it simple, like Rings (see ring.h). @@ -9,10 +9,9 @@ * The performance requirements on tree implementation will depend on * how each individual function is applied in the MPS. * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ #include "tree.h" @@ -569,7 +568,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index ff84851b1de..92e609b5f2f 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -5,9 +5,6 @@ PFM = w3i3mv -PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -20,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index da76ee4d338..5ffe8892ebb 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -5,9 +5,6 @@ PFM = w3i3pc -PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -20,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 26f4329bc0e..eb36bc200d2 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -5,10 +5,6 @@ PFM = w3i6mv -PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS -MASM = ml64 - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -21,9 +17,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 9870f697e4b..31b86a82fc0 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -7,11 +7,8 @@ PFM = w3i6pc -PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS +CFLAGSTARGETPRE = /Tamd64-coff -CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -24,9 +21,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/design/an.txt b/mps/design/an.txt new file mode 100644 index 00000000000..7d6cc117407 --- /dev/null +++ b/mps/design/an.txt @@ -0,0 +1,216 @@ +.. mode: -*- rst -*- + +Generic modules +=============== + +:Tag: design.mps.an +:Author: Gareth Rees +:Date: 2014-11-02 +:Status: complete design +:Revision: $Id$ +:Copyright: See `Copyright and License`_. +:Index terms: pair: generic modules; design + + +Introduction +------------ + +_`.intro`: This is the design of generic modules in the MPS. + +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. + +_`.overview`: Generic modules provide implementations of functional +modules using only the features of the Standard C Library. These +implementations are partially functional or non-functional, but +provide a basis for ports of the MPS to new platforms. + +_`.name`: The name "ANSI" for the generic modules is historical: the C +language was originally standardized by the American National +Standards Institute, and so Standard C used to be known as "ANSI C". + + +Requirements +------------ + +_`.req.port`: The MPS must be portable to new platforms. (Otherwise we +can't meet the needs of customers using new platforms.) + +_`.req.port.rapid`: The MPS should be portable to new platforms +rapidly. + +_`.req.port.rapid.expert`: An expert MPS developer (who may be a +novice on the new platform) should be able to get a minimally useful +implementation of the MPS running on a new platform within a few +hours. + +_`.req.port.rapid.novice`: A novice MPS developer (who is an expert on +the new platform) should be able to get the MPS running on a new +platform within a few days. + + +Design +------ + +_`.sol.modules`: Features of the MPS which can benefit from +platform-specific implementations are divided into *functional +modules*, with clean interfaces to the MPS and to each other. See +`.mod`_ for a list of these modules. (This helps meet `.req.port`_ by +isolating the platform dependencies, and it helps meet +`.req.port.rapid`_ because a porter can mix and match implementations, +using existing implementations where possible.) + +_`.sol.generic`: Each functional module has a generic implementation +using only features of the Standard C Library. (This helps meet +`.req.port.rapid`_ because the MPS can be ported in stages, starting +with the generic modules and porting the modules needed to meet the +most urgent requirements. The generic implementations help meet +`.req.port.rapid.novice`_ by providing clear and illustrative +examples.) + +_`.sol.fallback`: The interfaces to the modules are designed to make +it possible to implement `.sol.generic`_. When a platform-specific +feature is needed to meet performance (or other attribute) +requirements, the interface also makes it possible to meet the +functional requirements while missing the attribute requirements. See +`.sol.fallback.example`_ for an example. (This helps meet +`.req.port.rapid`_ by allowing the generic implementations to meet +many or most of the functional requirements.) + +_`.sol.fallback.example`: The MPS normally uses incremental collection +to meet requirements on pause times, but this requires barriers. The +interface to the protection module is designed to make it possible to +write an implementation without barriers, via the function +``ProtSync()`` that synchronizes the mutator with the collector. + +_`.sol.test`: There are makefiles for the pseudo-platforms ``anangc``, +``ananll`` and ``ananmv`` that compile and test the generic +implementations. See design.mps.config.opt_ for the configuration +options used to implement these platforms. (This supports +`.req.port.rapid`_ by making sure that the generic implementations are +working when it is time to use them.) + +.. _design.mps.config.opt: config#opt + + +Modules +------- + +_`.mod`: This section lists the functional modules in the MPS. + +_`.mod.lock`: Locks. See design.mps.lock_. + +_`.mod.prmc`: Protection mutator context. See design.mps.prmc_. + +_`.mod.prot`: Memory protection. See design.mps.prot_. + +_`.mod.ss`: Stack and register scanning. See design.mps.ss_. + +_`.mod.sp`: Stack probe. See design.mps.sp_. + +_`.mod.th`: Thread manager. See design.mps.thread-manager_. + +_`.mod.vm`: Virtual mapping. See design.mps.vm_. + +.. _design.mps.lock: lock +.. _design.mps.prot: prot +.. _design.mps.prmc: prmc +.. _design.mps.sp: sp +.. _design.mps.ss: ss +.. _design.mps.thread-manager: thread-manager +.. _design.mps.vm: vm + + +Limitations of generic implementations +-------------------------------------- + +_`.lim`: This section summarizes the limitations of the generic +implementations of the function modules. + +_`.lim.lock`: Requires a single-threaded mutator (see +design.mps.lock.impl.an_). + +_`.lim.prmc`: Does not support single-stepping of accesses (see +design.mps.prmc.impl.an.fault_) and requires a single-threaded mutator +(see design.mps.prmc.impl.an.suspend_). + +_`.lim.prot`: Does not support incremental collection (see +design.mps.prot.impl.an.sync_) and is not compatible with +implementations of the protection mutator context module that support +single-stepping of accesses (see design.mps.prot.impl.an.sync.issue_). + +_`.lim.sp`: Only suitable for use with programs that do not handle +stack overflow faults, or do not call into the MPS from the handler +(see design.mps.sp.issue.an_). + +_`.lim.ss`: Overscans compared to a platform-specific implementation +(see design.mps.ss.impl.an_). + +_`.lim.th`: Requires a single-threaded mutator (see +design.mps.thread-manager.impl.an.single_). + +_`.lim.vm`: Maps all reserved addresses into main memory (see +design.mps.vm.impl.an.reserve_), thus using more main memory than a +platform-specific implementation. + +.. _design.mps.lock.impl.an: lock#impl.an +.. _design.mps.prmc.impl.an.fault: prmc#impl.an.fault +.. _design.mps.prmc.impl.an.suspend: prmc#impl.an.suspend +.. _design.mps.prot.impl.an.sync: prot#impl.an.sync +.. _design.mps.prot.impl.an.sync.issue: prot#impl.an.sync.issue +.. _design.mps.sp.issue.an: sp#issue.an +.. _design.mps.ss.impl.an: ss#impl.an +.. _design.mps.thread-manager.impl.an.single: thread-manager#impl.an.single +.. _design.mps.vm.impl.an.reserve: vm#impl.an.reserve + + + +Document History +---------------- + +- 2014-11-02 GDR_ Initial draft based on design.mps.protan. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. All rights reserved. +. This is an open source license. Contact +Ravenbrook for commercial licensing options. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +#. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +#. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +#. Redistributions in any form must be accompanied by information on how + to obtain complete source code for this software and any + accompanying software that uses this software. The source code must + either be included in the distribution or be available for no more than + the cost of distribution plus a nominal fee, and must be freely + redistributable under reasonable conditions. For an executable file, + complete source code means the source code for all modules it contains. + It does not include source code for modules or files that typically + accompany the major components of the operating system on which the + executable file runs. + +**This software is provided by the copyright holders and contributors +"as is" and any express or implied warranties, including, but not +limited to, the implied warranties of merchantability, fitness for a +particular purpose, or non-infringement, are disclaimed. In no event +shall the copyright holders and contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or +services; loss of use, data, or profits; or business interruption) +however caused and on any theory of liability, whether in contract, +strict liability, or tort (including negligence or otherwise) arising in +any way out of the use of this software, even if advised of the +possibility of such damage.** diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt new file mode 100644 index 00000000000..7eb79df1475 --- /dev/null +++ b/mps/design/bootstrap.txt @@ -0,0 +1,127 @@ +.. mode: -*- rst -*- + +Bootstrapping +============= + +:Tag: design.mps.bootstrap +:Author: Gareth Rees +:Date: 2015-09-01 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: bootsrap; design + + +Introduction +------------ + +_`.intro`: This explains how the MPS gets started. + +_`.readership`: Any MPS developer. + +_`.overview`: The job of the MPS is to allocate memory to a program. +Before it can allocate memory, the MPS needs to create data structures +to represent its internal state. But before it can create those data +structures, it needs to allocate memory to store them in. This +bootstrapping problem affects the MPS at several points, which are +listed here, together with their solutions. + + +Bootstrapping problems +---------------------- + +Virtual memory descriptor +......................... + +_`.vm`: Before address space can be mapped into main memory, the +virtual memory descriptor must be initialized. But before the virtual +memory descriptor can be initialized, some address space must be +mapped into main memory in order to store it. See +`design.vm.req.bootstrap`_. + +_`.vm.sol`: The virtual memory descriptor is allocated initially on +the stack, and then copied into its place in the chunk after the +memory for it has been mapped. See `design.vm.sol.bootstrap`_. + +.. _design.vm.req.bootstrap: vm#req.bootstrap +.. _design.vm.sol.bootstrap: vm#sol.bootstrap + + +Arena descriptor +................ + +_`.arena`: Before chunks of address space can be reserved and mapped, +the virtual memory arena descriptor must be initialized (so that the +chunks can be added to the arena's chunk tree). But before a virtual +memory arena descriptor can be initialized, address space must be +reserved and mapped in order to store it. + +_`.arena.sol`: A small amount of address space is reserved and mapped +directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system) +in order to provide enough memory for the arena descriptor. + + +Arena's free land +................. + +_`.land`: Before the arena can allocate memory, a range of addresses +must be inserted into the arena's free land (so that the free land can +hand out memory from this range). But before addresses can be inserted +into the arena's free land, the arena must be able to allocate memory +(to store the nodes in the tree representing those addresses). + +_`.land.sol`: The arena has two "back door" mechanisms and uses them +in combination. First, there is a mechanism for allocating a block of +memory directly from a chunk, bypassing the free land; second, the MFS +pool class has a mechanism for extending it with a block of memory. + + +Document History +---------------- + +- 2015-09-01 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2015 Ravenbrook Limited. All rights reserved. +. This is an open source license. Contact +Ravenbrook for commercial licensing options. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +#. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +#. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +#. Redistributions in any form must be accompanied by information on how + to obtain complete source code for this software and any + accompanying software that uses this software. The source code must + either be included in the distribution or be available for no more than + the cost of distribution plus a nominal fee, and must be freely + redistributable under reasonable conditions. For an executable file, + complete source code means the source code for all modules it contains. + It does not include source code for modules or files that typically + accompany the major components of the operating system on which the + executable file runs. + +**This software is provided by the copyright holders and contributors +"as is" and any express or implied warranties, including, but not +limited to, the implied warranties of merchantability, fitness for a +particular purpose, or non-infringement, are disclaimed. In no event +shall the copyright holders and contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or +services; loss of use, data, or profits; or business interruption) +however caused and on any theory of liability, whether in contract, +strict liability, or tort (including negligence or otherwise) arising in +any way out of the use of this software, even if advised of the +possibility of such damage.** diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 629ffee08fe..34c2eedd4cd 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -76,14 +76,14 @@ class, a subclass of ``LandClass`` suitable for passing to ``LandClass CBSFastLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSLandClass`` that +_`.function.class.fast`: Returns a subclass of ``CBSLandClass`` that maintains, for each subtree, the size of the largest block in that subtree. This enables the ``LandFindFirst()``, ``LandFindLast()``, and ``LandFindLargest()`` generic functions. ``LandClass CBSZonedLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that +_`.function.class.zoned`: Returns a subclass of ``CBSFastLandClass`` that maintains, for each subtree, the union of the zone sets of all ranges in that subtree. This enables the ``LandFindInZones()`` generic function. diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt new file mode 100644 index 00000000000..65de1dd228f --- /dev/null +++ b/mps/design/exec-env.txt @@ -0,0 +1,189 @@ +.. mode: -*- rst -*- + +Execution environment +===================== + +:Tag: design.mps.exec-env +:Author: Richard Brooksby +:Date: 1996-08-30 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: execution; environment + + +Introduction +------------ + +_`.intro`: This document describes how the MPS is designed to work in +different execution environments (see standard.ansic section 5.1.2). + + +Discussion +---------- + +_`.std`: These are the relevant statements from the International +Standard ISO/IEC 9899:1990 "Programming languages — C", with tags +added: + + 4. Compliance + + […] + + _`.std.com.hosted`: A "conforming hosted implementation" shall + accept any strictly conforming program. _`.std.com.free`: A + "conforming freestanding implementation" shall accept any strictly + conforming program in which the use of the features specified in + the library clause (clause 7) is confined to the contents of the + standard headers ````, ````, ````, + and ````. A conforming implementation may have + extensions (including additional library functions), provided they + do not alter the behaviour of any strictly conforming program. + + […] + + 5.1.2 Execution environments + + _`.std.def`: Two execution environments are defined: + "freestanding" and "hosted". […] + + _`.std.init`: All objects in static storage shall be "initialized" + (set to their initial values) before program startup. The manner + and timing of such initialization are otherwise unspecified. […] + + _`.std.term`: "Program termination" returns control to the execution + environment. […] + + 5.1.2.1 Freestanding environment + + _`.std.free.lib`: Any library facilities available to a + freestanding environment are implementation-defined. + + _`.std.free.term`: The effect of program termination in a + free-standing environment is implementation-defined. + + +Interpretation +-------------- + +_`.int.free`: We interpret the "freestanding environment" as being the +sort of environment you'd expect in an embedded system. The classic +example is a washing machine. There are no library facilities +available, only language facilities. + +_`.int.free.lib`: We assume that the headers ````, +````, ```` and ```` are available in the +freestanding environment, because they define only language features +and not library calls. We assume that we may not make use of +definitions in any other headers in freestanding parts of the system. + +_`.int.free.term`: We may not terminate the program in a freestanding +environment, and therefore we may not call :c:func:`abort`. We can't +call :c:func:`abort` anyway, because it's not defined in the headers +listed above (`.int.free.lib`_). + +_`.int.free.term.own`: We can add an interface for asserting, that is, +reporting an error and not returning, for use in debugging builds +only. This is because the environment can implement this in a way that +does not return to the MPS, but doesn't terminate, either. We need +this if debugging builds are to run in a (possibly simulated or +emulated) freestanding environment at all. + + +Requirements +------------ + +_`.req`: It should be possible to make use of the MPS in a +freestanding environment such as an embedded controller. + +_`.req.conf`: There can be configurations of the MPS that are not +freestanding (such as using a VM arena). + + +Architecture +------------ + +_`.arch`: Like Gaul, the MPS is divided into three parts: the *core*, +the *platform*, and the *plinth*. + +_`.arch.core`: The *core* consists of the Memory Pool Manager (the +core data structures and algorithms) and the built-in Pool Classes. +The core must be freestanding. + +_`.arch.platform`: The *platform* provides the core with interfaces to +features of the operating system and processor (locks, memory +protection, protection mutator context, stack probing, stack and +register scanning, thread management, and virtual memory). The +platform is specialized to a particular environment and so can safely +use whatever features are available in that environment. + +_`.arch.plinth`: The *plinth* provides the core with interfaces to +features of the user environment (time, assertions, and logging). See +design.mps.io_ and design.mps.lib_. + +.. _design.mps.io: io +.. _design.mps.lib: lib + +_`.arch.distinction`: The distinction between *plinth* and *platform* +is that end users will need to customize the features provided by the +plinth for most programs that use the MPS (and so the interface needs +to be simple, documented and supported), whereas implementing the +platform interface is a specialized task that will typically be done +once for each platform and then maintained alongside the core. + + +Document History +---------------- + +- 1996-08-30 RB_ Created to clarify concepts needed for + design.mps.io_. + +- 2015-02-06 GDR_ Converted to reStructuredText; bring the + architecture description up to date by describing the platform + interface. + +.. _RB: http://www.ravenbrook.com/consultants/rb/ +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 1996-2015 Ravenbrook Limited. All rights reserved. +. This is an open source license. Contact +Ravenbrook for commercial licensing options. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +#. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +#. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +#. Redistributions in any form must be accompanied by information on how + to obtain complete source code for this software and any + accompanying software that uses this software. The source code must + either be included in the distribution or be available for no more than + the cost of distribution plus a nominal fee, and must be freely + redistributable under reasonable conditions. For an executable file, + complete source code means the source code for all modules it contains. + It does not include source code for modules or files that typically + accompany the major components of the operating system on which the + executable file runs. + +**This software is provided by the copyright holders and contributors +"as is" and any express or implied warranties, including, but not +limited to, the implied warranties of merchantability, fitness for a +particular purpose, or non-infringement, are disclaimed. In no event +shall the copyright holders and contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or +services; loss of use, data, or profits; or business interruption) +however caused and on any theory of liability, whether in contract, +strict liability, or tort (including negligence or otherwise) arising in +any way out of the use of this software, even if advised of the +possibility of such damage.** diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index 95c533f6bc8..8120f6e53e5 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -22,10 +22,11 @@ hexadecimal digits. _`.readership`: This document is intended for anyone devising arbitrary constants which may appear in hex-dumps. -_`.sources`: This transliteration was supplied by RHSK in -`mail.richardk.1997-04-07.13-44`_. - -.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt +_`.sources`: This transliteration was supplied by Richard Kistruck +[RHSK-1997-04-07]_ based on magic number encodings for object signatures +used by Richard Brooksby [RB-1996-02-12]_, the existence of which was +inspired by the structure marking used in the Multics operating system +[THVV-1995]_. Transliteration @@ -78,8 +79,8 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common letter that it deserves it. -4. Notes --------- +Notes +----- _`.change`: This transliteration differs from the old transliteration used for signatures (see design.mps.sig_), as follows: J:6->1; @@ -106,6 +107,33 @@ selected (by capitalisation), e.g.:: #define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */ +References +---------- + +.. [RB-1996-02-12] + "Signature magic numbers" (e-mail message); + `Richard Brooksby`_; + Harlequin; + 1996-12-02 12:05:30Z. + +.. _`Richard Brooksby`: mailto:rb@ravenbrook.com + +.. [RHSK-1997-04-07] + "Alpha-to-Hex v1.0 beta"; + Richard Kistruck; + Ravenbrook; + 1997-04-07 14:42:02+0100; + . + +.. [THVV-1995] + "Structure Marking"; + Tom Van Vleck; + multicians.org_; + . + +.. _multicians.org: http://www.multicians.org/ + + Document History ---------------- 2013-05-10 RB_ Converted to reStructuredText and imported to MPS design. diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt new file mode 100644 index 00000000000..b1298b26b90 --- /dev/null +++ b/mps/design/guide.review.txt @@ -0,0 +1,96 @@ +.. mode: -*- rst -*- + +Review checklist +================ + +:Tag: guide.review +:Status: incomplete documentation +:Author: Gareth Rees +:Organization: Ravenbrook Limited +:Date: 2015-08-10 +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: review; checklist + + +Introduction +------------ + +_`.scope`: This document contains a list of checks to apply when +reviewing code or other documents in the Memory Pool System. + +_`.readership`: This document is intended for reviewers. + +_`.example`: The "example" links are issues caused by a failure to +apply the checklist item. + +_`.diff`: Some items in the checklist are particularly susceptible to +being ignored if one reviews only via the version control diff. These +items refer to this tag. + + +Checklist +--------- + +_`.test`: If a new feature has been added to the code, is there a test +case? Example: job003923_. + +.. _job003923: http://www.ravenbrook.com/project/mps/issue/job003923/ + +_`.unwind`: If code has been updated in a function that unwinds its +state in failure cases, have the failure cases been updated to +correspond? Example: job003922_. See `.diff`_. + +.. _job003922: http://www.ravenbrook.com/project/mps/issue/job003922/ + + + +Document History +---------------- + +2015-08-10 GDR_ Created. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2015 Ravenbrook Limited. All rights reserved. +. This is an open source license. Contact +Ravenbrook for commercial licensing options. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +#. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +#. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +#. Redistributions in any form must be accompanied by information on how + to obtain complete source code for this software and any + accompanying software that uses this software. The source code must + either be included in the distribution or be available for no more than + the cost of distribution plus a nominal fee, and must be freely + redistributable under reasonable conditions. For an executable file, + complete source code means the source code for all modules it contains. + It does not include source code for modules or files that typically + accompany the major components of the operating system on which the + executable file runs. + +**This software is provided by the copyright holders and contributors +"as is" and any express or implied warranties, including, but not +limited to, the implied warranties of merchantability, fitness for a +particular purpose, or non-infringement, are disclaimed. In no event +shall the copyright holders and contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or +services; loss of use, data, or profits; or business interruption) +however caused and on any theory of liability, whether in contract, +strict liability, or tort (including negligence or otherwise) arising in +any way out of the use of this software, even if advised of the +possibility of such damage.** diff --git a/mps/design/index.txt b/mps/design/index.txt index d2a1e06024f..7e48b625319 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -41,8 +41,10 @@ Designs ====================== ================================================ abq_ Fixed-length queues alloc-frame_ Allocation frame protocol +an_ Generic modules arena_ Arena arenavm_ Virtual memory arena +bootstrap_ Bootstrapping bt_ Bit tables buffer_ Allocation buffers and allocation points cbs_ Coalescing block structures @@ -52,6 +54,7 @@ collection_ Collection framework config_ MPS configuration critical-path_ The critical path through the MPS diag_ Diagnostic feedback +exec-env_ Execution environment failover_ Fail-over allocator finalize_ Finalization fix_ The generic fix function @@ -59,6 +62,7 @@ freelist_ Free list allocator guide.hex.trans_ Transliterating the alphabet into hexadecimal guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS guide.impl.c.naming_ Coding standard: conventions for internal names +guide.review_ Review checklist interface-c_ C interface io_ I/O subsystem keyword-arguments_ Keyword arguments @@ -82,7 +86,6 @@ poolmvt_ Manual Variable Temporal pool class poolmvff_ Manual Variable First-Fit pool class prmc_ Protection mutator context prot_ Memory protection -protan_ ANSI implementation of protection module protli_ Linux implementation of protection module protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module @@ -117,8 +120,10 @@ writef_ The WriteF function .. _abq: abq .. _alloc-frame: alloc-frame +.. _an: an .. _arena: arena .. _arenavm: arenavm +.. _bootstrap: bootstrap .. _bt: bt .. _buffer: buffer .. _cbs: cbs @@ -128,6 +133,7 @@ writef_ The WriteF function .. _config: config .. _critical-path: critical-path .. _diag: diag +.. _exec-env: exec-env .. _failover: failover .. _finalize: finalize .. _fix: fix @@ -135,6 +141,7 @@ writef_ The WriteF function .. _guide.hex.trans: guide.hex.trans .. _guide.impl.c.format: guide.impl.c.format .. _guide.impl.c.naming: guide.impl.c.naming +.. _guide.review: guide.review .. _interface-c: interface-c .. _io: io .. _keyword-arguments: keyword-arguments @@ -158,7 +165,6 @@ writef_ The WriteF function .. _poolmvff: poolmvff .. _prmc: prmc .. _prot: prot -.. _protan: protan .. _protli: protli .. _protocol: protocol .. _protsu: protsu @@ -231,7 +237,7 @@ Document History Copyright and License --------------------- -Copyright © 2002-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2002-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/io.txt b/mps/design/io.txt index 655eea8caf2..27ab9d7802a 100644 --- a/mps/design/io.txt +++ b/mps/design/io.txt @@ -95,17 +95,19 @@ which the MPM sends and receives "messages" to and from the hosted I/O module. _`.arch.module`: The modules are part of the MPS but not part of the -freestanding core system (see design.mps.exec-env). The I/O module is +freestanding core system (see design.mps.exec-env_). The I/O module is responsible for transmitting those messages to the external tools, and for receiving messages from external tools and passing them to the MPM. +.. _design.mps.exec-env: exec-env + _`.arch.module.example`: For example, the "file implementation" might just send/write telemetry messages into a file so that they can be received/read later by an off-line measurement tool. _`.arch.external`: The I/O Interface is part of interface to the -freestanding core system (see design.mps.exec-env). This is so that +freestanding core system (see design.mps.exec-env_). This is so that the MPS can be deployed in a freestanding environment, with a special I/O module. For example, if the MPS is used in a washing machine the I/O module could communicate by writing output to the seven-segment @@ -429,7 +431,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/land.txt b/mps/design/land.txt index f99ff95baba..df16fc922b9 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -86,7 +86,7 @@ indicating whether to continue with the iteration. ``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS)`` -_`.type.visitor`: Type ``LandDeleteVisitor`` is a callback function that may +_`.type.deletevisitor`: Type ``LandDeleteVisitor`` is a callback function that may be passed to ``LandIterateAndDelete()``. It is called for every isolated contiguous range in address order. The function must return a ``Bool`` indicating whether to continue with the iteration. It may additionally @@ -187,6 +187,16 @@ _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor function additionally returns a Boolean indicating whether the range should be deleted from the land. +_`.function.iterate.and.delete.justify`: The reason for having both +``LandIterate()`` and ``LandIterateAndDelete()`` is that it may be +possible to use a more efficient algorithm, or to preserve more +properties of the data structure, when it is known that the land willl +not be modified during the iteration. For example, in the CBS +implementation, ``LandIterate()`` uses ``TreeTraverse()`` which +preserves the tree structure, whereas ``LandIterateAndDelete()`` uses +``TreeTraverseAndDelete()`` which flattens the tree structure, losing +information about recently accessed nodes. + ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` _`.function.find.first`: Locate the first block (in address order) @@ -311,7 +321,7 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. +Copyright © 2014-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/lib.txt b/mps/design/lib.txt index 962b6328cb2..1dd7efe6964 100644 --- a/mps/design/lib.txt +++ b/mps/design/lib.txt @@ -29,11 +29,13 @@ _`.goal`: The goals of the MPS library interface are: _`.goal.host`: To control the dependency of the MPS on the hosted ISO C library so that the core MPS remains freestanding (see -design.mps.exec-env). +design.mps.exec-env_). + +.. _design.mps.exec-env: exec-env _`.goal.free`: To allow the core MPS convenient access to ISO C functionality that is provided on freestanding platforms (see -design.mps.exec-env.std.com.free). +design.mps.exec-env_). Description @@ -46,7 +48,7 @@ _`.overview.access`: The core MPS needs to access functionality that could be provided by an ISO C hosted environment. _`.overview.hosted`: The core MPS must not make direct use of any -facilities in the hosted environment (design.mps.exec-env). However, +facilities in the hosted environment (design.mps.exec-env_). However, it is sensible to make use of them when the MPS is deployed in a hosted environment. @@ -93,7 +95,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 2c744cedb64..069474ae428 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -166,7 +166,7 @@ implemented using the same mechanism as normal locks. (But an operating system-specific mechanism is used, if possible, to ensure that the global locks are initialized just once.) -_`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: +_`.impl.an`: Single-threaded generic implementation ``lockan.c``: - single-threaded; - no need for locking; @@ -174,7 +174,7 @@ _`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: - provides checking in debug version; - otherwise does nothing except keep count of claims. -_`.impl.win`: Windows implementation ``lockw3.c``: +_`.impl.w3`: Windows implementation ``lockw3.c``: - supports Windows threads; - uses critical section objects [cso]_; @@ -182,7 +182,7 @@ _`.impl.win`: Windows implementation ``lockw3.c``: - recursive and non-recursive calls use the same Windows function; - also performs checking. -_`.impl.posix`: POSIX implementation ``lockix.c``: +_`.impl.ix`: POSIX implementation ``lockix.c``: - supports [POSIXThreads]_; - locking structure contains a mutex, initialized to check for @@ -194,7 +194,7 @@ _`.impl.posix`: POSIX implementation ``lockix.c``: success or ``EDEADLK`` (indicating a recursive claim); - also performs checking. -_`.impl.linux`: Linux implementation ``lockli.c``: +_`.impl.li`: Linux implementation ``lockli.c``: - supports [POSIXThreads]_; - also supports [LinuxThreads]_, a partial implementation of POSIX Threads diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 8d13d831420..0822e709527 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -7,7 +7,7 @@ Protection mutator context :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: protection mutator context; design diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 89635435ede..fb06b78b328 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -116,9 +116,22 @@ _`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if Implementations --------------- -_`.impl.an`: Generic implementation. See design.mps.protan_. +_`.impl.an`: Generic implementation in ``protan.c``. -.. _design.mps.protan: protan +_`.impl.an.set`: ``ProtSet()`` does nothing. + +_`.impl.an.sync`: ``ProtSync()`` has no way of changing the protection +of a segment, so it simulates faults on all segments that are supposed +to be protected, by calling ``TraceSegAccess()``, until it determines +that no segments require protection any more. This forces the trace to +proceed until it is completed, preventing incremental collection. + +_`.impl.an.sync.issue`: This relies on the pool actually removing the +protection, otherwise there is an infinite loop here. This is +therefore not compatible with implementations of the protection +mutator context module that support single-stepping of accesses (see design.mps.prmc.req.fault.step_). + +.. _design.mps.prmc.req.fault.step: prmc#req.fault.step _`.impl.ix`: POSIX implementation. diff --git a/mps/design/protan.txt b/mps/design/protan.txt deleted file mode 100644 index 4ab046d7e47..00000000000 --- a/mps/design/protan.txt +++ /dev/null @@ -1,135 +0,0 @@ -.. mode: -*- rst -*- - -ANSI implementation of protection module -======================================== - -:Tag: design.mps.protan -:Author: David Jones -:Date: 1997-03-19 -:Status: incomplete document -:Revision: $Id$ -:Copyright: See `Copyright and License`_. -:Index terms: - pair: ANSI; protection interface design - pair: ANSI protection interface; design - - -Introduction ------------- - -_`.readership`: Any MPS developer. - -_`.intro`: This is the design for the ANSI implementation of the -protection module. - - -Requirements ------------- - -_`.req.test`: This module is required for testing. Particularly on -platforms where no real implementation of the protection module -exists. - -_`.req.rapid-port`: This module is required for rapid porting. It -should enable a developer to port a minimally useful configuration of -the MPS to new platforms very quickly. - - -Overview --------- - -_`.overview`: Most of the functions in the module do nothing. The -exception is ``ProtSync()`` which traverses over all segments in the -arena and simulates an access to each segment that has any protection -on it. This means that this module depends on certain fields in the -segment structure. - -_`.overview.noos`: No operating system specific (or even ANSI hosted -specific) code is in this module. It can therefore be used on any -platform, particularly where no real implementation of the module -exists. It satisfies `.req.test`_ and `.req.rapid-port`_ in this way. - - -Functions ---------- - -_`.fun.protsetup`: ``ProtSetup()`` does nothing as there is nothing to -do (under UNIX we might expect the protection module to install one or -more signal handlers at this pointer, but that is not appropriate for -the ANSI implementation). Of course, we can't have an empty function -body, so there is a ``NOOP;`` here. - -_`.fun.sync`: ``ProtSync()`` is called to ensure that the actual -protection of each segment (as determined by the OS) is in accordance -with the segments's pm field. In the ANSI implementation we have no -way of changing the protection of a segment, so instead we generate -faults on all protected segments in the assumption that that will -remove the protection on segments. - -_`.fun.sync.how`: Continually loops over all the segments until it -finds that all segments have no protection. - -_`.fun.sync.seg`: If it finds a segment that is protected then -``PoolAccess()`` is called on that segment's pool and with that -segment. The call to ``PoolAccess()`` is wrapped with a -``ShieldEnter()`` and ``ShieldLeave()`` thereby giving the pool the -illusion that the fault was generated outside the MM. This depends on -being able to determine the protection of a segment (using the ``pm`` -field), on being able to call ``ShieldEnter()`` and ``ShieldLeave()``, -and on being able to call ``PoolAccess()``. - - -Document History ----------------- - -- 1997-03-19 David Jones. Incomplete document. - -- 2002-06-07 RB_ Converted from MMInfo database design document. - -- 2013-05-23 GDR_ Converted to reStructuredText. - -.. _RB: http://www.ravenbrook.com/consultants/rb/ -.. _GDR: http://www.ravenbrook.com/consultants/gdr/ - - -Copyright and License ---------------------- - -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact -Ravenbrook for commercial licensing options. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -#. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -#. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -#. Redistributions in any form must be accompanied by information on how - to obtain complete source code for this software and any - accompanying software that uses this software. The source code must - either be included in the distribution or be available for no more than - the cost of distribution plus a nominal fee, and must be freely - redistributable under reasonable conditions. For an executable file, - complete source code means the source code for all modules it contains. - It does not include source code for modules or files that typically - accompany the major components of the operating system on which the - executable file runs. - -**This software is provided by the copyright holders and contributors -"as is" and any express or implied warranties, including, but not -limited to, the implied warranties of merchantability, fitness for a -particular purpose, or non-infringement, are disclaimed. In no event -shall the copyright holders and contributors be liable for any direct, -indirect, incidental, special, exemplary, or consequential damages -(including, but not limited to, procurement of substitute goods or -services; loss of use, data, or profits; or business interruption) -however caused and on any theory of liability, whether in contract, -strict liability, or tort (including negligence or otherwise) arising in -any way out of the use of this software, even if advised of the -possibility of such damage.** diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 235e00f82ac..47dab436b4e 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -7,7 +7,7 @@ Stack probe :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack probe; design @@ -143,7 +143,7 @@ that it is only suitable for use with programs that do not handle stack overflow faults, or do not call into the MPS from the handler. This is because our customers have only required `.req.overflow`_ on Windows so far. If this becomes a requirement on other platforms, the -following Standard C implementation is likely to work:: +following Standard C implementation might work:: void StackProbe(Size depth) { volatile Word w; @@ -151,8 +151,9 @@ following Standard C implementation is likely to work:: w = *p; } -(The use of ``volatile`` is to prevent compilers from warning about -the variable ``w`` being written but never read.) +The use of ``volatile`` here is to prevent compilers from warning +about the variable ``w`` being written but never read, or worse, +optimizing away the whole statement under the "as if" rule. Implementations diff --git a/mps/design/splay-rotate-left.svg b/mps/design/splay-rotate-left.svg index f5e50922aa8..00ae646a735 100644 --- a/mps/design/splay-rotate-left.svg +++ b/mps/design/splay-rotate-left.svg @@ -388,7 +388,7 @@ id="tspan4371" x="388" y="96.362183" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y y + sodipodi:role="line">x diff --git a/mps/design/splay-rotate-right.svg b/mps/design/splay-rotate-right.svg index 39fea1b2a20..d2a02bc48bb 100644 --- a/mps/design/splay-rotate-right.svg +++ b/mps/design/splay-rotate-right.svg @@ -374,7 +374,7 @@ id="tspan4371" x="388" y="96.362183" - style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y y + sodipodi:role="line">x diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 01dd2caf268..60b5c2817fa 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -7,7 +7,7 @@ Stack and register scanning :Author: Gareth Rees :Date: 2014-10-22 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack and register scanning; design diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt index e00ccd8b317..a1bf99bb247 100644 --- a/mps/design/testthr.txt +++ b/mps/design/testthr.txt @@ -7,7 +7,7 @@ Multi-threaded testing :Author: Gareth Rees :Date: 2014-10-21 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/nailboard.txt#3 $ +:Revision: $Id$ :Copyright: See section `Copyright and License`_. :Index terms: pair: threads; testing diff --git a/mps/design/type.txt b/mps/design/type.txt index 708693ad1db..25943f41a4b 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -180,8 +180,8 @@ Mode Description ======================== ============================================== ``BufferModeATTACHED`` Buffer is attached to a region of memory. ``BufferModeFLIPPED`` Buffer has been flipped. -``BufferModeLOGGED`` Buffer emits the events ``BufferReserve`` and - ``BufferCommit``. +``BufferModeLOGGED`` Buffer remains permanently trapped, so that + all reserve and commit events can be logged. ``BufferModeTRANSITION`` Buffer is in the process of being detached. ======================== ============================================== diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 85c5506043f..fb1be6eb5da 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -133,8 +133,8 @@ the function ``VMCopy()``. This allows the initialization of a temporary VM descriptor on the stack. Second, call ``VMInit()`` to reserve address space and initialize the temporary VM descriptor. Third, call ``VMMap()`` on the new VM to map enough memory to store a -``VMChunkStruct``. Fourth, call ``VMCopy()`` to copy the temporary VM -descriptor into its place in the ``VMChunkStruct``. +``VMChunk``. Fourth, call ``VMCopy()`` to copy the temporary VM +descriptor into its place in the ``VMChunk``. _`.sol.params`: To meet `.req.params`_, the interface provides the function ``VMParamFromArgs()``, which decodes relevant keyword diff --git a/mps/design/writef.txt b/mps/design/writef.txt index bb8547d6616..2a0277990e0 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -6,7 +6,7 @@ The WriteF function :Tag: design.mps.writef :Author: Richard Brooksby :Date: 1996-10-18 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: WriteF function; design @@ -16,11 +16,13 @@ Introduction ------------ _`.intro`: This document describes the ``WriteF()`` function, which -allows formatted output in a manner similar to ANSI C ``printf``, but -allows the MPM to operate in a freestanding environment (see -design.mps.exec-env). +allows formatted output in a manner similar to ``printf()`` from the +Standard C library, but allows the Memory Pool Manager (MPM) to +operate in a freestanding environment (see design.mps.exec-env_). -_`.background`: The documents design.mps.exec-env and design.mps.lib_ +.. _design.mps.exec-env: exec-env + +_`.background`: The documents design.mps.exec-env_ and design.mps.lib_ describe the design of the library interface and the reason that it exists. @@ -31,10 +33,10 @@ Design ------ _`.no-printf`: There is no dependency on ``printf()``. The MPM only -depends on ``fputc()`` and ``fputs()``, via the Library Interface -(design.mps.lib_). This makes it much easier to deploy the MPS in a -freestanding environment. This is achieved by implementing our own -internal output routines in mpm.c. +depends on ``mps_io_fputc()`` and ``mps_io_fputs()``, via the library +interface (design.mps.lib_), part of the *plinth*. This makes it much +easier to deploy the MPS in a freestanding environment. This is +achieved by implementing our own output routines. _`.writef`: Our output requirements are few, so the code is short. The only output function which should be used in the rest of the MPM is @@ -42,9 +44,9 @@ only output function which should be used in the rest of the MPM is ``Res WriteF(mps_lib_FILE *stream, Count depth, ...)`` -If ``depth`` is greater than zero, then the first format character, -and each format character after a newline, is preceded by ``depth`` -spaces. +If ``depth`` is greater than zero, then the first output character, +and each output character after a newline in a format string, is +preceded by ``depth`` spaces. ``WriteF()`` expects a format string followed by zero or more items to insert into the output, followed by another format string, more items, @@ -54,7 +56,8 @@ and so on, and finally a ``NULL`` format string. For example:: "Hello: $A\n", (WriteFA)address, "Spong: $U ($S)\n", (WriteFU)number, (WriteFS)string, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code:: @@ -83,14 +86,15 @@ This makes ``Describe()`` methods much easier to write. For example, ``BufferDes " alignment $W\n", (WriteFW)buffer->alignment, " rampCount $U\n", (WriteFU)buffer->rampCount, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; -_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a -type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted -version of that type. These are provided both to ensure promotion and -to avoid any confusion about what type should be used in a cast. It is -easy to check the casts against the formats to ensure that they -correspond. +_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is +a type ``WriteFX`` defined in mpmtypes.h, which is the promoted +version of that type. These types are provided both to ensure +promotion and to avoid any confusion about what type should be used in +a cast. It is easy to check the casts against the formats to ensure +that they correspond. _`.types.cast`: Every argument to ``WriteF()`` must be cast, because in variable-length argument lists the "default argument promotion" @@ -154,7 +158,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/build.txt b/mps/manual/build.txt index 5403d7ffc44..7b8e17c51b9 100644 --- a/mps/manual/build.txt +++ b/mps/manual/build.txt @@ -96,8 +96,7 @@ Building the MPS for development If you're making modifications to the MPS itself, want to build MPS libraries for linking, or want to build MPS tests and tools, you should -use the MPS build. This uses makefiles or Xcode projects. [Coming -soon, Microsoft Visual Studio solutions.] +use the MPS build. This uses makefiles or Xcode projects. Prerequisites diff --git a/mps/manual/source/_templates/links.html b/mps/manual/source/_templates/links.html index b62c13d7813..b7263205f3e 100644 --- a/mps/manual/source/_templates/links.html +++ b/mps/manual/source/_templates/links.html @@ -1,13 +1,11 @@

Downloads

-MPS Kit release {{ release }}
All MPS Kit releases

Issues

-Known issues
-Issues fixed in release {{ release }} +All open issues

diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 2dd8d9d4207..b8da67a4333 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -7,14 +7,18 @@ Design :numbered: abq + an + bootstrap cbs config critical-path + exec-env failover freelist guide.hex.trans guide.impl.c.format guide.impl.c.naming + guide.review interface-c keyword-arguments land @@ -32,3 +36,4 @@ Design thread-manager type vm + writef diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index ee43ba7ae7c..8a8e71be1a6 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -41,7 +41,6 @@ Old design poolmv poolmvt poolmvff - protan protli protsu protocol @@ -61,4 +60,3 @@ Old design version vmo1 vmso - writef diff --git a/mps/manual/source/glossary/b.rst b/mps/manual/source/glossary/b.rst index 8356404267c..12d4838e466 100644 --- a/mps/manual/source/glossary/b.rst +++ b/mps/manual/source/glossary/b.rst @@ -182,9 +182,22 @@ Memory Management Glossary: B .. relevance:: Bitmaps are sometimes used to represent the marks in a - :term:`mark-sweep` collector, or the used memory in a - :term:`bitmapped fits` :term:`allocator`. + :term:`mark-sweep` collector (see :term:`bitmap marking`), + or the used memory in a :term:`bitmapped fits` + :term:`allocator`. + bitmap marking + + In :term:`mark-sweep` collectors, bitmap marking is a + technique for :term:`marking` objects that stores the mark + bits for the objects in a contiguous range of memory in a + separate :term:`bitmap`. This improves the collector's + :term:`locality of reference` and cache performance, because + it avoids setting the :term:`dirty bit` on the :term:`pages` + containing the marked objects. + + .. bibref:: :ref:`Zorn (1989) `. + bitmapped fit A class of :term:`allocation mechanisms` that use a diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index a0484b3c5ee..6c15cbd4e84 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -84,6 +84,7 @@ All :term:`bit table ` :term:`bit vector ` :term:`bitmap` +:term:`bitmap marking` :term:`bitmapped fit` :term:`bitmask` :term:`bitset ` diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst index db4d8b88a59..92abdcf2740 100644 --- a/mps/manual/source/glossary/m.rst +++ b/mps/manual/source/glossary/m.rst @@ -207,7 +207,11 @@ Memory Management Glossary: M though any conservative representation of a predicate on the :term:`memory location` of the object can be used. In particular, storing the mark bit within the object can lead to - poor :term:`locality of reference`. + poor :term:`locality of reference` and to poor cache + performance, because the marking phases ends up setting the + :term:`dirty bit` on all :term:`pages` in the :term:`working + set`. An alternative is to store the mark bits separately: + see :term:`bitmap marking`. .. seealso:: :term:`sweep `, :term:`compact `. diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst index 9f4449a930e..cbab9a255fe 100644 --- a/mps/manual/source/glossary/r.rst +++ b/mps/manual/source/glossary/r.rst @@ -39,7 +39,7 @@ Memory Management Glossary: R .. mps:specific:: A value of :c:type:`mps_rank_t` indicating whether a - :term:`root` is :term:`ambiguous ` + :term:`reference` is :term:`ambiguous ` (:c:func:`mps_rank_ambig`), :term:`exact ` (:c:func:`mps_rank_exact`) or :term:`weak ` (:c:func:`mps_rank_weak`). diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst index a7218dd2ba5..fd98e0481e5 100644 --- a/mps/manual/source/guide/index.rst +++ b/mps/manual/source/guide/index.rst @@ -13,4 +13,4 @@ Guide debug perf advanced - + malloc diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index 68473613ba2..88c7ec93eb5 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -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:: diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst new file mode 100644 index 00000000000..843fc2371ed --- /dev/null +++ b/mps/manual/source/guide/malloc.rst @@ -0,0 +1,70 @@ +.. 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 a block is +known statically based on its type (for example, a structure), or else +the size of the block 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. It's also better for virtual +memory performance, as a block does not have to be touched in order +to free it. + +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). In this situation you can implement this +interface using a global pool variable, and putting the size of each +block into its header, 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 ` pool class, for example :ref:`pool-mvff` (or its +:ref:`debugging counterpart `):: + + #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(); + } diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index 0562b9bce5a..a21594202c6 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -115,7 +115,7 @@ AMC interface method`, a :term:`forward method`, an :term:`is-forwarded method` and a :term:`padding method`. - It accepts four optional keyword arguments: + It accepts three optional keyword arguments: * :c:macro:`MPS_KEY_CHAIN` (type :c:type:`mps_chain_t`) specifies the :term:`generation chain` for the pool. If not specified, the @@ -128,8 +128,10 @@ AMC interface pointers` keep objects alive. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, - default 4096) is the default :term:`size` of block that the pool - will request from the :term:`arena`. + default 4096) is the minimum :term:`size` of the memory segments + that the pool requests from the :term:`arena`. Larger segments + reduce the per-segment overhead, but increase + :term:`fragmentation` and :term:`retention`. For example:: @@ -138,20 +140,12 @@ AMC interface res = mps_pool_create_k(&pool, arena, mps_class_amc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amc(), - mps_fmt_t fmt, - mps_chain_t chain) - .. index:: pair: AMC; introspection +.. _pool-amc-introspection: + AMC introspection ----------------- diff --git a/mps/manual/source/pool/amcz.rst b/mps/manual/source/pool/amcz.rst index 9993647d0db..4f65d205d1b 100644 --- a/mps/manual/source/pool/amcz.rst +++ b/mps/manual/source/pool/amcz.rst @@ -87,12 +87,11 @@ AMCZ interface res = mps_pool_create_k(&pool, arena, mps_class_amcz(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. + +.. index:: + pair: AMCZ; introspection - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: +AMCZ introspection +------------------ - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amcz(), - mps_fmt_t fmt, - mps_chain_t chain) +See :ref:`pool-amc-introspection`. diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst index 98da5eda587..4d66fdc0fc3 100644 --- a/mps/manual/source/pool/ams.rst +++ b/mps/manual/source/pool/ams.rst @@ -41,7 +41,8 @@ AMS properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AMS pool, the call to - :c:func:`mps_ap_create_k` takes no keyword arguments. + :c:func:`mps_ap_create_k` takes one optional keyword argument, + :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve the efficiency of stack-like allocation. @@ -137,19 +138,8 @@ AMS interface res = mps_pool_create_k(&pool, arena, mps_class_ams(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format, - chain, and ambiguous flag like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams(), - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) - When creating an :term:`allocation point` on an AMS pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of references @@ -166,13 +156,6 @@ AMS interface res = mps_ap_create_k(&ap, ams_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:function:: mps_pool_class_t mps_class_ams_debug(void) @@ -186,15 +169,3 @@ AMS interface :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams_debug(), - mps_pool_debug_option_s debug_option, - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst index e4437ebe5ee..63eca08635e 100644 --- a/mps/manual/source/pool/awl.rst +++ b/mps/manual/source/pool/awl.rst @@ -59,7 +59,7 @@ AWL properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AWL pool, the call to - :c:func:`mps_ap_create_k` accepts one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve @@ -350,18 +350,8 @@ AWL interface res = mps_pool_create_k(&pool, arena, mps_class_awl(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - find-dependent function like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_awl(), - mps_fmt_t fmt, - mps_awl_find_dependent_t find_dependent) - When creating an :term:`allocation point` on an AWL pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of @@ -378,13 +368,6 @@ AWL interface res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr) diff --git a/mps/manual/source/pool/lo.rst b/mps/manual/source/pool/lo.rst index edd784c1fe5..197e8b57138 100644 --- a/mps/manual/source/pool/lo.rst +++ b/mps/manual/source/pool/lo.rst @@ -136,12 +136,3 @@ LO interface MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); res = mps_pool_create_k(&pool, arena, mps_class_lo(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_lo(), - mps_fmt_t fmt) diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst index c4501d05c54..c1e13a5479d 100644 --- a/mps/manual/source/pool/mfs.rst +++ b/mps/manual/source/pool/mfs.rst @@ -87,7 +87,8 @@ MFS interface :term:`size` of blocks that will be allocated from this pool, in :term:`bytes (1)`. It must be at least one :term:`word`. - In addition, :c:func:`mps_pool_create_k` may take: + In addition, :c:func:`mps_pool_create_k` accepts one optional + keyword argument: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will @@ -103,13 +104,3 @@ MFS interface MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 1024 * 1024); res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size and - unit size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mfs(), - size_t extend_size, - size_t unit_size) diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 8561e96d7d1..27e691ed3af 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -7,10 +7,6 @@ MV (Manual Variable) ==================== -.. deprecated:: starting with version 1.111. - - :ref:`pool-mvff` or :ref:`pool-mvt` should be used instead. - **MV** is a general-purpose :term:`manually managed ` :term:`pool class` that manages :term:`blocks` of variable size. @@ -70,8 +66,8 @@ MV interface Return the :term:`pool class` for an MV (Manual Variable) :term:`pool`. - When creating an MV pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MV pool, :c:func:`mps_pool_create_k` takes four + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -105,17 +101,6 @@ MV interface res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size, - mean size, and maximum size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv(), - size_t extend_size, - size_t average_size, - mps_size_t maximum_size) - .. c:function:: mps_pool_class_t mps_class_mv_debug(void) @@ -123,49 +108,8 @@ MV interface class. When creating a debugging MV pool, :c:func:`mps_pool_create_k` - takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`, + takes five optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv_debug(), - mps_pool_debug_option_s debug_option, - mps_size_t extend_size, - mps_size_t average_size, - mps_size_t maximum_size) - - -.. index:: - pair: MV; introspection - -MV introspection ----------------- - -:: - - #include "mpscmv.h" - -.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) - - Return the total amount of free space in an MV pool. - - ``pool`` is the MV pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mv_size(mps_pool_t pool) - - Return the total size of an MV pool. - - ``pool`` is the MV pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 51252208719..04a7d48603d 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -102,8 +102,8 @@ MVFF interface Return the :term:`pool class` for an MVFF (Manual Variable First Fit) :term:`pool`. - When creating an MVFF pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MVFF pool, :c:func:`mps_pool_create_k` accepts + seven optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will request @@ -132,15 +132,15 @@ MVFF interface default false) determines whether new blocks are acquired at high addresses (if true), or at low addresses (if false). - * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`, - default false) determines whether to search for the highest - addressed free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type + :c:type:`mps_bool_t`, default false) determines whether to + search for the highest addressed free area (if true) or lowest + (if false) when allocating using :c:func:`mps_alloc`. - * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type :c:type:`mps_bool_t`, default - true) determines whether to allocate from the highest address in a - found free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type + :c:type:`mps_bool_t`, default true) determines whether to + allocate from the highest address in a found free area (if true) + or lowest (if false) when allocating using :c:func:`mps_alloc`. .. [#not-ap] @@ -150,12 +150,12 @@ MVFF interface They use a worst-fit policy in order to maximise the number of in-line allocations. - The defaults yield a a simple first-fit allocator. Specify + The defaults yield a a simple first-fit allocator. Specify :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` true, and :c:macro:`MPS_KEY_MVFF_FIRST_FIT` false to get a first-fit - allocator that works from the top of memory downwards. - Other combinations may be useful in special circumstances. + allocator that works from the top of memory downwards. Other + combinations may be useful in special circumstances. For example:: @@ -169,20 +169,6 @@ MVFF interface res = mps_pool_create_k(&pool, arena, mps_class_mvff(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff(), - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - .. c:function:: mps_pool_class_t mps_class_mvff_debug(void) @@ -190,55 +176,11 @@ MVFF interface class. When creating a debugging MVFF pool, :c:func:`mps_pool_create_k` - takes seven :term:`keyword arguments`. - - * :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, - :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff_debug(), - mps_pool_debug_option_s debug_option, - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - - -.. index:: - pair: MVFF; introspection - -MVFF introspection ------------------- - -:: - - #include "mpscmvff.h" - -.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvff_size(mps_pool_t pool) - - Return the total size of an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + accepts eight optional :term:`keyword arguments`: + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_SPARE`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index 18e738413b9..da2ce024baa 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -111,8 +111,8 @@ MVT interface Return the :term:`pool class` for an MVT (Manual Variable Temporal) :term:`pool`. - When creating an MVT pool, :c:func:`mps_pool_create_k` may take - six :term:`keyword arguments`: + When creating an MVT pool, :c:func:`mps_pool_create_k` accepts six + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -196,51 +196,3 @@ MVT interface MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.5); res = mps_pool_create_k(&pool, arena, mps_class_mvt(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvt(), - size_t minimum_size, - size_t mean_size, - size_t maximum_size, - mps_word_t reserve_depth, - mps_word_t fragmentation_limit) - - .. note:: - - The fragmentation_limit is a percentage from 0 to 100 - inclusive when passed to :c:func:`mps_pool_create`, not a - double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. - - -.. index:: - pair: MVT; introspection - -MVT introspection ------------------ - -:: - - #include "mpscmvt.h" - -.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvt_size(mps_pool_t pool) - - Return the total size of an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 2e82d055e7c..d39a392c614 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -39,7 +39,7 @@ SNC properties * Supports allocation via :term:`allocation points` only. If an allocation point is created in an SNC pool, the call to - :c:func:`mps_ap_create_k` requires one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Does not support deallocation via :c:func:`mps_free`. @@ -83,8 +83,8 @@ SNC properties .. index:: single: SNC; interface -SNC introspection ------------------ +SNC interface +------------- :: @@ -111,21 +111,12 @@ SNC introspection res = mps_pool_create_k(&pool, arena, mps_class_snc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_snc(), - mps_fmt_t fmt) - When creating an :term:`allocation point` on an SNC pool, - :c:func:`mps_ap_create_k` requires one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: - * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies - the :term:`rank` of references in objects allocated on this - allocation point. It must be :c:func:`mps_rank_exact`. + * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: @@ -133,10 +124,3 @@ SNC introspection MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_exact()); res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index fc9cc438c55..cb820397281 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -9,6 +9,15 @@ Release notes Release 1.115.0 --------------- +New features +............ + +#. When creating an :ref:`pool-amc` pool, :c:func:`mps_pool_create_k` + accepts the new keyword argument :c:macro:`MPS_KEY_EXTEND_BY`, + specifying the minimum size of the memory segments that the pool + requests from the :term:`arena`. + + Interface changes ................. @@ -16,6 +25,46 @@ Interface changes name :c:type:`mps_class_t` is still available via a ``typedef``, but is deprecated. +#. The functions :c:func:`mps_mv_free_size`, :c:func:`mps_mv_size`, + :c:func:`mps_mvff_free_size`, :c:func:`mps_mvff_size`, + :c:func:`mps_mvt_free_size` and :c:func:`mps_mvt_size` are now + deprecated in favour of the generic functions + :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`. + + +Other changes +............. + +#. :c:func:`mps_arena_committed` now returns a meaningful value (the + amount of memory marked as in use in the page tables) for + :term:`client arenas`. See job001887_. + + .. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/ + +#. :ref:`pool-amc` pools now assert that exact references into the + pool are aligned to the pool's alignment. See job002175_. + + .. _job002175: https://www.ravenbrook.com/project/mps/issue/job002175/ + +#. Internal calculation of the address space available to the MPS no + longer takes time proportional to the number of times the arena has + been extended, speeding up allocation when memory is tight. See + job003814_. + + .. _job003814: https://www.ravenbrook.com/project/mps/issue/job003814/ + +#. Setting :c:macro:`MPS_KEY_SPARE` for a :ref:`pool-mvff` pool now + works. See job003870_. + + .. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/ + +#. When the arena is out of memory and cannot be extended without + hitting the :term:`commit limit`, the MPS now returns + :c:macro:`MPS_RES_COMMIT_LIMIT` rather than substituting + :c:macro:`MPS_RES_RESOURCE`. See job003899_. + + .. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/ + .. _release-notes-1.114: @@ -57,8 +106,8 @@ New features generation sizes. (This is not necessary, but may improve performance.) -#. New pool introspection functions :c:func:`mps_pool_total_size` and - :c:func:`mps_pool_free_size`. +#. New pool introspection functions :c:func:`mps_pool_free_size` and + :c:func:`mps_pool_total_size`. Interface changes @@ -147,8 +196,8 @@ Other changes #. Allocation into :ref:`pool-awl` pools again reliably provokes garbage collections of the generation that the pool belongs to. (In - release 1.113.0, the generation would only be collected if a pool - of some other class allocated into it.) See job003772_. + version 1.113, the generation would only be collected if a pool of + some other class allocated into it.) See job003772_. .. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/ @@ -160,13 +209,21 @@ Other changes .. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/ #. The :ref:`pool-mvt` and :ref:`pool-mvff` pool classes are now - around 25% faster (in our benchmarks) than they were in release - 1.113.0. + around 25% faster (in our benchmarks) than they were in version + 1.113. -#. The default assertion handler in the ANSI plinth now flushes the - telemetry stream before aborting. See +#. The default assertion handler in the default :term:`plinth` now + flushes the telemetry stream before aborting. See :c:func:`mps_lib_assert_fail`. +#. Garbage collection performance is substantially improved in the + situation where the arena has been extended many times. Critical + operations now take time logarithmic in the number of times the + arena has been extended (rather than linear, as in version 1.113 + and earlier). See job003554_. + + .. _job003554: https://www.ravenbrook.com/project/mps/issue/job003554/ + .. _release-notes-1.113: @@ -278,8 +335,8 @@ Interface changes along indefinitely. See :ref:`topic-error-assertion-handling`. #. The behaviour when an assertion is triggered is now configurable in - the standard ANSI :term:`plinth` by installing an assertion - handler. See :c:func:`mps_lib_assert_fail_install`. + the default :term:`plinth` by installing an assertion handler. See + :c:func:`mps_lib_assert_fail_install`. #. Functions that take a variable number of arguments (:c:func:`mps_arena_create`, :c:func:`mps_pool_create`, @@ -437,3 +494,74 @@ Other changes later. See job003473_. .. _job003473: https://www.ravenbrook.com/project/mps/issue/job003473/ + + +.. _release-notes-1.110: + +Release 1.110.0 +--------------- + +New features +............ + +#. New supported platforms: + + * ``fri6gc`` (FreeBSD, x86-64, GCC) + * ``lii6gc`` (Linux, x86-64, GCC) + * ``w3i6mv`` (Windows, x86-64, Microsoft Visual C) + * ``xci3ll`` (OS X, IA-32, Clang/LLVM) + * ``xci6gc`` (OS X, x86-64, GCC) + * ``xci6ll`` (OS X, x86-64, Clang/LLVM) + +#. Support removed for platforms: + + * ``iam4cc`` (Irix 6, MIPS R4000, MIPSpro C) + * ``lii3eg`` (Linux, IA-32, EGCS) + * ``lippgc`` (Linux, PowerPC, GCC) + * ``o1alcc`` (OSF/1, Alpha, Digital C) + * ``o1algc`` (OSF/1, Alpha, GCC) + * ``s7ppmw`` (System 7, PowerPC, MetroWerks C) + * ``sos8gc`` (Solaris, SPARC 8, GCC) + * ``sos9sc`` (Solaris, SPARC 9, SunPro C) + * ``sus8gc`` (SunOS, SPARC 8, GCC) + * ``xcppgc`` (OS X, PowerPC, GCC) + +#. On Unix platforms, the MPS can now be built and installed by + running ``./configure && make install``. See :ref:`guide-build`. + +#. The MPS can be compiled in a single step via the new source file + ``mps.c``. This also allows you to compile the MPS in the same + compilation unit as your object format, allowing the compiler to + perform global optimizations between the two. See + :ref:`guide-build`. + +#. The set of build varieties has been reduced to three: the + :term:`cool` variety for development and debugging, the :term:`hot` + variety for production, and the :term:`rash` variety for people who + like to live dangerously. See :ref:`topic-error-variety`. + +#. The environment variable :envvar:`MPS_TELEMETRY_CONTROL` can now be + set to a space-separated list of event kinds. See + :ref:`topic-telemetry`. + +#. Telemetry output is now emitted to the file named by the + environment variable :envvar:`MPS_TELEMETRY_FILENAME`, if it is + set. See :ref:`topic-telemetry`. + + +Interface changes +................. + +#. Deprecated constants ``MPS_MESSAGE_TYPE_FINALIZATION``, + ``MPS_MESSAGE_TYPE_GC`` and ``MPS_MESSAGE_TYPE_GC_START`` have been + removed. Use :c:func:`mps_message_type_finalization`, + :c:func:`mps_message_type_gc` and + :c:func:`mps_message_type_gc_start` instead. + +#. Deprecated constants ``MPS_RANK_AMBIG``, ``MPS_RANK_EXACT`` and + ``MPS_RANK_WEAK`` have been removed. Use :c:func:`mps_rank_ambig`, + :c:func:`mps_rank_exact` and :c:func:`mps_rank_weak` instead. + +#. Deprecated functions with names starting ``mps_space_`` have been + removed. Use the functions with names starting ``mps_arena_`` + instead. diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 57e9c0d6548..4075cfe006a 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -120,31 +120,6 @@ many small objects. They must be used according to the point or points. -.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` variable argument list - mechanism. - - -.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_ap_destroy(mps_ap_t ap) Destroy an :term:`allocation point`. @@ -240,7 +215,8 @@ is thus:: size_t aligned_size = ALIGN(size); /* see note 1 */ do { mps_res_t res = mps_reserve(&p, ap, aligned_size); - if (res != MPS_RES_OK) /* handle the error */; + if (res != MPS_RES_OK) + /* handle the error */; /* p is now an ambiguous reference to the reserved block */ obj = p; /* initialize obj */ diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 04c537a79de..d33242e279d 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -92,32 +92,6 @@ the way that they acquire the memory to be managed. :c:func:`mps_arena_destroy`. -.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` ``va_list`` - mechanism. - - .. c:function:: void mps_arena_destroy(mps_arena_t arena) Destroy an :term:`arena`. @@ -192,15 +166,6 @@ Client arenas Client arenas have no mechanism for returning unused memory. - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size and base - address like this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t mps_arena_class_cl, - size_t size, mps_addr_t base) - .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -311,15 +276,6 @@ Virtual memory arenas res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size like - this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t arena_class_vm(), - size_t size) - .. index:: single: arena; properties @@ -391,9 +347,18 @@ Arena properties ``arena`` is the arena. - Returns the total amount of memory that has been committed to RAM + Returns the total amount of memory that has been committed for use by the MPS, in :term:`bytes (1)`. + For a :term:`virtual memory arena`, this is the amount of memory + mapped to RAM by the operating system's virtual memory interface. + + For a :term:`client arena`, this is the amount of memory marked as + in use in the arena's page tables. This is not particularly + meaningful by itself, but it corresponds to the amount of mapped + memory that the MPS would use if switched to a virtual memory + arena. + The committed memory is generally larger than the sum of the sizes of the allocated :term:`blocks`. The reasons for this are: @@ -420,10 +385,10 @@ Arena properties state>`). If it is called when the arena is in the unclamped state then the value may change after this function returns. A possible use might be to call it just after :c:func:`mps_arena_collect` to - (over-)estimate the size of the heap. + estimate the size of the heap. If you want to know how much memory the MPS is using then you're - probably interested in the value :c:func:`mps_arena_committed()` − + probably interested in the value :c:func:`mps_arena_committed` − :c:func:`mps_arena_spare_committed`. The amount of committed memory can be limited with the function @@ -447,12 +412,12 @@ Arena properties .. note:: - For a client arena, the reserved address may be lower than the - sum of the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument - passed to :c:func:`mps_arena_create_k` and the ``size`` - arguments passed to :c:func:`mps_arena_extend`, because the - arena may be unable to use the whole of each chunk for reasons - of alignment. + For a :term:`client arena`, the reserved address space may be + lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE` + keyword argument passed to :c:func:`mps_arena_create_k` and + the ``size`` arguments passed to :c:func:`mps_arena_extend`, + because the arena may be unable to use the whole of each chunk + for reasons of alignment. .. c:function:: size_t mps_arena_spare_commit_limit(mps_arena_t arena) @@ -517,6 +482,11 @@ Arena properties functions for limiting the amount of :term:`committed ` memory. + .. note:: + + :term:`Client arenas` do not use spare committed memory, and + so this function always returns 0. + .. index:: single: arena; states @@ -839,114 +809,3 @@ Arena introspection return storage to the operating system). For reliable results call this function and interpret the result while the arena is in the :term:`parked state`. - - -.. index:: - pair: arena; protection - -Protection interface --------------------- - -.. c:function:: void mps_arena_expose(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. - - ``mps_arena`` is the arena to expose. - - This is expected to only be useful for debugging. The arena is - left in the :term:`clamped state`. - - Since barriers are used during a collection, calling this function - has the same effect as calling :c:func:`mps_arena_park`: all - collections are run to completion, and the arena is clamped so - that no new collections begin. The MPS also uses barriers to - maintain :term:`remembered sets`, so calling this - function will effectively destroy the remembered sets and any - optimization gains from them. - - Calling this function is time-consuming: any active collections - will be run to completion; and the next collection will have to - recompute all the remembered sets by scanning the entire arena. - - The recomputation of the remembered sets can be avoided by calling - :c:func:`mps_arena_unsafe_expose_remember_protection` instead of - :c:func:`mps_arena_expose`, and by calling - :c:func:`mps_arena_unsafe_restore_protection` before calling - :c:func:`mps_arena_release`. Those functions have unsafe aspects - and place restrictions on what the :term:`client program` can do - (basically no exposed data can be changed). - - -.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. In addition, request the MPS to remember some parts of its - internal state so that they can be restored later. - - ``mps_arena`` is the arena to expose. - - This function is the same as :c:func:`mps_arena_expose`, but - additionally causes the MPS to remember its protection state. The - remembered protection state can optionally be restored later by - calling the :c:func:`mps_arena_unsafe_restore_protection` function. - This is an optimization that avoids the MPS having to recompute - all the remembered sets by scanning the entire arena. - - However, restoring the remembered protections is only safe if the - contents of the exposed pages have not been changed; therefore - this function should only be used if you do not intend to change - the pages, and the remembered protection must only be restored if - the pages have not been changed. - - The MPS will only remember the protection state if resources - (memory) are available. If memory is low then only some or - possibly none of the protection state will be remembered, with a - corresponding necessity to recompute it later. The MPS provides no - mechanism for the :term:`client program` to determine whether the - MPS has in fact remembered the protection state. - - The remembered protection state, if any, is discarded after - calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon - as the arena leaves the :term:`clamped state` by calling - :c:func:`mps_arena_release`. - - -.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Restore the remembered protection state for an :term:`arena`. - - ``mps_arena`` is the arena to restore the protection state for. - - This function restores the protection state that the MPS has - remembered when the :term:`client program` called - :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose - of remembering and restoring the protection state is to avoid the - need for the MPS to recompute all the :term:`remembered sets` by scanning the entire arena, that occurs when - :c:func:`mps_arena_expose` is used, and which causes the next - :term:`garbage collection` to be slow. - - The client program must not change the exposed data between the - call to :c:func:`mps_arena_unsafe_expose_remember_protection` and - :c:func:`mps_arena_unsafe_restore_protection`. If the client - program has changed the exposed data then - :c:func:`mps_arena_unsafe_restore_protection` must not be called: - in this case simply call :c:func:`mps_arena_release`. - - Calling this function does not release the arena from the clamped - state: :c:func:`mps_arena_release` must be called to continue - normal collections. - - Calling this function causes the MPS to forget the remember - protection state; as a consequence the same remembered state - cannot be restored more than once. - - diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst new file mode 100644 index 00000000000..dfd4d8d74cb --- /dev/null +++ b/mps/manual/source/topic/deprecated.rst @@ -0,0 +1,745 @@ +.. index:: + single: deprecated interfaces + +.. _topic-deprecated: + +Deprecated interfaces +===================== + +This chapter documents the public symbols in the MPS interface that +are now deprecated. These symbols may be removed in any future release +(see :ref:`topic-interface-support` for details). If you are using one +of these symbols, then you should update your code to use the +supported interface. + +.. note:: + + If you are relying on a deprecated interface, and there is no + supported alternative, please :ref:`contact us `. It + makes a difference if we know that someone is using a feature. + + +.. index:: + single: deprecated interfaces; in version 1.115 + +Deprecated in version 1.115 +........................... + +.. c:type:: typedef mps_pool_class_t mps_class_t + + .. deprecated:: + + The former name for :c:type:`mps_pool_class_t`, chosen when + pools were the only objects in the MPS that belonged to + classes. + + +.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MV pool. + + ``pool`` is the MV pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mv_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MV pool. + + ``pool`` is the MV pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvff_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvt_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. index:: + single: deprecated interfaces; in version 1.113 + +Deprecated in version 1.113 +........................... + +.. c:function:: MPS_ARGS_DONE(args) + + .. deprecated:: + + Formerly this was used to finalize a list of :term:`keyword + arguments` before passing it to a function. It is no longer + needed. + + +.. index:: + single: deprecated interfaces; in version 1.112 + +Deprecated in version 1.112 +........................... + +.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating an arena of class :c:func:`mps_arena_class_cl`, pass + the values for the keyword arguments :c:macro:`MPS_KEY_ARENA_SIZE` + and :c:macro:`MPS_KEY_ARENA_CL_BASE` like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_cl(), + size_t arena_size, + mps_addr_t cl_base) + + When creating an arena of class :c:func:`mps_arena_class_vm`, pass + the value for the keyword argument :c:macro:`MPS_KEY_ARENA_SIZE` + like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_vm(), + size_t arena_size) + + +.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` ``va_list`` + mechanism. See :c:func:`mps_arena_create` for details of which + arguments to pass for the different arena classes. + + +.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating a pool of class :c:func:`mps_class_amc` or + :c:func:`mps_class_amcz`, pass the values for the keyword + arguments :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN` + like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_amc(), + mps_fmt_t format, + mps_chain_t chain) + + When creating a pool of class :c:func:`mps_class_ams`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and ambiguous flag + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams(), + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_ams_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams_debug(), + mps_pool_debug_option_s *pool_debug_options, + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_awl`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT` and + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_awl(), + mps_fmt_t format, + mps_awl_find_dependent_t awl_find_dependent) + + When creating a pool of class :c:func:`mps_class_lo`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_lo(), + mps_fmt_t format) + + When creating a pool of class :c:func:`mps_class_mfs`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY` and + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mfs(), + size_t extend_by, + size_t unit_size) + + When creating a pool of class :c:func:`mps_class_mv`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, and :c:macro:`MPS_KEY_MAX_SIZE` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv(), + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mv_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE` and + :c:macro:`MPS_KEY_MAX_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv_debug(), + mps_pool_debug_option_s *pool_debug_options, + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mvff`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_ALIGN`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff(), + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvff_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff_debug(), + mps_pool_debug_option_s *pool_debug_options, + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvt`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_MIN_SIZE`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE`, + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` and + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvt(), + size_t min_size, + size_t mean_size, + size_t max_size, + mps_word_t mvt_reserve_depth, + mps_word_t mvt_frag_limit) + + .. note:: + + The ``mvt_frag_limit`` is a percentage from 0 to 100 + inclusive when passed to :c:func:`mps_pool_create`, not a + double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. + + When creating a pool of class :c:func:`mps_class_snc`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_snc(), + mps_fmt_t format) + + +.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_pool_create` for details of which arguments to pass + for the different pool classes. + + +.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` variable argument list + mechanism. + + When creating an allocation point on a pool of class + :c:func:`mps_class_ams`, :c:func:`mps_class_ams_debug`, + :c:func:`mps_class_awl` or :c:func:`mps_class_snc`, pass the + keyword argument :c:macro:`MPS_KEY_RANK` like this:: + + mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, + mps_rank_t rank) + + +.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_ap_create` for details of which arguments to pass + for the different pool classes. + + +.. c:type:: mps_fmt_A_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant A. :: + + typedef struct mps_fmt_A_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_A_s; + + The fields of this structure correspond to the keyword arguments + to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not + used. In older versions of the MPS this was a *copy method* + that copied objects belonging to this format. + + +.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant A. + + +.. c:type:: mps_fmt_B_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant B. :: + + typedef struct mps_fmt_B_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + mps_fmt_class_t mps_class; + } mps_fmt_B_s; + + Variant B is the same as variant A except for the addition of the + ``mps_class`` method. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant B. + + +.. c:type:: mps_fmt_auto_header_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant auto-header. :: + + typedef struct mps_fmt_auto_header_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + size_t mps_headerSize; + } mps_fmt_auto_header_s; + + Variant auto-header is the same as variant A except for the + removal of the unused ``copy`` method, and the addition of the + ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant auto-header. + + +.. c:type:: mps_fmt_fixed_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant fixed. :: + + typedef struct mps_fmt_fixed_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_fixed_s; + + Variant fixed is the same as variant A except for the removal of + the unused ``copy`` method, and the lack of a ``skip`` method + (this is not needed because the objects are fixed in size). See + :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant fixed. + + +.. index:: + single: deprecated interfaces; in version 1.111 + +Deprecated in version 1.111 +........................... + +.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) + + .. deprecated:: + + Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. + + :term:`Fix` a :term:`reference`. + + This is a function equivalent to:: + + MPS_SCAN_BEGIN(ss); + res = MPS_FIX12(ss, ref_io); + MPS_SCAN_END(ss); + return res; + + Because :term:`scanning ` is an operation on the + :term:`critical path`, we recommend that you use + :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) + to ensure that the "stage 1 fix" is inlined. + + .. note:: + + If you call this between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to + ensure that the scan state is passed correctly. + + +.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) + + .. deprecated:: + + Use :c:func:`mps_telemetry_get`, + :c:func:`mps_telemetry_reset`, and :c:func:`mps_telemetry_set` + instead. + + Update and return the :term:`telemetry filter`. + + ``reset_mask`` is a :term:`bitmask` indicating the bits in the + telemetry filter that should be reset. + + ``flip_mask`` is a bitmask indicating the bits in the telemetry + filter whose value should be flipped after the resetting. + + Returns the previous value of the telemetry filter, prior to the + reset and the flip. + + The parameters ``reset_mask`` and ``flip_mask`` allow the + specification of any binary operation on the filter control. For + typical operations, the parameters should be set as follows: + + ============ ============== ============= + Operation ``reset_mask`` ``flip_mask`` + ============ ============== ============= + ``set(M)`` ``M`` ``M`` + ------------ -------------- ------------- + ``reset(M)`` ``M`` ``0`` + ------------ -------------- ------------- + ``flip(M)`` ``0`` ``M`` + ------------ -------------- ------------- + ``read()`` ``0`` ``0`` + ============ ============== ============= + + +.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + Call a function via the MPS trampoline. + + ``r_o`` points to a location that will store the result of calling + ``f``. + + ``f`` is the function to call. + + ``p`` and ``s`` are arguments that will be passed to ``f`` each + time it is called. This is intended to make it easy to pass, for + example, an array and its size as parameters. + + The MPS relies on :term:`barriers (1)` to protect memory + that is in an inconsistent state. On some operating systems, + barrier hits generate exceptions that have to be caught by a + handler that is on the stack. On these operating systems, any code + that uses memory managed by the MPS must be called from inside + such an exception handler, that is, inside a call to + :c:func:`mps_tramp`. + + If you have multiple threads that run code that uses memory + managed by the MPS, each thread must execute such code inside a + call to :c:func:`mps_tramp`. + + +.. index:: + single: trampoline + +.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + The type of a function called by :c:func:`mps_tramp`. + + ``p`` and ``s`` are the corresponding arguments that were passed + to :c:func:`mps_tramp`. + + +.. c:function:: void mps_arena_expose(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. + + ``arena`` is the arena to expose. + + This is expected to only be useful for debugging. The arena is + left in the :term:`clamped state`. + + Since barriers are used during a collection, calling this function + has the same effect as calling :c:func:`mps_arena_park`: all + collections are run to completion, and the arena is clamped so + that no new collections begin. The MPS also uses barriers to + maintain :term:`remembered sets`, so calling this + function will effectively destroy the remembered sets and any + optimization gains from them. + + Calling this function is time-consuming: any active collections + will be run to completion; and the next collection will have to + recompute all the remembered sets by scanning the entire arena. + + The recomputation of the remembered sets can be avoided by calling + :c:func:`mps_arena_unsafe_expose_remember_protection` instead of + :c:func:`mps_arena_expose`, and by calling + :c:func:`mps_arena_unsafe_restore_protection` before calling + :c:func:`mps_arena_release`. Those functions have unsafe aspects + and place restrictions on what the :term:`client program` can do + (basically no exposed data can be changed). + + +.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. In addition, request the MPS to remember some parts of its + internal state so that they can be restored later. + + ``arena`` is the arena to expose. + + This function is the same as :c:func:`mps_arena_expose`, but + additionally causes the MPS to remember its protection state. The + remembered protection state can optionally be restored later by + calling the :c:func:`mps_arena_unsafe_restore_protection` function. + This is an optimization that avoids the MPS having to recompute + all the remembered sets by scanning the entire arena. + + However, restoring the remembered protections is only safe if the + contents of the exposed pages have not been changed; therefore + this function should only be used if you do not intend to change + the pages, and the remembered protection must only be restored if + the pages have not been changed. + + The MPS will only remember the protection state if resources + (memory) are available. If memory is low then only some or + possibly none of the protection state will be remembered, with a + corresponding necessity to recompute it later. The MPS provides no + mechanism for the :term:`client program` to determine whether the + MPS has in fact remembered the protection state. + + The remembered protection state, if any, is discarded after + calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon + as the arena leaves the :term:`clamped state` by calling + :c:func:`mps_arena_release`. + + +.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Restore the remembered protection state for an :term:`arena`. + + ``arena`` is the arena to restore the protection state for. + + This function restores the protection state that the MPS has + remembered when the :term:`client program` called + :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose + of remembering and restoring the protection state is to avoid the + need for the MPS to recompute all the :term:`remembered sets` by + scanning the entire arena, that occurs when + :c:func:`mps_arena_expose` is used, and which causes the next + :term:`garbage collection` to be slow. + + The client program must not change the exposed data between the + call to :c:func:`mps_arena_unsafe_expose_remember_protection` and + :c:func:`mps_arena_unsafe_restore_protection`. If the client + program has changed the exposed data then + :c:func:`mps_arena_unsafe_restore_protection` must not be called: + in this case simply call :c:func:`mps_arena_release`. + + Calling this function does not release the arena from the clamped + state: :c:func:`mps_arena_release` must be called to continue + normal collections. + + Calling this function causes the MPS to forget the remembered + protection state; as a consequence the same remembered state + cannot be restored more than once. + diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 82efa2e5e3c..1120b868897 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -76,31 +76,28 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested without exceeding the :term:`commit limit`. - You need to deallocate something to make more space, or increase + You need to deallocate something or allow the :term:`garbage + collector` to reclaim something to make more space, or increase the commit limit by calling :c:func:`mps_arena_commit_limit_set`. .. c:macro:: MPS_RES_FAIL A :term:`result code` indicating that something went wrong that - does not fall under the description of any other result code. The - exact meaning depends on the function that returned this result - code. + does not fall under the description of any other result code. .. c:macro:: MPS_RES_IO A :term:`result code` indicating that an input/output error - occurred. The exact meaning depends on the function that returned - this result code. + occurred in the :term:`telemetry` system. .. c:macro:: MPS_RES_LIMIT A :term:`result code` indicating that an operation could not be completed as requested because of an internal limitation of the - MPS. The exact meaning depends on the function that returned this - result code. + MPS. .. c:macro:: MPS_RES_MEMORY @@ -109,7 +106,7 @@ Result codes completed because there wasn't enough memory available. You need to deallocate something or allow the :term:`garbage - collector` to reclaim something to free enough memory, or expand + collector` to reclaim something to free enough memory, or extend the :term:`arena` (if you're using an arena for which that does not happen automatically). @@ -140,27 +137,23 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested because an invalid parameter was passed to - the operation. The exact meaning depends on the function that - returned this result code. + the operation. .. c:macro:: MPS_RES_RESOURCE A :term:`result code` indicating that an operation could not be completed as requested because the MPS could not obtain a needed - resource. The resource in question depends on the operation. + resource. It can be returned when the MPS runs out of + :term:`address space`. If this happens, you need to reclaim memory + within your process (as for the result code + :c:macro:`MPS_RES_MEMORY`). Two special cases have their own result codes: when the MPS runs out of committed memory, it returns :c:macro:`MPS_RES_MEMORY`, and when it cannot proceed without exceeding the :term:`commit limit`, it returns :c:macro:`MPS_RES_COMMIT_LIMIT`. - This result code can be returned when the MPS runs out of - :term:`virtual memory`. If this happens, you need to reclaim - memory within your process (as for the result code - :c:macro:`MPS_RES_MEMORY`), or terminate other processes running - on the same machine. - .. c:macro:: MPS_RES_UNIMPL @@ -272,13 +265,49 @@ this documentation. :c:type:`mps_fmt_t` for this argument. +``global.c: RingIsSingle(&arena->chainRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`generation chains` belonging to the + arena. It is necessary to call :c:func:`mps_chain_destroy` first. + + +``global.c: RingIsSingle(&arena->formatRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`object formats` belonging to the arena. + It is necessary to call :c:func:`mps_fmt_destroy` first. + + +``global.c: RingIsSingle(&arena->rootRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`roots` belonging to the arena. + It is necessary to call :c:func:`mps_root_destroy` first. + + +``global.c: RingIsSingle(&arena->threadRing)`` + + The client program called :c:func:`mps_arena_destroy` without + deregistering all the :term:`threads` belonging to the arena. + It is necessary to call :c:func:`mps_thread_dereg` first. + + +``global.c: RingLength(&arenaGlobals->poolRing) == 5`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`pools` belonging to the arena. + It is necessary to call :c:func:`mps_pool_destroy` first. + + ``lockix.c: res == 0`` ``lockw3.c: lock->claims == 0`` The client program has made a re-entrant call into the MPS. Look - at the backtrace to see what it was. Common culprits are - :term:`format methods` and :term:`stepper functions`. + at the backtrace to see what it was. Common culprits are signal + handlers, assertion handlers, :term:`format methods`, and + :term:`stepper functions`. ``locus.c: chain->activeTraces == TraceSetEMPTY`` @@ -305,13 +334,19 @@ this documentation. condition? -``ring.c: ring->next == ring`` +``poolsnc.c: foundSeg`` - The client program destroyed an object without having destroyed - all the objects that it owns first. For example, it destroyed an - arena without first destroying all pools in that arena, or it - destroyed a pool without first destroying all allocation points - created on that pool. + The client program passed an incorrect ``frame`` argument to + :c:func:`mps_ap_frame_pop`. This argument must be the result from + a previous call to :c:func:`mps_ap_frame_push` on the same + allocation point. + + +``seg.c: gcseg->buffer == NULL`` + + The client program destroyed pool without first destroying all the + allocation points created on that pool. The allocation points must + be destroyed first. ``trace.c: ss->rank < RankEXACT`` @@ -320,7 +355,7 @@ this documentation. for finalization, and then continued to run the garbage collector. See :ref:`topic-finalization-cautions` under :ref:`topic-finalization`, which says, "You must destroy these - pools by following the “safe tear-down” procedure described under + pools by following the ‘safe tear-down’ procedure described under :c:func:`mps_pool_destroy`." @@ -330,22 +365,24 @@ this documentation. reference to an object that moved. See :ref:`topic-scanning-protocol`, which says, "If :c:func:`MPS_FIX2` returns :c:macro:`MPS_RES_OK`, it may have updated the reference. - If necessary, make sure that the updated reference is stored back - to the region being scanned." + Make sure that the updated reference is stored back to the region + being scanned." .. index:: single: error handling; varieties single: variety +.. _topic-error-variety: + Varieties --------- -The MPS has three behaviours with respect to internal checking and -:ref:`telemetry `, which need to be selected at -compile time, by defining one of the following preprocessor -constants. If none is specified then :c:macro:`CONFIG_VAR_HOT` is the -default. +The MPS has three *varieties* which have different levels of internal +checking and :ref:`telemetry `. The variety can be +selected at compile time, by defining one of the following +preprocessor constants. If none is specified then +:c:macro:`CONFIG_VAR_HOT` is the default. .. index:: @@ -354,7 +391,7 @@ default. .. c:macro:: CONFIG_VAR_COOL - The cool variety is intended for development and testing. + The *cool variety* is intended for development and testing. All functions check the consistency of their data structures and may assert, including functions on the :term:`critical path`. @@ -372,7 +409,7 @@ default. .. c:macro:: CONFIG_VAR_HOT - The hot variety is intended for production and deployment. + The *hot variety* is intended for production and deployment. Some functions check the consistency of their data structures and may assert, namely those not on the :term:`critical path`. However, @@ -389,7 +426,7 @@ default. .. c:macro:: CONFIG_VAR_RASH - The rash variety is intended for mature integrations, or for + The *rash variety* is intended for mature integrations, or for developers who like living dangerously. No functions check the consistency of their data structures and diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 9ed826b2ac2..7db5c8a1178 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -179,6 +179,20 @@ There are some cautions to be observed when using in-band headers: #. Not all :term:`pool classes` support objects with in-band headers. See the documentation for the pool class. +.. note:: + + A :term:`client program` that allocates objects with + :term:`in-band headers` has to make a choice about how to + represent references to those objects. It can represent them using + :term:`base pointers` (which is convenient for allocation, since + :c:func:`mps_reserve` returns a base pointer, but requires + decoding when scanning) or using :term:`client pointers` (which is + convenient for scanning, since the :term:`scan method` takes a + client pointer, but requires encoding on allocation). Either + approach will work, but :term:`client pointers` are normally the + better choice, since scanning is normally more + performance-critical than allocation. + .. index:: pair: object format; cautions @@ -221,9 +235,9 @@ Cautions #. Format methods must use no more than 64 words of stack space. This restriction is necessary to avoid stack overflow in the MPS; - see :mps:ref:`design.mps.sp` for details. If your application has - format methods that need more stack space than this, :ref:`contact - us `. + see :ref:`design-sp` for details. If your application has format + methods that need more stack space than this, :ref:`contact us + `. #. Format methods must not: @@ -535,137 +549,3 @@ Object format introspection c. memory not managed by the MPS; It must not access other memory managed by the MPS. - - -Obsolete interface ------------------- - -.. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more flexible and easier to understand. - -Formerly the only way to create object formats was to describe the -format in the form of a *format variant structure*. - -There are four format variants. - -* Variant A (:c:type:`mps_fmt_A_s`): for objects without - :term:`in-band headers`. - -* Variant B (:c:type:`mps_fmt_B_s`): as variant A, but with the - addition of a class method. - -* Variant auto-header (:c:type:`mps_fmt_auto_header_s`): for objects - with :term:`in-band headers`. - -* Variant fixed (:c:type:`mps_fmt_fixed_s`): for fixed-size objects. - -The client program creates an object format by construct a format -variant structure and then calling the appropriate ``mps_fmt_create_`` -function for the variant. The variant structure can then be disposed -of. - - -.. c:type:: mps_fmt_A_s - - The type of the structure used to create an :term:`object format` - of variant A. :: - - typedef struct mps_fmt_A_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_A_s; - - The fields of this structure correspond to the keyword arguments - to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not - used. In older versions of the MPS this was a *copy method* - that copied objects belonging to this format. - - -.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) - - Create an :term:`object format` based on a description of an - object format of variant A. - - -.. c:type:: mps_fmt_B_s - - The type of the structure used to create an :term:`object format` - of variant B. :: - - typedef struct mps_fmt_B_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - mps_fmt_class_t mps_class; - } mps_fmt_B_s; - - Variant B is the same as variant A except for the addition of the - ``mps_class`` method. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) - - Create an :term:`object format` based on a description of an - object format of variant B. - - -.. c:type:: mps_fmt_auto_header_s - - The type of the structure used to create an :term:`object format` - of variant auto-header. :: - - typedef struct mps_fmt_auto_header_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - size_t mps_headerSize; - } mps_fmt_auto_header_s; - - Variant auto-header is the same as variant A except for the - removal of the unused ``copy`` method, and the addition of the - ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) - - Create an :term:`object format` based on a description of an - object format of variant auto-header. - - -.. c:type:: mps_fmt_fixed_s - - The type of the structure used to create an :term:`object format` - of variant fixed. :: - - typedef struct mps_fmt_fixed_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_fixed_s; - - Variant fixed is the same as variant A except for the removal of - the unused ``copy`` method, and the lack of a ``skip`` method - (this is not needed because the objects are fixed in size). See - :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) - - Create an :term:`object format` based on a description of an - object format of variant fixed. diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst index 32f4a6bb494..3f2cb2863bf 100644 --- a/mps/manual/source/topic/index.rst +++ b/mps/manual/source/topic/index.rst @@ -29,3 +29,5 @@ Reference plinth platform porting + deprecated + diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index 54637557f60..e7715181836 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -35,6 +35,10 @@ Support policy a version in which the symbol (or reliance on some of its behaviour) is deprecated. + Symbols may be deprecated in their old place in the reference + manual, or they may be moved to the :ref:`topic-deprecated` + chapter. + .. note:: If you are relying on a feature and you see that it's @@ -204,7 +208,8 @@ Instead, we recommend this approach:: mps_addr_t p; struct foo *fp; res = mps_alloc(&p, pool, sizeof(struct foo)); - if(res) /* handle error case */; + if (res != MPS_RES_OK) + /* handle error case */; fp = p; This has defined behaviour because conversion from ``void *`` to any diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 25e18f2de4d..ac80333ba36 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -82,43 +82,43 @@ now :c:macro:`MPS_KEY_ARGS_END`. The type of :term:`keyword argument` keys. Must take one of the following values: - ======================================== ====================================================== ========================================================== - Keyword Type & field in ``arg.val`` See - ======================================== ====================================================== ========================================================== - :c:macro:`MPS_KEY_ARGS_END` *none* *see above* - :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` - :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` - :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` - :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` - :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` - :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` ``mps_pool_debug_options_s *`` ``pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` - :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` - ======================================== ====================================================== ========================================================== + ======================================== ========================================================= ========================================================== + Keyword Type & field in ``arg.val`` See + ======================================== ========================================================= ========================================================== + :c:macro:`MPS_KEY_ARGS_END` *none* *see above* + :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` + :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` + :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` + :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` + :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` + :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` + :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` + ======================================== ========================================================= ========================================================== .. c:function:: MPS_ARGS_BEGIN(args) @@ -192,11 +192,3 @@ now :c:macro:`MPS_KEY_ARGS_END`. ``args`` is the name of array that contains the keyword arguments. It must match the argument to the preceding call to :c:func:`MPS_ARGS_BEGIN`. - - -.. c:function:: MPS_ARGS_DONE(args) - - .. deprecated:: starting with version 1.113. - - Formerly this was used to finalize a list of keyword arguments - before passing it to a function. It is no longer needed. diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index 8f26f267d70..f771f6c1c31 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -262,6 +262,11 @@ Library module :c:func:`mps_lib_assert_fail_install`. For a discussion of the default behaviour, see :ref:`topic-error-assertion-handling`. + .. warning:: + + This function must not call any function in MPS, and it must + not access memory managed by the MPS. + .. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) This function customises the behaviour of the default assertion handler @@ -277,6 +282,11 @@ Library module Returns the previously installed handler. + .. warning:: + + The installed assertion handler must not call any function in + MPS, and it must not access memory managed by the MPS. + .. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *) The type of assertion handlers passed to and returned by diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst index 68ec8185f03..d1ffe56d45b 100644 --- a/mps/manual/source/topic/pool.rst +++ b/mps/manual/source/topic/pool.rst @@ -40,31 +40,6 @@ making it available for allocation. :c:func:`mps_pool_destroy`. -.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_pool_destroy(mps_pool_t pool) Destroy a :term:`pool`. @@ -83,12 +58,12 @@ making it available for allocation. .. warning:: - It is not safe to destroy an :term:`automatically managed - ` pool if it contains any objects + It is not safe to carry on running the :term:`garbage + collector` after destroying an :term:`automatically managed + ` pool that contains any objects that are :term:`reachable` from your roots, or any objects that have been registered for :term:`finalization` but not yet - finalized, and then to carry on running the :term:`garbage - collector`. + finalized. Our recommended approach is to destroy automatically managed pools just before destroying the arena, and then only while @@ -123,13 +98,6 @@ See the :ref:`pool` for a list of pool classes. The type of :term:`pool classes`. -.. c:type:: typedef mps_pool_class_t mps_class_t - - .. deprecated:: starting with version 1.115. - - The former name for ``mps_pool_class_t``, chosen when pools - were the only objects in the MPS that belonged to classes. - .. index:: pair: pool; introspection diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index b58663a48b7..600dd7138de 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -38,29 +38,10 @@ usable. See :ref:`design-lock` for the design, and ``lock.h`` for the interface. There are implementations for Linux in ``lockli.c``, - POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is a - generic implementation in ``lockan.c``, which cannot actually take - any locks and so only works for a single thread. + POSIX in ``lockix.c``, and Windows in ``lockw3.c``. -#. The **thread manager** module suspends and resumes :term:`threads`, - so that the MPS can gain exclusive access to :term:`memory (2)`, - and so that it can scan the :term:`registers` and :term:`control - stack` of suspended threads. - - See :ref:`design-thread-manager` for the design, and ``th.h`` for - the interface. There are implementations for POSIX in ``thix.c`` - plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in - ``thw3.c``. There is a generic implementation in ``than.c``, which - necessarily only supports a single thread. - -#. The **virtual mapping** module reserves :term:`address space` from - the operating system (and returns it), and :term:`maps ` - address space to :term:`main memory` (and unmaps it). - - See :ref:`design-vm` for the design, and ``vm.h`` for the - interface. There are implementations for POSIX in ``vmix.c``, and - Windows in ``vmw3.c``. There is a generic implementation in - ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. + There is a generic implementation in ``lockan.c``, which cannot + actually take any locks and so only works for a single thread. #. The **memory protection** module applies :term:`protection` to areas of :term:`memory (2)`, ensuring that attempts to read or @@ -70,10 +51,13 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. There is a generic implementation - in ``protan.c``, which can't provide memory protection, so it - forces memory to be scanned until that there is no further need to - protect it. + OS X using Mach in ``protxc.c``. + + There is a generic implementation in ``protan.c``, which can't + provide memory protection, so it forces memory to be scanned until + that there is no further need to protect it. This means it can't + support incremental collection, and has no control over pause + times. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection @@ -83,8 +67,10 @@ usable. See :ref:`design-prmc` for the design, and ``prot.h`` for the interface. There are implementations on Unix, Windows, and OS X for - IA-32 and x86-64. There is a generic implementation in - ``prmcan.c``, which can't provide these features. + IA-32 and x86-64. + + There is a generic implementation in ``prmcan.c``, which can't + provide these features, and so only supports a single thread. #. The **stack probe** module checks that there is enough space on the :term:`control stack` for the MPS to complete any operation that it @@ -93,8 +79,12 @@ usable. See :ref:`design-sp` for the design, and ``sp.h`` for the interface. There are implementations on Windows on IA-32 in - ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There is a generic - implementation in ``span.c``, which can't provide this feature. + ``spi3w3.c`` and x86-64 in ``spi6w3.c``. + + There is a generic implementation in ``span.c``, which can't + provide this feature, and so is only suitable for use with a client + program that does not handle stack overflow faults, or does not + call into the MPS from the handler. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. @@ -103,8 +93,34 @@ usable. interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in - ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``, - which calls :c:func:`setjmp` to spill the registers. + ``ssw3i6mv.c``. + + There is a generic implementation in ``ssan.c``, which calls + :c:func:`setjmp` to spill the registers and scans the whole jump + buffer, thus overscanning compared to a platform-specific + implementation. + +#. The **thread manager** module suspends and resumes :term:`threads`, + so that the MPS can gain exclusive access to :term:`memory (2)`, + and so that it can scan the :term:`registers` and :term:`control + stack` of suspended threads. + + See :ref:`design-thread-manager` for the design, and ``th.h`` for + the interface. There are implementations for POSIX in ``thix.c`` + plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in + ``thw3.c``. + + There is a generic implementation in ``than.c``, which necessarily + only supports a single thread. + +#. The **virtual mapping** module reserves :term:`address space` from + the operating system (and returns it), and :term:`maps ` + address space to :term:`main memory` (and unmaps it). + + See :ref:`design-vm` for the design, and ``vm.h`` for the + interface. There are implementations for POSIX in ``vmix.c``, and + Windows in ``vmw3.c``. There is a generic implementation in + ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. Platform detection @@ -185,15 +201,17 @@ Makefile -------- Add a makefile even if you expect to use an integrated development -environment like Visual Studio or Xcode. Makefiles make it easier to -carry out continuous integration and delivery. +environment (IDE) like Visual Studio or Xcode. Makefiles make it +easier to carry out continuous integration and delivery, and are less +likely to stop working because of incompatibilities between IDE +versions. -The makefile must be named ``osarct.gmk``, and must define ``PFM`` to -be the platform code, ``MPMPF`` to be the list of platform modules -(the same files included by ``mps.c``), and ``LIBS`` to be the linker -options for any libraries required by the test cases. Then it must -include the compiler-specific makefile and ``comm.gmk``. For example, -``lii6ll.gmk`` looks like this:: +On Unix platforms, the makefile must be named ``osarct.gmk``, and must +define ``PFM`` to be the platform code, ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``), and ``LIBS`` +to be the linker options for any libraries required by the test cases. +Then it must include the compiler-specific makefile and ``comm.gmk``. +For example, ``lii6ll.gmk`` looks like this:: PFM = lii6ll @@ -222,6 +240,29 @@ improve performance by compiling the MPS and their object format in the same compilation unit. These steps would be more complicated if the MPS required particular compilation options. +On Windows, the makefile must be named ``osarct.nmk``, and must define +``PFM`` to be the platform code, and ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``) in square +brackets. Then it must include the compiler-specific makefile and +``comm.nmk``. For example, ``w3i6mv.nmk`` looks like this:: + + PFM = w3i6mv + + MPMPF = \ + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6mv] \ + [thw3] \ + [thw3i6] \ + [vmw3] + + !INCLUDE mv.nmk + !INCLUDE comm.nmk + Porting strategy ---------------- @@ -230,15 +271,17 @@ Start the port by selecting existing implementations of the functional modules, using the generic implementations where nothing else will do. Then check that the "smoke tests" pass, by running:: - make -f osarct.gmk testrun + make -f osarct.gmk testrun # Unix + nmake /f osarct.nmk testrun # Windows -Most or all of the test cases should pass at this point (if you're +Most or all of the test cases should pass at this point. If you're using the generic threading implementation, then the multi-threaded -test cases ``amcssth`` and ``awlutth`` are expected to fail; and if -you're using the generic lock implementation, then the lock -utilization test case ``lockut`` is expected to fail). However, -performance will be very poor if you're using the generic memory -protection implementation. +test cases are expected to fail. If you're using the generic lock +implementation, then the lock utilization test case ``lockut`` is +expected to fail. If you're using the generic memory protection +implementation, all the tests that rely on incremental collection are +expected to fail. See ``tool/testcases.txt`` for a database of test +cases and the configurations in which they are expected to pass. Now that there is a working system to build on, porting the necessary modules to the new platform can be done incrementally. It's a good diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index ed9adbb045a..6b4c4a1d396 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -361,9 +361,9 @@ Scanning interface .. c:function:: MPS_FIX_CALL(ss, call) - Call a function from within a :term:`scan method`, between - :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, passing - the :term:`scan state` correctly. + Call a function to do some scanning, from within a :term:`scan + method`, between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, passing the :term:`scan state` correctly. ``ss`` is the scan state that was passed to the scan method. @@ -377,6 +377,9 @@ Scanning interface must wrap the call with :c:func:`MPS_FIX_CALL` to ensure that the scan state is passed correctly. + The function being called must use :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END` appropriately. + In example below, the scan method ``obj_scan`` fixes the object's ``left`` and ``right`` references, but delegates the scanning of references inside the object's ``data`` member to the function @@ -406,9 +409,11 @@ Scanning interface .. warning:: - Use of :c:func:`MPS_FIX_CALL` is best avoided, as it forces - values out of registers. The gains in simplicity of the code - need to be measured against the loss in performance. + Use of :c:func:`MPS_FIX_CALL` is best avoided, as it may + force values out of registers (depending on compiler + optimisations such as inlining). The gains in simplicity of + the code ought to be measured against the loss in + performance. .. index:: @@ -496,30 +501,3 @@ Fixing interface In the case where the scan method does not need to do anything between :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`, you can use the convenience macro :c:func:`MPS_FIX12`. - - -.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. - - :term:`Fix` a :term:`reference`. - - This is a function equivalent to:: - - MPS_SCAN_BEGIN(ss); - res = MPS_FIX12(ss, ref_io); - MPS_SCAN_END(ss); - return res; - - Because :term:`scanning ` is an operation on the - :term:`critical path`, we recommend that you use - :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) - to ensure that the "stage 1 fix" is inlined. - - .. note:: - - If you call this between :c:func:`MPS_SCAN_BEGIN` and - :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to - ensure that the scan state is passed correctly. diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 4dc6d8d89a7..e25e71e4c59 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -388,41 +388,6 @@ further analysis by running :program:`mpseventsql`. Telemetry interface ------------------- -.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`mps_telemetry_get`, :c:func:`mps_telemetry_reset`, - and :c:func:`mps_telemetry_set` instead. - - Update and return the :term:`telemetry filter`. - - ``reset_mask`` is a :term:`bitmask` indicating the bits in the - telemetry filter that should be reset. - - ``flip_mask`` is a bitmask indicating the bits in the telemetry - filter whose value should be flipped after the resetting. - - Returns the previous value of the telemetry filter, prior to the - reset and the flip. - - The parameters ``reset_mask`` and ``flip_mask`` allow the - specification of any binary operation on the filter control. For - typical operations, the parameters should be set as follows: - - ============ ============== ============= - Operation ``reset_mask`` ``flip_mask`` - ============ ============== ============= - ``set(M)`` ``M`` ``M`` - ------------ -------------- ------------- - ``reset(M)`` ``M`` ``0`` - ------------ -------------- ------------- - ``flip(M)`` ``0`` ``M`` - ------------ -------------- ------------- - ``read()`` ``0`` ``0`` - ============ ============== ============= - - .. c:function:: void mps_telemetry_flush(void) Flush the internal event buffers into the :term:`telemetry stream`. diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index 0a4156613ac..9417c473b04 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -168,47 +168,3 @@ Thread interface It is recommended that threads be deregistered only when they are just about to exit. - - -.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - Call a function via the MPS trampoline. - - ``r_o`` points to a location that will store the result of calling - ``f``. - - ``f`` is the function to call. - - ``p`` and ``s`` are arguments that will be passed to ``f`` each - time it is called. This is intended to make it easy to pass, for - example, an array and its size as parameters. - - The MPS relies on :term:`barriers (1)` to protect memory - that is in an inconsistent state. On some operating systems, - barrier hits generate exceptions that have to be caught by a - handler that is on the stack. On these operating systems, any code - that uses memory managed by the MPS must be called from inside - such an exception handler, that is, inside a call to - :c:func:`mps_tramp`. - - If you have multiple threads that run code that uses memory - managed by the MPS, each thread must execute such code inside a - call to :c:func:`mps_tramp`. - - Starting with version 1.111, this is not required on any operating - system supported by the MPS. - - -.. index:: - single: trampoline - -.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - The type of a function called by :c:func:`mps_tramp`. - - ``p`` and ``s`` are the corresponding arguments that were passed - to :c:func:`mps_tramp`. diff --git a/mps/test/README b/mps/test/README index 08f3f398c36..90edaf8857f 100644 --- a/mps/test/README +++ b/mps/test/README @@ -11,18 +11,19 @@ Testing on unix From the test directory:: - $ PLATFORM=lii6ll # substitute your platform - $ CODE=../code # code directory of the branch you are testing - $ make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o - $ alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" - $ qa clib - $ qa run function/5.c - $ qa runset testsets/passing + PLATFORM=lii6ll # substitute your platform + CODE=../code # code directory of the branch you are testing + make -B -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" + qa clib + qa run function/5.c + qa runset testsets/passing Each test case is compiled in its turn to the file ``test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` so you can debug it with:: - $ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test + lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test -(Or ``gdb`` instead of ``lldb``.) +Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler, +so you'll probably want to set a breakpoint on mmqa_assert_handler. diff --git a/mps/test/argerr/111.c b/mps/test/argerr/111.c index cba3b7feda8..6f60b0a3269 100644 --- a/mps/test/argerr/111.c +++ b/mps/test/argerr/111.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED base for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = AddrIsAligned(base, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/143.c b/mps/test/argerr/143.c index 045b8d89893..9099a6c3c13 100644 --- a/mps/test/argerr/143.c +++ b/mps/test/argerr/143.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED stackpointer for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = AddrIsAligned(reg_scan_p, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c index a2fd7d76910..c6d465671eb 100644 --- a/mps/test/argerr/146.c +++ b/mps/test/argerr/146.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,9 +483,20 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } + mps_arena_collect(arena); + + mps_ap_destroy(ap); + mps_pool_destroy(pool); + mps_chain_destroy(chain); + mps_fmt_destroy(format); + mps_root_destroy(root); + mps_thread_dereg(thread); + mps_arena_destroy(arena); } int main(void) diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c index ecb781e5e39..0b11507cc81 100644 --- a/mps/test/argerr/147.c +++ b/mps/test/argerr/147.c @@ -4,6 +4,8 @@ TEST_HEADER summary = unaligned scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c index b1ec5cbdd0f..814429c1cdb 100644 --- a/mps/test/argerr/148.c +++ b/mps/test/argerr/148.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null addr to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/149.c b/mps/test/argerr/149.c index 422043e8cef..c86d9ce3983 100644 --- a/mps/test/argerr/149.c +++ b/mps/test/argerr/149.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/150.c b/mps/test/argerr/150.c index 4be2075aa0e..88d751f5d4a 100644 --- a/mps/test/argerr/150.c +++ b/mps/test/argerr/150.c @@ -449,7 +449,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +481,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/151.c b/mps/test/argerr/151.c index 6541675947b..19ed2169a93 100644 --- a/mps/test/argerr/151.c +++ b/mps/test/argerr/151.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/35.c b/mps/test/argerr/35.c index 4508eac3bff..218721759bf 100644 --- a/mps/test/argerr/35.c +++ b/mps/test/argerr/35.c @@ -6,7 +6,7 @@ TEST_HEADER link = testlib.o OUTPUT_SPEC assert = true - assertfile P= poolmv.c + assertfile P= pool.c assertcond = AddrIsAligned(old, pool->alignment) END_HEADER */ diff --git a/mps/test/argerr/36.c b/mps/test/argerr/36.c index 8704bc1dc2b..ac35d796cac 100644 --- a/mps/test/argerr/36.c +++ b/mps/test/argerr/36.c @@ -4,6 +4,10 @@ TEST_HEADER summary = wrong size_t to free (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= dbgpool.c + assertcond = tag->size == size END_HEADER */ @@ -25,11 +29,8 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie( - mps_pool_create( - &pool, arena, mps_class_mv(), - (size_t) 4096, (size_t) 32, (size_t) 64*1024), - "create pool"); + cdie(mps_pool_create_k(&pool, arena, mps_class_mv_debug(), mps_args_none), + "create pool"); die(mps_alloc(&a, pool, 8), "alloc a"); diff --git a/mps/test/conerr/22.c b/mps/test/conerr/22.c index aa371bd68b6..fb020003628 100644 --- a/mps/test/conerr/22.c +++ b/mps/test/conerr/22.c @@ -22,7 +22,7 @@ static void test(void) size_t avgSize; size_t maxSize; - mps_addr_t obj = (mps_addr_t)1; + mps_addr_t obj = (mps_addr_t)MPS_PF_ALIGN; extendBy = (size_t) 4096; avgSize = (size_t) 32; diff --git a/mps/test/conerr/26.c b/mps/test/conerr/26.c index 7114c056fc8..8fcabc44357 100644 --- a/mps/test/conerr/26.c +++ b/mps/test/conerr/26.c @@ -26,7 +26,7 @@ static void test(void) cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none), "create pool 0"); - cdie(mps_pool_create(&pool1, arena, mps_class_mv(), mps_args_none), + cdie(mps_pool_create_k(&pool1, arena, mps_class_mv(), mps_args_none), "create pool 1"); cdie(mps_alloc(&obj, pool0, 152), "allocate in 0"); diff --git a/mps/test/conerr/3.c b/mps/test/conerr/3.c index 85f340a5f5b..dae5b202009 100644 --- a/mps/test/conerr/3.c +++ b/mps/test/conerr/3.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = destroy an arena which isn't an arena, with a pointer in + summary = destroy an arena which isn't an arena language = c link = testlib.o OUTPUT_SPEC @@ -11,13 +11,15 @@ OUTPUT_SPEC END_HEADER */ +#include "mpmst.h" #include "testlib.h" static void test(void) { + char buf[sizeof(ArenaStruct)]; mps_arena_t arena; - arena = (mps_arena_t)&arena; + arena = (void *)buf; mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/function/103.c b/mps/test/function/103.c index fc4a7fa160a..07a77bf2470 100644 --- a/mps/test/function/103.c +++ b/mps/test/function/103.c @@ -32,7 +32,9 @@ static void fillup(void) mps_addr_t a; char *b; - mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64); + die(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)64, (size_t)64, (size_t)64), + "mps_pool_create"); size=1024ul*1024ul; while (size) { while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) { diff --git a/mps/test/function/120.c b/mps/test/function/120.c index 915965094c0..4bd55205998 100644 --- a/mps/test/function/120.c +++ b/mps/test/function/120.c @@ -27,7 +27,7 @@ void *stackpointer; mps_arena_t arena; mps_thr_t thread; mps_pool_t pool; -mps_pool_t pools[100]; +mps_pool_t pools[1000]; static void test(void) { int i; @@ -100,13 +100,17 @@ static void test(void) { i = 0; - while ((i < 100) && (res == MPS_RES_OK)) { + while (i < sizeof pools / sizeof pools[0]) { res = mps_pool_create(&pools[i], arena, mps_class_mv(), (size_t) 64, (size_t) 64, (size_t) 64); - i++; + if (res == MPS_RES_OK) { + i++; + } else { + break; + } } report_res("poolcr", res); - for (i -= 2; i >= 0; i--) { + for (i--; i >= 0; i--) { mps_pool_destroy(pools[i]); } diff --git a/mps/test/function/121.c b/mps/test/function/121.c index 263fa705594..c5780e23ee7 100644 --- a/mps/test/function/121.c +++ b/mps/test/function/121.c @@ -11,50 +11,56 @@ END_HEADER #include "testlib.h" #include "mpsavm.h" -#include "mpscmv.h" - - -void *stackpointer; +#include "mpsacl.h" mps_arena_t arena; -mps_thr_t thread; -mps_pool_t pool; -mps_pool_t pools[100]; +static char buffer[1024 * 1024]; static void test(void) { + mps_res_t res, prev_res = MPS_RES_OK; int i; - for (i = 64; i >= 0; i--) { - mps_res_t res; + + /* VM arenas round up small sizes and so creation must succeed. */ + for (i = 1024; i >= 0; i -= i/17 + 1) { + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i); + die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), + "mps_arena_create"); + } MPS_ARGS_END(args); + mps_arena_destroy(arena); + } - comment("Trying arena of %d kB.", i); - res = mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*i)); + /* Client arenas have to work within the memory they are given and + * so must fail at some point. */ + for (i = 1024; i >= 0; i -= i/17 + 1) { + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, buffer); + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i); + res = mps_arena_create_k(&arena, mps_arena_class_cl(), args); + } MPS_ARGS_END(args); if (res == MPS_RES_OK) { - res = mps_thread_reg(&thread, arena); - if (res == MPS_RES_OK) { - mps_thread_dereg(thread); - } else { - if (res != MPS_RES_MEMORY) { - error("Wrong error code, %d, for mps_thread_reg.", res); - } + if (prev_res != MPS_RES_OK) { + error("Success with smaller size."); } mps_arena_destroy(arena); } else { - report_res("arena_create", res); if (res != MPS_RES_MEMORY) { + report_res("arena_create", res); error("Wrong error code."); } } + prev_res = res; + } + if (res != MPS_RES_MEMORY) { + error("Wrong error code."); } } int main(void) { - void *m; - stackpointer=&m; /* hack to get stack pointer */ - easy_tramp(test); pass(); return 0; diff --git a/mps/test/function/137.c b/mps/test/function/137.c index 178d2f5e628..715dae9b4c8 100644 --- a/mps/test/function/137.c +++ b/mps/test/function/137.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/139.c b/mps/test/function/139.c index 14537004366..3ba3c2a3395 100644 --- a/mps/test/function/139.c +++ b/mps/test/function/139.c @@ -43,10 +43,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/144.c b/mps/test/function/144.c index efbcf4d9d29..4343be93fea 100644 --- a/mps/test/function/144.c +++ b/mps/test/function/144.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); die(mps_alloc(&b, pool, 64), "alloc b"); diff --git a/mps/test/function/150.c b/mps/test/function/150.c index 78eec6b2647..c8496f3d662 100644 --- a/mps/test/function/150.c +++ b/mps/test/function/150.c @@ -195,13 +195,12 @@ static void test(void) /* register loads of objects for finalization (1000*4) */ a = allocone(apamc, 2, 1); - b = a; for (j=0; j<1000; j++) { - a = allocone(apamc, 2, mps_rank_exact()); + b = allocone(apamc, 2, mps_rank_exact()); c = allocone(apawl, 2, mps_rank_weak()); d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */ - mps_finalize(arena, (mps_addr_t*)&a); + mps_finalize(arena, (mps_addr_t*)&b); mps_finalize(arena, (mps_addr_t*)&c); mps_finalize(arena, (mps_addr_t*)&d); mps_finalize(arena, (mps_addr_t*)&d); @@ -209,7 +208,7 @@ static void test(void) setref(a, 0, b); setref(a, 1, c); setref(c, 1, d); - b = a; + a = b; } /* throw them all away and collect everything */ diff --git a/mps/test/function/158.c b/mps/test/function/158.c index b257d879f30..7f54823d1db 100644 --- a/mps/test/function/158.c +++ b/mps/test/function/158.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 1, 0, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)1, (mps_bool_t)0, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/159.c b/mps/test/function/159.c index d3fb350003f..987824dd737 100644 --- a/mps/test/function/159.c +++ b/mps/test/function/159.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 1, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)1, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/160.c b/mps/test/function/160.c index 4c58a5058aa..af5b017e2a7 100644 --- a/mps/test/function/160.c +++ b/mps/test/function/160.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MV pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/161.c b/mps/test/function/161.c index 93ede5ed738..23a0fb8be14 100644 --- a/mps/test/function/161.c +++ b/mps/test/function/161.c @@ -32,10 +32,9 @@ static void test(void) (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/162.c b/mps/test/function/162.c index 05245b7191c..8967b95b269 100644 --- a/mps/test/function/162.c +++ b/mps/test/function/162.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/163.c b/mps/test/function/163.c index 90e04b83b23..9b735a076fa 100644 --- a/mps/test/function/163.c +++ b/mps/test/function/163.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, MPS_PF_ALIGN, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)MPS_PF_ALIGN, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/18.c b/mps/test/function/18.c index 60a17e52d57..45f1a0fe8cc 100644 --- a/mps/test/function/18.c +++ b/mps/test/function/18.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o newfmt.o OUTPUT_SPEC - errtext = create pool: COMMIT_LIMIT + errtext = create AMC pool: COMMIT_LIMIT END_HEADER */ @@ -48,8 +48,8 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); do { res = mps_alloc(&q, pool, 64*1024); @@ -60,7 +60,7 @@ static void test(void) while (1) { p++; die(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); report("pool", "%i", p); } diff --git a/mps/test/function/19.c b/mps/test/function/19.c index bdbe02f88f8..15fdecd9018 100644 --- a/mps/test/function/19.c +++ b/mps/test/function/19.c @@ -49,14 +49,14 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p = 0; cdie(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); while (1) { p++; diff --git a/mps/test/function/20.c b/mps/test/function/20.c index b66f96d4e67..3cec79e7df3 100644 --- a/mps/test/function/20.c +++ b/mps/test/function/20.c @@ -33,7 +33,8 @@ static void test(void) { mps_stack_scan_ambig, stackpointer, 0), "create root"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p=0; diff --git a/mps/test/function/21.c b/mps/test/function/21.c index d7e12e266ff..7b493f6602f 100644 --- a/mps/test/function/21.c +++ b/mps/test/function/21.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); for (p=0; p<2000; p++) { die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/22.c b/mps/test/function/22.c index cbdaa909898..8927643e49f 100644 --- a/mps/test/function/22.c +++ b/mps/test/function/22.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/224.c b/mps/test/function/224.c index 0cec33e1cd8..ec828bd9026 100644 --- a/mps/test/function/224.c +++ b/mps/test/function/224.c @@ -32,7 +32,7 @@ static void test(void) die(mps_arena_commit_limit_set(arena, VMSIZE), "commit limit"); die(mps_pool_create(&pool, arena, mps_class_mv(), - EXTENDBY, AVGSIZE, EXTENDBY), + (size_t)EXTENDBY, (size_t)AVGSIZE, (size_t)EXTENDBY), "pool create"); for (p=0; psize = 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; +} diff --git a/mps/test/function/23.c b/mps/test/function/23.c index afcf764a059..2046aa56b92 100644 --- a/mps/test/function/23.c +++ b/mps/test/function/23.c @@ -19,7 +19,9 @@ END_HEADER #include "mpsavm.h" #include "newfmt.h" - +#define EXTEND_BY ((size_t)(1024*128)) +#define MEAN_SIZE ((size_t)(1024*64)) +#define MAX_SIZE ((size_t)(1024*1024)) #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { @@ -66,7 +68,7 @@ static void test(void) comment("Sizes in megabytes:"); die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i = 0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; @@ -76,7 +78,7 @@ static void test(void) mps_pool_destroy(poolMV); die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i = 0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; @@ -88,7 +90,7 @@ static void test(void) a = allocdumb(ap, 1024*1024*30); /* allocate 30 M object */ die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i=0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; diff --git a/mps/test/function/96.c b/mps/test/function/96.c index 210fbf46542..6504674cf41 100644 --- a/mps/test/function/96.c +++ b/mps/test/function/96.c @@ -32,7 +32,9 @@ static void fillup(void) mps_addr_t a; char *b; - mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64); + die(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)64, (size_t)64, (size_t)64), + "create MV pool"); size=1024ul*1024ul; while (size) { while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) { @@ -116,7 +118,9 @@ static void test(void) for (j=0; j<1000*1024; j++) { res=allocrdumb(&a, ap, 1024, mps_rank_exact()); if (res == MPS_RES_OK) { - comment("%i ok", j); + if (j % 100000 == 0) { + comment("%i ok", j); + } } else { break; } diff --git a/mps/test/test/script/clib b/mps/test/test/script/clib index be1a45c4fb3..6552a20b3b7 100644 --- a/mps/test/test/script/clib +++ b/mps/test/test/script/clib @@ -22,7 +22,7 @@ sub clib { while (defined($tlfile = )) { unless ($tlfile =~ /^%/) { - chop($tlfile); + chomp($tlfile); $tlfile = $testlib_dir."/".$tlfile; $tlobj = $tlfile; $tlobj =~ s/\.c/$obj_suffix/; @@ -326,7 +326,7 @@ sub readSymbols { } while () { - chop; + chomp; if (/#define MMQA_SYMBOL_(.*)$/) { $mps_symbols{$1} = 1; } elsif (/#define MMQA_DEFINED_(.*)$/) { @@ -340,7 +340,7 @@ sub readSymbols { } while () { - chop; + chomp; unless (/^%/) { $mps_assumed{$_} = 1; } diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index 8f5c35ca7b6..794027763b2 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -48,7 +48,7 @@ sub readheader { $line = $_; while (! /END_HEADER/) { defined($_=) || die "Couldn't find end of test header in $infile.\n"; - chop; + chomp; if ($line =~ /\\$/) { chop($line); $line = $line.$_; diff --git a/mps/test/test/script/options b/mps/test/test/script/options index 023b1f5c7ae..5ef905a09fb 100644 --- a/mps/test/test/script/options +++ b/mps/test/test/script/options @@ -26,7 +26,7 @@ sub platform_detect { local $os = `uname`; local $osrel = `uname -r`; local $processor = `uname -p`; - chop($os); chop($osrel); chop($processor); + chomp($os); chomp($osrel); chomp($processor); $platform_class = $os."_".$osrel."_".$processor; $platform_class =~ s/ /_/g; $platform_phylum = "unix"; diff --git a/mps/test/test/script/runtest b/mps/test/test/script/runtest index b540843eab4..64269c4382d 100644 --- a/mps/test/test/script/runtest +++ b/mps/test/test/script/runtest @@ -241,7 +241,7 @@ sub run_testset { } else { while () { unless (/(^%)|(^\s*$)/) { - chop; + chomp; &run_from_testset($_); } } diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr index cfea284dfd7..990040192b4 100644 --- a/mps/test/testsets/argerr +++ b/mps/test/testsets/argerr @@ -80,14 +80,14 @@ argerr/78.c argerr/79.c argerr/80.c argerr/81.c -argerr/82.c -argerr/83.c +% argerr/82.c -- see +% argerr/83.c -- see argerr/84.c argerr/85.c argerr/86.c argerr/87.c -argerr/88.c -argerr/89.c +% argerr/88.c -- see +% argerr/89.c -- see argerr/90.c argerr/91.c argerr/92.c @@ -111,7 +111,7 @@ argerr/109.c argerr/110.c argerr/111.c argerr/112.c -argerr/113.c +% argerr/113.c -- last argument to mps_root_create_table is count, not size argerr/114.c argerr/115.c argerr/116.c @@ -124,9 +124,9 @@ argerr/122.c argerr/123.c argerr/124.c argerr/125.c -argerr/126.c +% argerr/126.c -- see argerr/127.c -argerr/128.c +% argerr/128.c -- see argerr/129.c argerr/130.c argerr/131.c @@ -147,9 +147,9 @@ argerr/145.c argerr/146.c argerr/147.c argerr/148.c -argerr/149.c -argerr/150.c -argerr/151.c -argerr/152.c +% argerr/149.c -- you're allowed to fix non-references +% argerr/150.c -- you're allowed to fix non-references +% argerr/151.c -- you're allowed to fix unaligned references +% argerr/152.c -- no way to check this argerr/153.c argerr/154.c diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr index 3f108a9cb0f..12966b681a0 100644 --- a/mps/test/testsets/conerr +++ b/mps/test/testsets/conerr @@ -10,7 +10,7 @@ conerr/8.c conerr/9.c conerr/10.c conerr/11.c -conerr/12.c +% conerr/12.c -- job003889 conerr/13.c conerr/14.c conerr/15.c @@ -31,17 +31,17 @@ conerr/29.c conerr/30.c conerr/31.c conerr/32.c -conerr/33.c +% conerr/33.c -- job003791 conerr/34.c conerr/35.c conerr/36.c -conerr/37.c +% conerr/37.c -- reserve/commit macros don't check arguments conerr/37f.c -conerr/38.c +% conerr/38.c -- reserve/commit macros don't check arguments conerr/38f.c -conerr/39.c +% conerr/39.c -- reserve/commit macros don't check arguments conerr/39f.c -conerr/40.c +% conerr/40.c -- reserve/commit macros don't check arguments conerr/40f.c conerr/41.c conerr/42.c @@ -52,7 +52,7 @@ conerr/45.c conerr/46.c conerr/47.c conerr/48.c -conerr/49.c +% conerr/49.c -- see design.mps.thread-manager.req.register.multi conerr/50.c conerr/51.c conerr/52.c @@ -60,6 +60,6 @@ conerr/53.c conerr/54.c conerr/55.c conerr/56.c -conerr/57.c -conerr/58.c +% conerr/57.c -- see +% conerr/58.c -- see conerr/59.c diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index bf298aae0b2..fde2ca5de8d 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -167,3 +167,5 @@ function/223.c function/224.c % 225 -- no such test function/226.c +function/227.c +function/229.c \ No newline at end of file diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 2aaf8aa4956..5e9c0606ab7 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -35,11 +35,11 @@ mkdir %LOGDIR% @rem Determine which tests to run. set EXCLUDE= -if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX -if "%TESTSUITE%"=="testci" set EXCLUDE=BNX -if "%TESTSUITE%"=="testall" set EXCLUDE=NX -if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX -if "%TESTSUITE%"=="testpoll" set EXCLUDE=LNPTX +if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX +if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX +if "%TESTSUITE%"=="testpollnone" set EXCLUDE=LNPTX @rem Ensure that test cases don't pop up dialog box on abort() set MPS_TESTLIB_NOABORT=true diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index cdb41ac458b..6ea7dfcb4dc 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -12,9 +12,9 @@ # # Usage:: # -# testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) +# testrun.sh [-s SUITE] [-r RUNNER] DIR [CASE1 CASE2 ...] # -# You can use this feature to run the same test many times, to get +# You can use this program to run the same test many times, to get # lots of random coverage. For example:: # # yes amcss | head -100 | xargs tool/testrun.sh code/xc/Debug @@ -22,38 +22,58 @@ # This runs the AMC stress test 100 times from the code/xc/Debug # directory, reporting all failures. +echo "MPS test suite" + +TEST_RUNNER= +TEST_CASES= + +# Parse command-line arguments. +while [ $# -gt 0 ]; do + case "$1" in + -s) + TEST_SUITE=$2 + case "$TEST_SUITE" in + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; + testpollnone) EXCLUDE="LNPTW" ;; + *) + echo "Test suite $TEST_SUITE not recognized." + exit 1 ;; + esac + echo "Test suite: $TEST_SUITE" + TEST_CASE_DB=$(dirname -- "$0")/testcases.txt + TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | + grep -v -e "=[$EXCLUDE]" | + cut -d' ' -f1) + shift 2 + ;; + -r) + TEST_RUNNER=$2 + shift 2 + ;; + -*) + echo "Unrecognized option $1" + exit 1 + ;; + *) + break + ;; + esac +done + # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -echo "MPS test suite" echo "Logging test output to $LOGDIR" - -# First argument is the directory containing the test cases. + +# Next argument is the directory containing the test cases. TEST_DIR=$1 shift echo "Test directory: $TEST_DIR" # Determine which tests to run. -TEST_CASE_DB=$(dirname -- "$0")/testcases.txt -if [ $# -eq 1 ]; then - TEST_SUITE=$1 - echo "Test suite: $TEST_SUITE" - case $TEST_SUITE in - testrun) EXCLUDE="LNW" ;; - testci) EXCLUDE="BNW" ;; - testall) EXCLUDE="NW" ;; - testansi) EXCLUDE="LNTW" ;; - testpoll) EXCLUDE="LNPTW" ;; - *) - echo "Test suite $TEST_SUITE not recognized." - exit 1 ;; - esac - TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | - grep -v -e "=[$EXCLUDE]" | - cut -d' ' -f1) -else - echo "$# test cases from the command line" - TEST_CASES=$* -fi +TEST_CASES="$TEST_CASES $*" SEPARATOR=---------------------------------------- TEST_COUNT=0 @@ -67,16 +87,16 @@ for TESTCASE in $TEST_CASES; do export MPS_TELEMETRY_FILENAME echo "Running $TEST" - TEST_COUNT=$(expr $TEST_COUNT + 1) - if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then - PASS_COUNT=$(expr $PASS_COUNT + 1) + TEST_COUNT=$((TEST_COUNT + 1)) + if $TEST_RUNNER "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then + PASS_COUNT=$((PASS_COUNT + 1)) else echo "$TEST failed: log follows" echo ${SEPARATOR}${SEPARATOR} cat -- "$LOGTEST" echo echo ${SEPARATOR}${SEPARATOR} - FAIL_COUNT=$(expr $FAIL_COUNT + 1) + FAIL_COUNT=$((FAIL_COUNT + 1)) fi if [ -f "$MPS_TELEMETRY_FILENAME" ]; then From 0141cc951ae7b0f5666467ec31a66fc2e06c1489 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 19 Jan 2016 16:23:39 +0000 Subject: [PATCH 31/40] Resolving review issues in . Improving documentation. Fixing minor type misuse. Copied from Perforce Change: 188922 ServerID: perforce.ravenbrook.com --- mps/code/thix.c | 7 +++++-- mps/code/thxc.c | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mps/code/thix.c b/mps/code/thix.c index be1b1f770ae..c1a31c6e902 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -137,10 +137,11 @@ void ThreadDeregister(Thread thread, Arena arena) * each one except the current thread. * * Threads that are found to be dead (that is, if func returns FALSE) - * are moved to deadRing. + * are moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ -static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { Ring node, next; pthread_t self; @@ -178,6 +179,7 @@ static Bool threadSuspend(Thread thread) res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc); AVER(res == ResOK); AVER(thread->mfc != NULL); + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } @@ -201,6 +203,7 @@ static Bool threadResume(Thread thread) res = PThreadextResume(&thread->thrextStruct); AVER(res == ResOK); thread->mfc = NULL; + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index b4d7c4188f0..6ecc1ea726e 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -115,7 +115,8 @@ void ThreadDeregister(Thread thread, Arena arena) * each one except the current thread. * * Threads that are found to be dead (that is, if func returns FALSE) - * are marked as dead and moved to deadRing. + * are marked as dead and moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) @@ -151,6 +152,9 @@ static Bool threadSuspend(Thread thread) /* No rendezvous is necessary: thread_suspend "prevents the thread * from executing any more user-level instructions" */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; } @@ -160,6 +164,9 @@ static Bool threadResume(Thread thread) kern_return = thread_resume(thread->port); /* Mach has no equivalent of EAGAIN. */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; } From 7203f2f03aa76008f87c9bed596dcbe48ea2d533 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 20 Jan 2016 11:44:28 +0000 Subject: [PATCH 32/40] Adding reference to job for improving definalization. see . Copied from Perforce Change: 188929 ServerID: perforce.ravenbrook.com --- mps/code/poolmrg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index f329b87f110..2cb5e7a2f21 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -745,7 +745,12 @@ Res MRGRegister(Pool pool, Ref ref) } -/* MRGDeregister -- deregister (once) an object for finalization */ +/* MRGDeregister -- deregister (once) an object for finalization + * + * TODO: Definalization loops over all finalizable objects in the heap, + * and so using it could accidentally be disastrous for performance. + * See job003953 and back out changelist 187123 if this is fixed. + */ Res MRGDeregister(Pool pool, Ref obj) { From 8179e2699b5ad404b41dd497a0e62679e55ca894 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 28 Jan 2016 15:52:48 +0000 Subject: [PATCH 33/40] Mps git repository renamed from mps-temporary to mps. Copied from Perforce Change: 189034 ServerID: perforce.ravenbrook.com --- mps/procedure/release-build.rst | 7 ++++--- mps/procedure/version-create.rst | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index c35f3a25610..cf07cee0620 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -33,7 +33,7 @@ All relative paths are relative to .. _version-create: version-create -#. Make sure that you have rights to push to the ``mps-temporary`` +#. Make sure that you have rights to push to the ``mps`` repository on GitHub. If not, follow the `Becoming a Ravenbrook team member procedure `_ first. @@ -218,10 +218,10 @@ On a Unix (including OS X) machine: Memory Pool System Kit release $RELEASE. See . END - git push --tags git@github.com:Ravenbrook/mps-temporary.git + git push --tags git@github.com:Ravenbrook/mps.git #. Go to the `list of releases on Github - `__ and + `__ and select "Draft a new release". Select the tag you just pushed, and set the title and description to match the other releases. @@ -259,6 +259,7 @@ B. Document History 2012‑09‑24 RB_ Make sure ZIP files contain files with Windows line endings. Use a fresh Perforce client to avoid any possibility of a clash with working files. Different archive name for custom variants. 2013-03-20 GDR_ Ensure that manual HTML is up to date before making a release. 2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of release 1.112.0. +2016-01-28 RB_ Git repository renamed from mps-temporary to mps. ========== ===== ========================================================== .. _RB: mailto:rb@ravenbrook.com diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index d52c208ce7d..3f743639fdf 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -154,7 +154,7 @@ the parent branch. A typical invocation looks like this:: PUSHES=$(p4 have //info.ravenbrook.com/infosys/robots/git-fusion/etc/pushes | cut -d' ' -f3) p4 edit $PUSHES - printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps-temporary.git\tversion/$VERSION" >> $PUSHES + printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps.git\tversion/$VERSION" >> $PUSHES p4 submit -d "Arranging for MPS version $VERSION to be pushed to GitHub by Git Fusion" $PUSHES @@ -178,6 +178,7 @@ B. Document History 2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of version 1.112. 2014-01-14 GDR_ Step for adding to Git Fusion. 2014-03-19 GDR_ Describe automated procedure. +2016-01-28 RB_ Git repository renamed from mps-temporary to mps. ========== ===== ======================================================== .. _GDR: mailto:gdr@ravenbrook.com From dc77e889d1386c932bf91e99d7629e1e3d2f6664 Mon Sep 17 00:00:00 2001 From: Sam Skulls Date: Wed, 14 May 2014 00:54:47 -0600 Subject: [PATCH 34/40] Fix typo --- mps/example/scheme/scheme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 1e7b7084759..fb43e62e344 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -416,7 +416,7 @@ static void error(const char *format, ...) * that type. * * These functions illustrate the two-phase MPS Allocation Point - * Protocol with `reserve` and `commmit`. This protocol allows very fast + * Protocol with `reserve` and `commit`. This protocol allows very fast * in-line allocation without locking, but there is a very tiny chance that * the object must be re-initialized. In nearly all cases, however, it's * just a pointer bump. See topic/allocation. From 273839a83428758909a154a98beb4e8c2a31b0fd Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 28 Jan 2016 16:03:16 +0000 Subject: [PATCH 35/40] Fixing typo thanks to --- mps/example/scheme/scheme-advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 5089366f0af..830b5b9da33 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -424,7 +424,7 @@ static void error(const char *format, ...) * that type. * * These functions illustrate the two-phase MPS Allocation Point - * Protocol with `reserve` and `commmit`. This protocol allows very fast + * Protocol with `reserve` and `commit`. This protocol allows very fast * in-line allocation without locking, but there is a very tiny chance that * the object must be re-initialized. In nearly all cases, however, it's * just a pointer bump. See topic/allocation. From 673d651aba7e46d88bd1d3c6bc40c7a0399dfb4c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 30 Jan 2016 19:55:37 +0000 Subject: [PATCH 36/40] Fixing uninitialised variable warning from gcc 5.2.1. Copied from Perforce Change: 189069 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/code/arenavm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 6314cae5b60..cf65402b4e6 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -998,7 +998,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, { Arena arena; RangeStruct range, oldRange; - Chunk chunk; + Chunk chunk = NULL; /* suppress uninit warning */ Bool found, b; Index baseIndex; Count pages; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index ba34a7c70ef..f5666a1e7e6 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -992,7 +992,7 @@ static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter) while (RingNext(node) != &vmArena->spareRing && purged < size) { Ring next = RingNext(node); Page page = PageOfSpareRing(next); - Chunk chunk; + Chunk chunk = NULL; /* suppress uninit warning */ Bool b; /* Use the fact that the page table resides in the chunk to find the chunk that owns the page. */ From 1cd22e39b273906aa507235dda8680c97b7c5d2e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 30 Jan 2016 20:16:30 +0000 Subject: [PATCH 37/40] Removing arena configure method from arena classes. Copied from Perforce Change: 189080 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/code/arenacl.c | 11 ----------- mps/code/arenavm.c | 11 ----------- mps/code/mpmst.h | 1 - mps/code/mpmtypes.h | 1 - 5 files changed, 1 insertion(+), 25 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index a317f16343e..ed959d04ff7 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -408,7 +408,7 @@ Res ArenaConfigure(Arena arena, ArgList args) return res; } - return (*arena->class->configure)(arena, args); + return ResOK; } diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index b5837d0b3d9..cd5c24fe46a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -324,16 +324,6 @@ failChunkCreate: } -/* ClientArenaConfigure -- configure the arena */ - -static Res ClientArenaConfigure(Arena arena, ArgList args) -{ - UNUSED(arena); - UNUSED(args); - return ResOK; -} - - /* ClientArenaFinish -- finish the arena */ static void ClientArenaFinish(Arena arena) @@ -467,7 +457,6 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->offset = offsetof(ClientArenaStruct, arenaStruct); this->varargs = ClientArenaVarargs; this->init = ClientArenaInit; - this->configure = ClientArenaConfigure; this->finish = ClientArenaFinish; this->extend = ClientArenaExtend; this->pagesMarkAllocated = ClientArenaPagesMarkAllocated; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 8dff04b463c..ba34a7c70ef 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -619,16 +619,6 @@ failVMInit: } -/* VMArenaConfigure -- configure the arena */ - -static Res VMArenaConfigure(Arena arena, ArgList args) -{ - UNUSED(arena); - UNUSED(args); - return ResOK; -} - - /* VMArenaFinish -- finish the arena */ static void VMArenaFinish(Arena arena) @@ -1204,7 +1194,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->offset = offsetof(VMArenaStruct, arenaStruct); this->varargs = VMArenaVarargs; this->init = VMArenaInit; - this->configure = VMArenaConfigure; this->finish = VMArenaFinish; this->purgeSpare = VMPurgeSpare; this->grow = VMArenaGrow; diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ac5c12c1498..d212e0e3307 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -525,7 +525,6 @@ typedef struct mps_arena_class_s { size_t offset; /* offset of generic struct in outer struct */ ArenaVarargsMethod varargs; ArenaInitMethod init; - ArenaConfigureMethod configure; ArenaFinishMethod finish; ArenaPurgeSpareMethod purgeSpare; ArenaExtendMethod extend; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 3a494760cb6..a6030e4c1e5 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -119,7 +119,6 @@ typedef unsigned FindDelete; /* */ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs); typedef Res (*ArenaInitMethod)(Arena *arenaReturn, ArenaClass class, ArgList args); -typedef Res (*ArenaConfigureMethod)(Arena arena, ArgList args); typedef void (*ArenaFinishMethod)(Arena arena); typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size); typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size); From d4e54ba17ecf481d8b5307acef68ad655b16d977 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 3 Feb 2016 15:33:03 +0000 Subject: [PATCH 38/40] Backing out the introduction of mps_arena_configure. see . Copied from Perforce Change: 189081 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 27 ---------- mps/code/mpm.h | 1 - mps/code/mps.h | 1 - mps/code/mpsi.c | 14 ------ mps/code/mpsicv.c | 7 +-- mps/manual/source/glossary/c.rst | 3 +- mps/manual/source/glossary/s.rst | 3 +- mps/manual/source/release.rst | 8 --- mps/manual/source/topic/arena.rst | 69 +++++++++++++++----------- mps/manual/source/topic/deprecated.rst | 35 ------------- mps/test/function/165.c | 15 ++---- mps/test/function/231.c | 5 +- 12 files changed, 48 insertions(+), 140 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index ed959d04ff7..94dd0044733 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -385,33 +385,6 @@ failInit: } -/* ArenaConfigure -- configure an arena */ - -Res ArenaConfigure(Arena arena, ArgList args) -{ - Res res; - mps_arg_s arg; - - AVERT(Arena, arena); - AVERT(ArgList, args); - - if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT)) { - Size limit = arg.val.size; - res = ArenaSetCommitLimit(arena, limit); - if (res != ResOK) - return res; - } - if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) { - Size limit = arg.val.size; - res = ArenaSetSpareCommitLimit(arena, limit); - if (res != ResOK) - return res; - } - - return ResOK; -} - - /* ArenaFinish -- finish the generic part of the arena * * .finish.caller: Unlike PoolFinish, this is called by the class finish diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 05286a200d2..022064f3a2f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -498,7 +498,6 @@ extern Bool ArenaClassCheck(ArenaClass class); extern Bool ArenaCheck(Arena arena); extern Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args); -extern Res ArenaConfigure(Arena arena, ArgList args); extern void ArenaDestroy(Arena arena); extern Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args); diff --git a/mps/code/mps.h b/mps/code/mps.h index 10207eb6e94..d9e750417e0 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -439,7 +439,6 @@ extern mps_res_t mps_arena_create(mps_arena_t *, mps_arena_class_t, ...); extern mps_res_t mps_arena_create_v(mps_arena_t *, mps_arena_class_t, va_list); extern mps_res_t mps_arena_create_k(mps_arena_t *, mps_arena_class_t, mps_arg_s []); -extern mps_res_t mps_arena_configure(mps_arena_t, mps_arg_s []); extern void mps_arena_destroy(mps_arena_t); extern size_t mps_arena_reserved(mps_arena_t); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 112ab313c00..9d9d4986000 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -350,20 +350,6 @@ mps_res_t mps_arena_create_k(mps_arena_t *mps_arena_o, } -/* mps_arena_configure -- configure an arena object */ - -mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[]) -{ - Res res; - - ArenaEnter(arena); - res = ArenaConfigure(arena, args); - ArenaLeave(arena); - - return (mps_res_t)res; -} - - /* mps_arena_destroy -- destroy an arena object */ void mps_arena_destroy(mps_arena_t arena) diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index c1ea620c810..29a81b174c8 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -320,7 +320,7 @@ static mps_res_t root_single(mps_ss_t ss, void *p, size_t s) * mps_arena_reserved * incidentally tests: * mps_alloc - * mps_arena_configure + * mps_arena_commit_limit_set * mps_class_mv * mps_pool_create * mps_pool_destroy @@ -347,10 +347,7 @@ static void arena_commit_test(mps_arena_t arena) res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE); } while (res == MPS_RES_OK); die_expect(res, MPS_RES_COMMIT_LIMIT, "Commit limit allocation"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, limit); - die(mps_arena_configure(arena, args), "commit_limit_set after"); - } MPS_ARGS_END(args); + die(mps_arena_commit_limit_set(arena, limit), "commit_limit_set after"); res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE); die_expect(res, MPS_RES_OK, "Allocation failed after raising commit_limit"); mps_pool_destroy(pool); diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst index 23b2d960048..ffdf1899243 100644 --- a/mps/manual/source/glossary/c.rst +++ b/mps/manual/source/glossary/c.rst @@ -354,8 +354,7 @@ Memory Management Glossary: C The commit limit is a limit on the :term:`committed ` :term:`memory (2)` that the :term:`arena` will obtain from the operating system. It can be changed by - passing the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` - :term:`keyword argument` to :c:func:`mps_arena_configure`. + calling :c:func:`mps_arena_commit_limit_set`. committed (1) diff --git a/mps/manual/source/glossary/s.rst b/mps/manual/source/glossary/s.rst index b18c186fd23..dc9355f2a0f 100644 --- a/mps/manual/source/glossary/s.rst +++ b/mps/manual/source/glossary/s.rst @@ -467,8 +467,7 @@ Memory Management Glossary: S committed memory` that the MPS will obtain from the operating system. It can be retrieved by calling :c:func:`mps_arena_spare_commit_limit` and changed by - passing the :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` - :term:`keyword argument` to :c:func:`mps_arena_configure`. + calling :c:func:`mps_arena_spare_commit_limit_set`. spare committed memory diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 5a862a6bc47..ad285d7adc6 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -23,10 +23,6 @@ New features :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` sets the :term:`spare commit limit` for the arena. -#. The new function :c:func:`mps_arena_configure` provides a - :term:`keyword argument` interface for changing the properties of - an arena. - Interface changes ................. @@ -41,10 +37,6 @@ Interface changes deprecated in favour of the generic functions :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`. -#. The functions :c:func:`mps_arena_commit_limit_set` and - :c:func:`mps_arena_spare_commit_limit_set` are deprecated in favour - of :c:func:`mps_arena_configure`. - Other changes ............. diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 7c9f580adde..f98de4ba56d 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -92,19 +92,6 @@ the way that they acquire the memory to be managed. :c:func:`mps_arena_destroy`. -.. c:function:: mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[]) - - Configure an :term:`arena`. - - ``arena`` is the arena to configure. - - ``args`` are :term:`keyword arguments` specifying configuration - parameters. See the documentation for the arena class. - - Returns :c:macro:`MPS_RES_OK` if the arena was configured - successfully, or another :term:`result code` otherwise. - - .. c:function:: void mps_arena_destroy(mps_arena_t arena) Destroy an :term:`arena`. @@ -186,10 +173,6 @@ Client arenas Client arenas have no mechanism for returning unused memory. - When configuring a client arena, :c:func:`mps_arena_configure` - accepts the :term:`keyword argument` - :c:macro:`MPS_KEY_COMMIT_LIMIT` as described above. - .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -312,11 +295,6 @@ Virtual memory arenas res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); } MPS_ARGS_END(args); - When configuring a virtual memory arena, - :c:func:`mps_arena_configure` accepts the :term:`keyword - arguments` :c:macro:`MPS_KEY_COMMIT_LIMIT` and - :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` as described above. - .. index:: single: arena; properties @@ -349,9 +327,10 @@ Arena properties memory that the MPS will map to RAM via the operating system's virtual memory interface. - The commit limit can be changed by passing the + The commit limit can be set by passing the :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to - :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The + :c:func:`mps_arena_create_k`. It can be changed by calling + :c:func:`mps_arena_commit_limit_set`. The commit limit cannot be set to a value that is lower than the number of bytes that the MPS is using. If an attempt is made to set the commit limit to a value greater than or equal to that @@ -376,6 +355,20 @@ Arena properties there is more committed memory than the commit limit. +.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit) + + Change the :term:`commit limit` for an :term:`arena`. + + ``arena`` is the arena to change the commit limit for. + + ``limit`` is the new commit limit in :term:`bytes (1)`. + + Returns :c:macro:`MPS_RES_OK` if successful, or another + :term:`result code` if not. + + See :c:func:`mps_arena_spare_commit_limit` for details. + + .. c:function:: size_t mps_arena_committed(mps_arena_t arena) Return the total :term:`committed ` memory for an @@ -469,10 +462,11 @@ Arena properties use, neither by the :term:`client program`, or by the MPS itself) the MPS is allowed to have. - The spare commit limit can be changed by passing the + The spare commit limit can be set by passing the :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword - argument` to :c:func:`mps_arena_create_k` or - :c:func:`mps_arena_configure`. Setting it to a value lower than + argument` to :c:func:`mps_arena_create_k`. It can be changed + by calling :c:func:`mps_arena_spare_commit_limit_set`. + Setting it to a value lower than the current amount of spare committed memory causes spare committed memory to be uncommitted so as to bring the value under the limit. In particular, setting it to 0 will mean that the MPS @@ -500,8 +494,8 @@ Arena properties The amount of "spare committed" memory can be limited passing the :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword - argument` to :c:func:`mps_arena_create_k` or - :c:func:`mps_arena_configure`. The value of the limit can be + argument` to :c:func:`mps_arena_create_k` or by calling + :c:func:`mps_arena_spare_commit_limit_set`. The value of the limit can be retrieved with :c:func:`mps_arena_spare_commit_limit`. This is analogous to the functions for limiting the amount of :term:`committed ` memory. @@ -512,6 +506,23 @@ Arena properties so this function always returns 0. +.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit) + + Change the :term:`spare commit limit` for an :term:`arena`. + + ``arena`` is the arena to change the spare commit limit for. + + ``limit`` is the new spare commit limit in :term:`bytes (1)`. + + Non-virtual-memory arena classes (for example, a :term:`client + arena`) do not have spare committed memory. For these arenas, this + function sets a value but has no other effect. + + Initially the spare commit limit is a configuration-dependent + value. The value of the limit can be retrieved by the function + :c:func:`mps_arena_spare_commit_limit`. + + .. index:: single: arena; states diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 5a3f9900bf1..dfd4d8d74cb 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -25,41 +25,6 @@ supported interface. Deprecated in version 1.115 ........................... -.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit) - - .. deprecated:: - - Pass the :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword - argument` to :c:func:`mps_arena_create_k` or - :c:func:`mps_arena_configure`. - - Change the :term:`commit limit` for an :term:`arena`. - - ``arena`` is the arena to change the commit limit for. - - ``limit`` is the new commit limit in :term:`bytes (1)`. - - Returns :c:macro:`MPS_RES_OK` if successful, or another - :term:`result code` if not. - - -.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit) - - Change the :term:`spare commit limit` for an :term:`arena`. - - ``arena`` is the arena to change the spare commit limit for. - - ``limit`` is the new spare commit limit in :term:`bytes (1)`. - - Non-virtual-memory arena classes (for example, a :term:`client - arena`) do not have spare committed memory. For these arenas, this - function sets a value but has no other effect. - - Initially the spare commit limit is a configuration-dependent - value. The value of the limit can be retrieved by the function - :c:func:`mps_arena_spare_commit_limit`. - - .. c:type:: typedef mps_pool_class_t mps_class_t .. deprecated:: diff --git a/mps/test/function/165.c b/mps/test/function/165.c index da0734ba279..5bd3bda7a44 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -59,10 +59,7 @@ static void test(void) /* Set the spare commit limit to 0MB */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 0); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t) 0); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); mps_free(pool, objs[0], BIGSIZE); @@ -74,10 +71,7 @@ static void test(void) /* Try again but with arena hysteresis */ /* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, -1); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t)-1); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); mps_free(pool, objs[0], BIGSIZE); @@ -87,10 +81,7 @@ static void test(void) report("reduce2", "%ld", com0-com1); /* Reducing the spare committed limit should return most of the spare */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 1024*1024); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t)(1024*1024)); com2 = mps_arena_committed(arena); report("reduce3", "%ld", com0-com2); diff --git a/mps/test/function/231.c b/mps/test/function/231.c index ac13e02d4a1..c8c29fa44e2 100644 --- a/mps/test/function/231.c +++ b/mps/test/function/231.c @@ -27,10 +27,7 @@ static void test(void) report_res("create2", mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none)); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024); - report_res("configure", mps_arena_configure(arena, args)); - } MPS_ARGS_END(args); + report_res("configure", mps_arena_commit_limit_set(arena, 16 * 1024)); mps_arena_destroy(arena); } From 38f73575ae2a1c8b0cc6dd7e02c85be92f60148e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 3 Feb 2016 16:50:42 +0000 Subject: [PATCH 39/40] Removing result code from arenasetsparecommitlimit since it can never fail. See . Copied from Perforce Change: 189084 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 3 +-- mps/code/mpm.h | 2 +- mps/code/mpsi.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 94dd0044733..722e450c4d5 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -1314,7 +1314,7 @@ Size ArenaSpareCommitLimit(Arena arena) return arena->spareCommitLimit; } -Res ArenaSetSpareCommitLimit(Arena arena, Size limit) +void ArenaSetSpareCommitLimit(Arena arena, Size limit) { AVERT(Arena, arena); /* Can't check limit, as all possible values are allowed. */ @@ -1326,7 +1326,6 @@ Res ArenaSetSpareCommitLimit(Arena arena, Size limit) } EVENT2(SpareCommitLimitSet, arena, limit); - return ResOK; } /* Used by arenas which don't use spare committed memory */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 022064f3a2f..b8cb8c250ee 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -620,7 +620,7 @@ extern Size ArenaSpareCommitted(Arena arena); extern Size ArenaCommitLimit(Arena arena); extern Res ArenaSetCommitLimit(Arena arena, Size limit); extern Size ArenaSpareCommitLimit(Arena arena); -extern Res ArenaSetSpareCommitLimit(Arena arena, Size limit); +extern void ArenaSetSpareCommitLimit(Arena arena, Size limit); extern Size ArenaNoPurgeSpare(Arena arena, Size size); extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 9d9d4986000..283fbc6123e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -204,7 +204,7 @@ mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit) void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit) { ArenaEnter(arena); - (void)ArenaSetSpareCommitLimit(arena, limit); + ArenaSetSpareCommitLimit(arena, limit); ArenaLeave(arena); return; From 8ace24237d6866c44a5036a9ffe460affcfc7057 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 10 Feb 2016 15:14:21 +0000 Subject: [PATCH 40/40] Ensuring landfinish doesn't try treecheck on unmapped memory. see . Copied from Perforce Change: 189121 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mps/code/arena.c b/mps/code/arena.c index cf65402b4e6..738761aaa33 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -417,6 +417,11 @@ static void arenaFreeLandFinish(Arena arena) AVERT(Arena, arena); AVER(arena->hasFreeLand); + /* We're about to free the memory occupied by the free land, which + contains a CBS. We want to make sure that LandFinish doesn't try + to check the CBS, so nuke it here. TODO: LandReset? */ + arena->freeLandStruct.splayTreeStruct.root = TreeEMPTY; + /* The CBS block pool can't free its own memory via ArenaFree because * that would use the free land. */ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,