diff --git a/mps/.p4ignore b/mps/.p4ignore index fb2e5c024e5..25cd419ae6d 100644 --- a/mps/.p4ignore +++ b/mps/.p4ignore @@ -16,5 +16,8 @@ TAGS *.dSYM code/*/*/*.d *.pyc +test/obj test/test/log test/test/obj +....gcda +....gcno \ No newline at end of file diff --git a/mps/code/abq.c b/mps/code/abq.c index b915bb42c9b..22286354c77 100644 --- a/mps/code/abq.c +++ b/mps/code/abq.c @@ -1,7 +1,7 @@ /* abq.c: QUEUE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: A fixed-length FIFO queue. * @@ -185,18 +185,10 @@ Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *strea if(res != ResOK) return res; - res = METER_WRITE(abq->push, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->pop, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->peek, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->delete, stream); - if(res != ResOK) - return res; + METER_WRITE(abq->push, stream); + METER_WRITE(abq->pop, stream); + METER_WRITE(abq->peek, stream); + METER_WRITE(abq->delete, stream); res = WriteF(stream, "}\n", NULL); if(res != ResOK) @@ -311,7 +303,7 @@ static void *ABQElement(ABQ abq, Index index) { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c index 4cff09f1745..367bafe730b 100644 --- a/mps/code/abqtest.c +++ b/mps/code/abqtest.c @@ -7,15 +7,16 @@ #include "abq.h" #include "mps.h" #include "mpsavm.h" +#include "mpscmfs.h" #include "mpstd.h" #include "testlib.h" -#include +#include /* printf */ SRCID(abqtest, "$Id$"); - +static mps_pool_t pool; static ABQStruct abq; /* the ABQ which we will use */ static Size abqSize; /* the size of the current ABQ */ @@ -50,9 +51,12 @@ static TestBlock testBlocks = NULL; static TestBlock CreateTestBlock(unsigned no) { - TestBlock b = malloc(sizeof(TestBlockStruct)); - cdie(b != NULL, "malloc"); + TestBlock b; + mps_addr_t p; + die(mps_alloc(&p, pool, sizeof(TestBlockStruct)), "alloc"); + + b = p; b->next = testBlocks; b->id = no; b->base = 0; @@ -78,7 +82,7 @@ static void DestroyTestBlock(TestBlock b) } } - free(b); + mps_free(pool, b, sizeof(TestBlockStruct)); } typedef struct TestClosureStruct *TestClosure; @@ -146,9 +150,6 @@ static void step(void) } } - -#define testArenaSIZE (((size_t)4)<<20) - extern int main(int argc, char *argv[]) { mps_arena_t arena; @@ -158,9 +159,14 @@ extern int main(int argc, char *argv[]) abqSize = 0; - die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), "mps_arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, sizeof(TestBlockStruct)); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + die(ABQInit((Arena)arena, &abq, NULL, ABQ_SIZE, sizeof(TestBlock)), "ABQInit"); diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 367a4464390..56e1bd8c129 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -35,14 +35,14 @@ #include "fmtscheme.h" #define OBJ_LEN (1u << 4) -#define OBJ_COUNT 1 +#define OBJ_COUNT 10 static void test_air(int interior, int stack) { size_t n_finalized = 0; size_t i, j; obj_t *s[OBJ_COUNT] = {0}; - mps_root_t root; + mps_root_t root = NULL; if (!stack) { mps_addr_t *p = (void *)s; die(mps_root_create_table(&root, scheme_arena, mps_rank_ambig(), 0, p, @@ -90,20 +90,15 @@ static mps_gen_param_s obj_gen_params[] = { { 170, 0.45 } }; -static void test_main(int interior, int stack) +static void test_main(void *marker, int interior, int stack) { mps_res_t res; mps_chain_t obj_chain; mps_fmt_t obj_fmt; mps_thr_t thread; - mps_root_t reg_root; - void *marker = ▮ + mps_root_t reg_root = NULL; - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1 << 20); - MPS_ARGS_DONE(args); - res = mps_arena_create_k(&scheme_arena, mps_arena_class_vm(), args); - } MPS_ARGS_END(args); + res = mps_arena_create_k(&scheme_arena, mps_arena_class_vm(), mps_args_none); if (res != MPS_RES_OK) error("Couldn't create arena"); res = mps_chain_create(&obj_chain, scheme_arena, @@ -149,12 +144,14 @@ static void test_main(int interior, int stack) int main(int argc, char *argv[]) { + void *marker = ▮ + testlib_init(argc, argv); - test_main(TRUE, TRUE); - test_main(TRUE, FALSE); - /* not test_main(FALSE, TRUE) -- see .fail.lii6ll. */ - test_main(FALSE, FALSE); + test_main(marker, TRUE, TRUE); + test_main(marker, TRUE, FALSE); + /* not test_main(marker, FALSE, TRUE) -- see .fail.lii6ll. */ + test_main(marker, FALSE, FALSE); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 3f9afba4e82..48892a45830 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -12,13 +12,10 @@ #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" #include "mpslib.h" -#include -#include + +#include /* fflush, printf, putchar */ /* These values have been tuned in the hope of getting one dynamic collection. */ @@ -81,19 +78,6 @@ static void report(mps_arena_t arena) printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message)); printf("}\n"); - - if(condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) { - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. - * - * GDR 2013-03-12: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003440), so I've commented - * out this feature. - */ - /* die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); */ - } - } else { cdie(0, "unknown message type"); break; @@ -101,14 +85,12 @@ static void report(mps_arena_t arena) mps_message_discard(arena, message); } - - return; } /* make -- create one new object */ -static mps_addr_t make(void) +static mps_addr_t make(size_t rootsCount) { size_t length = rnd() % (2*avLEN); size_t size = (length+2) * sizeof(mps_word_t); @@ -119,7 +101,7 @@ static mps_addr_t make(void) MPS_RESERVE_BLOCK(res, p, ap, size); if (res) die(res, "MPS_RESERVE_BLOCK"); - res = dylan_init(p, size, exactRoots, exactRootsCOUNT); + res = dylan_init(p, size, exactRoots, rootsCount); if (res) die(res, "dylan_init"); } while(!mps_commit(ap, p, size)); @@ -141,7 +123,7 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, /* test -- the body of the test */ -static void test(mps_arena_t arena) +static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) { mps_fmt_t format; mps_chain_t chain; @@ -157,7 +139,7 @@ static void test(mps_arena_t arena) die(dylan_fmt(&format, arena), "fmt_create"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain), + die(mps_pool_create(&pool, arena, pool_class, format, chain), "pool_create(amc)"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); @@ -269,13 +251,13 @@ static void test(mps_arena_t arena) i = (r >> 1) % exactRootsCOUNT; if (exactRoots[i] != objNULL) cdie(dylan_check(exactRoots[i]), "dying root check"); - exactRoots[i] = make(); + exactRoots[i] = make(roots_count); if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL) dylan_write(exactRoots[(exactRootsCOUNT-1) - i], exactRoots, exactRootsCOUNT); } else { i = (r >> 1) % ambigRootsCOUNT; - ambigRoots[(ambigRootsCOUNT-1) - i] = make(); + ambigRoots[(ambigRootsCOUNT-1) - i] = make(roots_count); /* Create random interior pointers */ ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1); } @@ -313,13 +295,10 @@ int main(int argc, char *argv[]) "arena_create"); mps_message_type_enable(arena, mps_message_type_gc()); mps_message_type_enable(arena, mps_message_type_gc_start()); - /* GDR 2013-03-12: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003440), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");*/ + die(mps_arena_commit_limit_set(arena, 2*testArenaSIZE), "set limit"); die(mps_thread_reg(&thread, arena), "thread_reg"); - test(arena); + test(arena, mps_class_amc(), exactRootsCOUNT); + test(arena, mps_class_amcz(), 0); mps_thread_dereg(thread); report(arena); mps_arena_destroy(arena); diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c index 15dd342336c..8b3a0c65e36 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -12,12 +12,9 @@ #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include + +#include /* fflush, printf, putchar */ /* These values have been tuned in the hope of getting one dynamic collection. */ @@ -51,7 +48,7 @@ static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; static mps_addr_t bogusRoots[bogusRootsCOUNT]; -static mps_addr_t make(void) +static mps_addr_t make(size_t roots_count) { size_t length = rnd() % (2*avLEN); size_t size = (length+2) * sizeof(mps_word_t); @@ -63,7 +60,7 @@ static mps_addr_t make(void) if (res) die(res, "MPS_RESERVE_BLOCK"); userP = (mps_addr_t)((char*)p + headerSIZE); - res = dylan_init(userP, size, exactRoots, exactRootsCOUNT); + res = dylan_init(userP, size, exactRoots, roots_count); if (res) die(res, "dylan_init"); ((int*)p)[0] = realHeader; @@ -94,27 +91,14 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) { - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. - * - * GDR 2013-03-07: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003432), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");*/ - } } } /* test -- the body of the test */ -static void *test(void *arg, size_t s) +static void *test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) { - mps_arena_t arena; mps_fmt_t format; mps_chain_t chain; mps_root_t exactRoot, ambigRoot, bogusRoot; @@ -125,13 +109,10 @@ static void *test(void *arg, size_t s) mps_ap_t busy_ap; mps_addr_t busy_init; - arena = (mps_arena_t)arg; - (void)s; /* unused */ - die(EnsureHeaderFormat(&format, arena), "fmt_create"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain), + die(mps_pool_create(&pool, arena, pool_class, format, chain), "pool_create(amc)"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); @@ -220,13 +201,13 @@ static void *test(void *arg, size_t s) i = (r >> 1) % exactRootsCOUNT; if (exactRoots[i] != objNULL) die(HeaderFormatCheck(exactRoots[i]), "wrapper check"); - exactRoots[i] = make(); + exactRoots[i] = make(roots_count); if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL) dylan_write(exactRoots[(exactRootsCOUNT-1) - i], exactRoots, exactRootsCOUNT); } else { i = (r >> 1) % ambigRootsCOUNT; - ambigRoots[(ambigRootsCOUNT-1) - i] = make(); + ambigRoots[(ambigRootsCOUNT-1) - i] = make(roots_count); /* Create random interior pointers */ ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1); } @@ -261,20 +242,16 @@ 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(), 3*testArenaSIZE), + die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "arena_create\n"); mps_message_type_enable(arena, mps_message_type_gc()); - /* GDR 2013-03-07: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003432), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");*/ + die(mps_arena_commit_limit_set(arena, 2*testArenaSIZE), "set limit"); die(mps_thread_reg(&thread, arena), "thread_reg"); - mps_tramp(&r, test, arena, 0); + test(arena, mps_class_amc(), exactRootsCOUNT); + test(arena, mps_class_amcz(), 0); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index f01dbaf9d6b..2f91edee93e 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -4,21 +4,34 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * - * .posix: This is Posix only. + * .mode: This test case has two modes: + * + * .mode.walk: In this mode, the main thread parks the arena half way + * through the test case and runs mps_arena_formatted_objects_walk(). + * This checks that walking works while the other threads continue to + * allocate in the background. + * + * .mode.commit: In this mode, the arena's commit limit is set. This + * checks that the MPS can make progress inside a tight limit in the + * presence of allocation on multiple threads. But this is + * incompatible with .mode.walk: if the arena is parked, then the + * arena has no chance to make progress. */ -#define _POSIX_C_SOURCE 199309L - #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "testthr.h" #include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" -#include -#include -#include -#include + +#include /* fflush, printf, putchar */ + +enum { + ModeWALK = 0, /* .mode.walk */ + ModeCOMMIT = 1 /* .mode.commit */ +}; /* These values have been tuned in the hope of getting one dynamic collection. */ @@ -43,7 +56,6 @@ static mps_gen_param_s testChain[genCOUNT] = { #define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED)) -static mps_pool_t pool; static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; @@ -67,26 +79,20 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. */ - die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); } } -mps_arena_t arena; -mps_fmt_t format; -mps_chain_t chain; -mps_root_t exactRoot, ambigRoot; -unsigned long objs = 0; +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; /* make -- create one new object */ -static mps_addr_t make(mps_ap_t ap) +static mps_addr_t make(mps_ap_t ap, size_t roots_count) { size_t length = rnd() % (2*avLEN); size_t size = (length+2) * sizeof(mps_word_t); @@ -97,7 +103,7 @@ static mps_addr_t make(mps_ap_t ap) MPS_RESERVE_BLOCK(res, p, ap, size); if (res) die(res, "MPS_RESERVE_BLOCK"); - res = dylan_init(p, size, exactRoots, exactRootsCOUNT); + res = dylan_init(p, size, exactRoots, roots_count); if (res) die(res, "dylan_init"); } while(!mps_commit(ap, p, size)); @@ -108,16 +114,16 @@ static mps_addr_t make(mps_ap_t ap) /* test_stepper -- stepping function for walk */ -static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pol, +static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, void *p, size_t s) { - testlib_unused(object); testlib_unused(fmt); testlib_unused(pol); + testlib_unused(object); testlib_unused(fmt); testlib_unused(pool); testlib_unused(s); (*(unsigned long *)p)++; } -/* init -- initialize pool and roots */ +/* init -- initialize roots and chain */ static void init(void) { @@ -126,9 +132,6 @@ static void init(void) die(dylan_fmt(&format, arena), "fmt_create"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain), - "pool_create(amc)"); - for(i = 0; i < exactRootsCOUNT; ++i) exactRoots[i] = objNULL; for(i = 0; i < ambigRootsCOUNT; ++i) @@ -146,13 +149,12 @@ static void init(void) } -/* finish -- finish pool and roots */ +/* finish -- finish roots and chain */ static void finish(void) { mps_root_destroy(exactRoot); mps_root_destroy(ambigRoot); - mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); } @@ -160,7 +162,7 @@ static void finish(void) /* churn -- create an object and install into roots */ -static void churn(mps_ap_t ap) +static void churn(mps_ap_t ap, size_t roots_count) { size_t i; size_t r; @@ -171,22 +173,52 @@ static void churn(mps_ap_t ap) i = (r >> 1) % exactRootsCOUNT; if (exactRoots[i] != objNULL) cdie(dylan_check(exactRoots[i]), "dying root check"); - exactRoots[i] = make(ap); + exactRoots[i] = make(ap, roots_count); if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL) dylan_write(exactRoots[(exactRootsCOUNT-1) - i], exactRoots, exactRootsCOUNT); } else { i = (r >> 1) % ambigRootsCOUNT; - ambigRoots[(ambigRootsCOUNT-1) - i] = make(ap); + ambigRoots[(ambigRootsCOUNT-1) - i] = make(ap, roots_count); /* Create random interior pointers */ ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1); } } +typedef struct closure_s { + mps_pool_t pool; + size_t roots_count; +} closure_s, *closure_t; + +static void *kid_thread(void *arg) +{ + void *marker = ▮ + mps_thr_t thread; + mps_root_t reg_root; + mps_ap_t ap; + closure_t cl = arg; + + die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg"); + die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, + mps_stack_scan_ambig, marker, 0), "root_create"); + + die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)"); + while(mps_collections(arena) < collectionsCOUNT) { + churn(ap, cl->roots_count); + } + mps_ap_destroy(ap); + + mps_root_destroy(reg_root); + mps_thread_dereg(thread); + + return NULL; +} + + /* test -- the body of the test */ -static void *test(void *arg, size_t s) +static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode) { size_t i; mps_word_t collections, rampSwitch; @@ -194,9 +226,19 @@ static void *test(void *arg, size_t s) int ramping; mps_ap_t ap, busy_ap; mps_addr_t busy_init; + mps_pool_t pool; + testthr_t kids[10]; + closure_s cl; + int walked = FALSE, ramped = FALSE; - arena = (mps_arena_t)arg; - (void)s; /* unused */ + die(mps_pool_create(&pool, arena, pool_class, format, chain), + "pool_create(amc)"); + + cl.pool = pool; + cl.roots_count = roots_count; + + for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i) + testthr_create(&kids[i], kid_thread, &cl); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2"); @@ -217,21 +259,23 @@ static void *test(void *arg, size_t s) if (collections != c) { collections = c; - printf("\nCollection %lu started, %lu objects.\n", c, objs); + printf("\nCollection %lu started, %lu objects, committed=%lu.\n", + c, objs, (unsigned long)mps_arena_committed(arena)); report(arena); for (i = 0; i < exactRootsCOUNT; ++i) cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), "all roots check"); - if (collections == collectionsCOUNT / 2) { + 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) { + if (collections >= rampSwitch && !ramped) { int begin_ramp = !ramping || /* Every other time, switch back immediately. */ (collections & 1); @@ -256,9 +300,10 @@ static void *test(void *arg, size_t s) ramping = 1; } } + ramped = TRUE; } - churn(ap); + churn(ap, roots_count); r = (size_t)rnd(); @@ -276,79 +321,45 @@ static void *test(void *arg, size_t s) mps_ap_destroy(busy_ap); mps_ap_destroy(ap); + for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i) + testthr_join(&kids[i], NULL); + + mps_pool_destroy(pool); + return NULL; } - -static void *fooey2(void *arg, size_t s) -{ - mps_ap_t ap; - - (void)arg; (void)s; /* unused */ - die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate(fooey)"); - while(mps_collections(arena) < collectionsCOUNT) { - churn(ap); - } - mps_ap_destroy(ap); - return NULL; -} - - -static void *fooey(void* childIsFinishedReturn) -{ - void *r; - mps_thr_t thread; - void *marker = ▮ - mps_root_t reg_root; - - die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg"); - die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, - mps_stack_scan_ambig, marker, 0), "root_create"); - mps_tramp(&r, fooey2, NULL, 0); - mps_root_destroy(reg_root); - mps_thread_dereg(thread); - *(int *)childIsFinishedReturn = 1; - return r; -} - - -int main(int argc, char *argv[]) +static void test_arena(int mode) { mps_thr_t thread; mps_root_t reg_root; void *marker = ▮ - pthread_t kids[10]; - unsigned i; - void *r; - int childIsFinished = 0; - - testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); + if (mode == ModeCOMMIT) + die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); mps_message_type_enable(arena, mps_message_type_gc()); init(); 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"); - for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i) { - int err = pthread_create(&kids[i], NULL, fooey, (void *)&childIsFinished); - if (err != 0) - error("pthread_create returned %d", err); - } - mps_tramp(&r, test, arena, 0); + mps_stack_scan_ambig, marker, 0), "root_create"); + + test_pool(mps_class_amc(), exactRootsCOUNT, mode); + test_pool(mps_class_amcz(), 0, mode); + mps_root_destroy(reg_root); mps_thread_dereg(thread); - - for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i) { - int err = pthread_join(kids[i], NULL); - if (err != 0) - error("pthread_join returned %d", err); - } - finish(); report(arena); mps_arena_destroy(arena); +} + +int main(int argc, char *argv[]) +{ + testlib_init(argc, argv); + test_arena(ModeWALK); + test_arena(ModeCOMMIT); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/amsss.c b/mps/code/amsss.c index c678f26ff45..1d04f199349 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -15,14 +15,9 @@ #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include -#include -#include + +#include /* fflush, printf */ #define exactRootsCOUNT 50 diff --git a/mps/code/amssshe.c b/mps/code/amssshe.c index 37408340a00..ce5dd4800c8 100644 --- a/mps/code/amssshe.c +++ b/mps/code/amssshe.c @@ -13,14 +13,9 @@ #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include -#include -#include + +#include /* fflush, printf */ #define exactRootsCOUNT 50 diff --git a/mps/code/apss.c b/mps/code/apss.c index 3a60587d412..8c90536fa00 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -16,7 +16,7 @@ #include "testlib.h" #include "mpslib.h" -#include +#include /* printf */ #include /* malloc */ diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c index 8b149c194bd..d5e56eaec2d 100644 --- a/mps/code/arenacv.c +++ b/mps/code/arenacv.c @@ -14,8 +14,6 @@ * being allocated; this requires using two adjacent zones. */ -#include - #include "mpm.h" #include "poolmv.h" #include "testlib.h" @@ -23,6 +21,9 @@ #include "mpsavm.h" #include "mpsacl.h" +#include /* printf */ +#include /* malloc */ + #define tractsSIZE 500 diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 1bcc6272f35..81e0684c436 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -480,7 +480,7 @@ ARG_DEFINE_KEY(arena_contracted, Fun); static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) { - Size userSize; /* size requested by user */ + Size userSize = VM_ARENA_SIZE_DEFAULT; /* size requested by user */ Size chunkSize; /* size actually created */ Size vmArenaSize; /* aligned size of VMArenaStruct */ Res res; @@ -495,8 +495,8 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) AVER(class == VMArenaClassGet()); AVERT(ArgList, args); - ArgRequire(&arg, args, MPS_KEY_ARENA_SIZE); - userSize = arg.val.size; + if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE)) + userSize = arg.val.size; AVER(userSize > 0); @@ -593,6 +593,8 @@ static void VMArenaFinish(Arena arena) AVERT(VMArena, vmArena); arenaVM = vmArena->vm; + EVENT1(ArenaDestroy, vmArena); + /* destroy all chunks, including the primary */ arena->primary = NULL; RING_FOR(node, &arena->chunkRing, next) { @@ -612,7 +614,6 @@ static void VMArenaFinish(Arena arena) VMUnmap(arenaVM, VMBase(arenaVM), VMLimit(arenaVM)); VMDestroy(arenaVM); - EVENT1(ArenaDestroy, vmArena); } diff --git a/mps/code/arg.h b/mps/code/arg.h index dd458efe7b7..bb184dddad9 100644 --- a/mps/code/arg.h +++ b/mps/code/arg.h @@ -1,7 +1,7 @@ /* arg.h: Keyword argument lists * * $Id$ - * Copyright (c) 2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. * * .source: See . */ @@ -28,6 +28,7 @@ typedef struct mps_key_s { } KeyStruct; #define ARG_DEFINE_KEY(id, type) \ + extern const KeyStruct _mps_key_##id; \ const KeyStruct _mps_key_##id = {KeySig, #id, ArgCheck##type} #define argsNone mps_args_none @@ -62,7 +63,7 @@ extern Bool ArgCheckPool(Arg arg); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/awlut.c b/mps/code/awlut.c index b8e14a0db7d..c62153ed44c 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -16,10 +16,9 @@ #include "mpslib.h" #include "mps.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* printf */ +#include /* strlen */ #define testArenaSIZE ((size_t)64<<20) diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c index 257b4142723..d3b2d572319 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -17,10 +17,9 @@ #include "mpslib.h" #include "mps.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* strlen */ +#include /* printf */ #define testArenaSIZE ((size_t)64<<20) diff --git a/mps/code/awlutth.c b/mps/code/awlutth.c index f12d8913543..2bfaddc3813 100644 --- a/mps/code/awlutth.c +++ b/mps/code/awlutth.c @@ -13,16 +13,13 @@ #include "mpsavm.h" #include "fmtdy.h" #include "testlib.h" +#include "testthr.h" #include "mpslib.h" #include "mps.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include -#if defined(MPS_OS_LI) || defined(MPS_OS_FR) || defined(MPS_OS_XC) -#include -#endif + +#include /* printf, puts */ +#include /* strlen */ #define testArenaSIZE ((size_t)64<<20) @@ -314,7 +311,7 @@ static void *setup_thr(void *v) int main(int argc, char *argv[]) { mps_arena_t arena; - pthread_t pthread1; + testthr_t thread1; testlib_init(argc, argv); @@ -324,9 +321,9 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); - pthread_create(&pthread1, NULL, setup_thr, (void *)arena); + testthr_create(&thread1, setup_thr, arena); setup_thr(arena); - pthread_join(pthread1, NULL); + testthr_join(&thread1, NULL); mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); diff --git a/mps/code/btcv.c b/mps/code/btcv.c index 414c3351161..33e3df8be26 100644 --- a/mps/code/btcv.c +++ b/mps/code/btcv.c @@ -18,7 +18,7 @@ #include "testlib.h" #include "mpslib.h" -#include +#include /* printf */ SRCID(btcv, "$Id$"); diff --git a/mps/code/bttest.c b/mps/code/bttest.c index 918463ef4b9..20bb4cab4e7 100644 --- a/mps/code/bttest.c +++ b/mps/code/bttest.c @@ -10,11 +10,10 @@ #include "mpsavm.h" #include "testlib.h" #include "mpslib.h" - -#include -#include #include "mpstd.h" -#include + +#include /* fflush, fgets, printf, putchar, puts */ +#include /* exit, strtol */ SRCID(bttest, "$Id$"); diff --git a/mps/code/buffer.c b/mps/code/buffer.c index baa553a19a2..27314924600 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -980,14 +980,14 @@ Bool BufferIsTrappedByMutator(Buffer buffer) * * Just represent the two patterns by two different pointers to dummies. */ -AllocPatternStruct AllocPatternRampStruct = {'\0'}; +static AllocPatternStruct AllocPatternRampStruct = {'\0'}; AllocPattern AllocPatternRamp(void) { return &AllocPatternRampStruct; } -AllocPatternStruct AllocPatternRampCollectAllStruct = {'\0'}; +static AllocPatternStruct AllocPatternRampCollectAllStruct = {'\0'}; AllocPattern AllocPatternRampCollectAll(void) { @@ -1075,7 +1075,7 @@ static Res bufferTrivInit(Buffer buffer, Pool pool, ArgList args) AVERT(Buffer, buffer); AVERT(Pool, pool); UNUSED(args); - EVENT3(BufferInit, buffer, pool, buffer->isMutator); + EVENT3(BufferInit, buffer, pool, BOOL(buffer->isMutator)); return ResOK; } @@ -1288,7 +1288,7 @@ static Res segBufInit(Buffer buffer, Pool pool, ArgList args) segbuf->rankSet = RankSetEMPTY; AVERT(SegBuf, segbuf); - EVENT3(BufferInitSeg, buffer, pool, buffer->isMutator); + EVENT3(BufferInitSeg, buffer, pool, BOOL(buffer->isMutator)); return ResOK; } @@ -1515,7 +1515,7 @@ static Res rankBufInit(Buffer buffer, Pool pool, ArgList args) BufferSetRankSet(buffer, RankSetSingle(rank)); /* There's nothing to check that the superclass doesn't, so no AVERT. */ - EVENT4(BufferInitRank, buffer, pool, buffer->isMutator, rank); + EVENT4(BufferInitRank, buffer, pool, BOOL(buffer->isMutator), rank); return ResOK; } diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 773dc280bcb..8aa21f87ca7 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1174,8 +1174,7 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream) res = SplayTreeDescribe(cbsSplay(cbs), stream, describe); if (res != ResOK) return res; - res = METER_WRITE(cbs->treeSearch, stream); - if (res != ResOK) return res; + METER_WRITE(cbs->treeSearch, stream); res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index c807976fcda..bfe65a3f498 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -158,7 +158,7 @@ SNC = poolsnc.c POOLN = pooln.c MV2 = poolmv2.c MVFF = poolmvff.c -TESTLIB = testlib.c +TESTLIB = testlib.c testthrix.c FMTDY = fmtdy.c fmtno.c FMTDYTST = fmtdy.c fmtno.c fmtdytst.c FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c @@ -294,6 +294,7 @@ TEST_TARGETS=\ landtest \ locbwcss \ lockcov \ + lockut \ locusss \ locv \ messtest \ @@ -492,6 +493,9 @@ $(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \ $(PFM)/$(VARIETY)/lockcov: $(PFM)/$(VARIETY)/lockcov.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a +$(PFM)/$(VARIETY)/lockut: $(PFM)/$(VARIETY)/lockut.o \ + $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(PFM)/$(VARIETY)/locusss: $(PFM)/$(VARIETY)/locusss.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index b7d9d622bd7..3469391b840 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -1,7 +1,7 @@ # commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*- # # $Id$ -# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # @@ -146,6 +146,10 @@ $(PFM)\$(VARIETY)\awluthe.exe: $(PFM)\$(VARIETY)\awluthe.obj \ $(FMTTESTOBJ) \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\awlutth.exe: $(PFM)\$(VARIETY)\awlutth.obj \ + $(FMTTESTOBJ) \ + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\btcv.exe: $(PFM)\$(VARIETY)\btcv.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) @@ -155,6 +159,9 @@ $(PFM)\$(VARIETY)\bttest.exe: $(PFM)\$(VARIETY)\bttest.obj \ $(PFM)\$(VARIETY)\cvmicv.exe: $(PFM)\$(VARIETY)\cvmicv.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\djbench.exe: $(PFM)\$(VARIETY)\djbench.obj \ + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) @@ -170,6 +177,9 @@ $(PFM)\$(VARIETY)\finaltest.exe: $(PFM)\$(VARIETY)\finaltest.obj \ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \ + $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\landtest.exe: $(PFM)\$(VARIETY)\landtest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) @@ -179,7 +189,7 @@ $(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \ $(PFM)\$(VARIETY)\lockcov.exe: $(PFM)\$(VARIETY)\lockcov.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) -$(PFM)\$(VARIETY)\lockutw3.exe: $(PFM)\$(VARIETY)\lockutw3.obj \ +$(PFM)\$(VARIETY)\lockut.exe: $(PFM)\$(VARIETY)\lockut.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(PFM)\$(VARIETY)\locusss.exe: $(PFM)\$(VARIETY)\locusss.obj \ @@ -306,7 +316,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2013 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 3f7d2043ab3..0cc1dfc8c66 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -58,23 +58,27 @@ TEST_TARGETS=\ 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 \ - lockutw3.exe \ + lockut.exe \ locusss.exe \ locv.exe \ messtest.exe \ @@ -178,7 +182,7 @@ SNC = DW = FMTTEST = FMTSCHEME = -TESTLIB = +TESTLIB = # CHECK PARAMETERS @@ -226,9 +230,6 @@ TESTLIB = !IFNDEF TESTLIB !ERROR commpre.nmk: TESTLIB not defined !ENDIF -!IFNDEF TESTLIB -!ERROR commpre.nmk: TESTLIB not defined -!ENDIF # DECLARATIONS diff --git a/mps/code/config.h b/mps/code/config.h index e29127c153c..0afa66c06bb 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -231,6 +231,16 @@ #define ATTRIBUTE_NO_SANITIZE_ADDRESS #endif +/* Attribute for functions that do not return. + * GCC: + * Clang: + */ +#if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL) +#define ATTRIBUTE_NORETURN __attribute__((__noreturn__)) +#else +#define ATTRIBUTE_NORETURN +#endif + /* EPVMDefaultSubsequentSegSIZE is a default for the alignment of * subsequent segments (non-initial at each save level) in EPVM. See @@ -356,6 +366,8 @@ pool to be very heavily used. */ #define CONTROL_EXTEND_BY 4096 +#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 20) + /* Stack configuration */ diff --git a/mps/code/djbench.c b/mps/code/djbench.c index b27e44e16a4..c1f37f412b2 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -13,13 +13,13 @@ #include "mps.c" -#include -#include -#include -#include #include "getopt.h" #include "testlib.h" +#include "testthr.h" +#include /* fprintf, stderr */ +#include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */ +#include /* CLOCKS_PER_SEC, clock */ #define DJMUST(expr) \ do { \ @@ -56,6 +56,7 @@ static mps_bool_t zoned = TRUE; /* arena allocates using zones */ \ for (k = 0; k < nblocks; ++k) { \ blocks[k].p = NULL; \ + blocks[k].s = 0; \ } \ \ for (j = 0; j < npass; ++j) { \ @@ -135,24 +136,14 @@ typedef void *(*dj_t)(void *); static void weave(dj_t dj) { - pthread_t *threads = alloca(sizeof(threads[0]) * nthreads); + testthr_t *threads = alloca(sizeof(threads[0]) * nthreads); unsigned t; - for (t = 0; t < nthreads; ++t) { - int err = pthread_create(&threads[t], NULL, dj, NULL); - if (err != 0) { - fprintf(stderr, "Unable to create thread: %d\n", err); - exit(EXIT_FAILURE); - } - } + for (t = 0; t < nthreads; ++t) + testthr_create(&threads[t], dj, NULL); - for (t = 0; t < nthreads; ++t) { - int err = pthread_join(threads[t], NULL); - if (err != 0) { - fprintf(stderr, "Unable to join thread: %d\n", err); - exit(EXIT_FAILURE); - } - } + for (t = 0; t < nthreads; ++t) + testthr_join(&threads[t], NULL); } @@ -321,7 +312,8 @@ int main(int argc, char *argv[]) { argv += optind; printf("seed: %lu\n", seed); - + (void)fflush(stdout); + while (argc > 0) { for (i = 0; i < sizeof(pools) / sizeof(pools[0]); ++i) if (strcmp(argv[0], pools[i].name) == 0) diff --git a/mps/code/event.c b/mps/code/event.c index 2e7468c3752..475fa4f875c 100644 --- a/mps/code/event.c +++ b/mps/code/event.c @@ -44,13 +44,13 @@ char EventBuffer[EventKindLIMIT][EventBufferSIZE]; char *EventLast[EventKindLIMIT]; /* Pointers to the last even written out of each buffer. */ -char *EventWritten[EventKindLIMIT]; +static char *EventWritten[EventKindLIMIT]; EventControlSet EventKindControl; /* Bit set used to control output. */ /* A single event structure output once per buffer flush. */ -EventEventClockSyncStruct eventClockSyncStruct; +static EventEventClockSyncStruct eventClockSyncStruct; /* eventClockSync -- Populate and write the clock sync event. */ @@ -422,7 +422,7 @@ void EventDump(mps_lib_FILE *stream) for (kind = 0; kind < EventKindLIMIT; ++kind) { for (event = (Event)EventLast[kind]; - event < (Event)(EventBuffer[kind] + EventBufferSIZE); + (char *)event < EventBuffer[kind] + EventBufferSIZE; event = (Event)((char *)event + event->any.size)) { /* Try to keep going even if there's an error, because this is used as a backtrace and we'll take what we can get. */ diff --git a/mps/code/eventcnv.c b/mps/code/eventcnv.c index 355b6efa2a2..7b7e060470f 100644 --- a/mps/code/eventcnv.c +++ b/mps/code/eventcnv.c @@ -197,6 +197,12 @@ static Res eventRead(Bool *eofOut, EventUnion *event, FILE *stream) return ResIO; } + if (event->any.size < sizeof(event->any)) + return ResFAIL; /* invalid size: too small */ + + if (event->any.size > sizeof(*event)) + return ResFAIL; /* invalid size: too large */ + /* Read the rest of the event. */ rest = event->any.size - sizeof(event->any); if (rest > 0) { diff --git a/mps/code/eventcom.h b/mps/code/eventcom.h index 6114b045d48..931c975596d 100644 --- a/mps/code/eventcom.h +++ b/mps/code/eventcom.h @@ -1,6 +1,6 @@ /* -- Event Logging Common Definitions * - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * $Id$ * * .sources: mps.design.telemetry @@ -56,7 +56,8 @@ ENUM_DECLARE(EventKind) enum EventDefinitionsEnum { EVENT_LIST(EVENT_ENUM, X) - EventEnumWarningSuppressor /* suppress comma-at-end-of-enum warning */ + /* suppress comma-at-end-of-enum warning */ + EventEnumWarningSuppressor = USHRT_MAX }; @@ -89,7 +90,11 @@ typedef Word EventFW; /* word */ typedef unsigned EventFU; /* unsigned integer */ typedef char EventFS[EventStringLengthMAX + sizeof('\0')]; /* string */ typedef double EventFD; /* double */ -typedef int EventFB; /* boolean */ +/* EventFB must be unsigned (even though Bool is a typedef for int) + * because it used as the type of a bitfield with width 1, and we need + * the legals values of the field to be 0 and 1 (not 0 and -1 which + * would be the case for int : 1). */ +typedef unsigned EventFB; /* Boolean */ /* Event packing bitfield specifiers */ #define EventFP_BITFIELD @@ -133,7 +138,7 @@ typedef union EventUnion { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c index 46bfa688a9b..e1c9ea22381 100644 --- a/mps/code/eventsql.c +++ b/mps/code/eventsql.c @@ -102,7 +102,7 @@ typedef sqlite3_int64 int64; * and for reporting errors. */ -unsigned int verbosity = 0; +static unsigned int verbosity = 0; #define LOG_ALWAYS 0 #define LOG_OFTEN 1 @@ -533,7 +533,7 @@ static void logFileCompleted(sqlite3 *db, /* An array of table-creation statement strings. */ -const char *createStatements[] = { +static const char *createStatements[] = { "CREATE TABLE IF NOT EXISTS event_kind (name TEXT," " description TEXT," " enum INTEGER PRIMARY KEY)", @@ -571,7 +571,7 @@ static void makeTables(sqlite3 *db) } } -const char *glueTables[] = { +static const char *glueTables[] = { "event_kind", "event_type", "event_param", diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 5b7f7ab1312..4c50ac994f9 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -29,15 +29,20 @@ * $Id$ */ +#include "mps.h" +#include "mpsavm.h" +#include "mpscmvff.h" +#include "check.h" #include "config.h" #include "eventdef.h" #include "eventcom.h" #include "table.h" #include "testlib.h" /* for ulongest_t and associated print formats */ +#include #include -#include -#include +#include /* exit, EXIT_FAILURE, EXIT_SUCCESS */ +#include /* strcpy, strlen */ static const char *prog; /* program name */ static const char *logFileName = NULL; @@ -106,15 +111,19 @@ static void parseArgs(int argc, char *argv[]) static void *tableAlloc(void *closure, size_t size) { - UNUSED(closure); - return malloc(size); + mps_pool_t pool = closure; + mps_addr_t p; + mps_res_t res; + res = mps_alloc(&p, pool, size); + if (res != MPS_RES_OK) + everror("allocation failed: %d", res); + return p; } static void tableFree(void *closure, void *p, size_t size) { - UNUSED(closure); - UNUSED(size); - free(p); + mps_pool_t pool = closure; + mps_free(pool, p, size); } /* Printing routines */ @@ -171,7 +180,7 @@ static double parseDouble(char **pInOut) #define MAX_STRING_LENGTH 1024 -char strBuf[MAX_STRING_LENGTH]; +static char strBuf[MAX_STRING_LENGTH]; static char *parseString(char **pInOut) { @@ -215,21 +224,21 @@ static Table internTable; /* dictionary of intern ids to strings */ static Table labelTable; /* dictionary of addrs to intern ids */ -static void createTables(void) +static void createTables(mps_pool_t pool) { Res res; /* MPS intern IDs are serials from zero up, so we can use -1 * and -2 as specials. */ res = TableCreate(&internTable, (size_t)1<<4, - tableAlloc, tableFree, NULL, + tableAlloc, tableFree, pool, (Word)-1, (Word)-2); if (res != ResOK) everror("Couldn't make intern table."); /* We assume that 0 and 1 are invalid as Addrs. */ res = TableCreate(&labelTable, (size_t)1<<7, - tableAlloc, tableFree, NULL, + tableAlloc, tableFree, pool, 0, 1); if (res != ResOK) everror("Couldn't make label table."); @@ -238,19 +247,19 @@ static void createTables(void) /* recordIntern -- record an interned string in the table. a copy of * the string from the parsed buffer into a newly-allocated block. */ -static void recordIntern(char *p) +static void recordIntern(mps_pool_t pool, char *p) { ulongest_t stringId; char *string; - char *copy; + mps_addr_t copy; size_t len; Res res; stringId = parseHex(&p); string = parseString(&p); len = strlen(string); - copy = malloc(len+1); - if (copy == NULL) + res = mps_alloc(©, pool, len + 1); + if (res != MPS_RES_OK) everror("Couldn't allocate space for a string."); (void)strcpy(copy, string); res = TableDefine(internTable, (Word)stringId, (void *)copy); @@ -258,12 +267,55 @@ static void recordIntern(char *p) everror("Couldn't create an intern mapping."); } -/* recordLabel records a label (an association between an address and - * a string ID). Note that the event log may have been generated on a - * platform with addresses larger than Word on the current platform. - * If that happens then we are scuppered because our Table code uses - * Word as the key type: there's nothing we can do except detect this - * bad case (see also the EventInit handling and warning code). +/* Over time there may be multiple labels associated with an address, + * so we keep a list, recording for each label the clock when the + * association was made. This means that printAddr can select the + * label that was in force at the time of the event. + */ + +typedef struct LabelStruct *Label; +typedef struct LabelStruct { + ulongest_t clock; /* clock of this label */ + ulongest_t id; /* string id of this label */ +} LabelStruct; + +typedef struct LabelListStruct *LabelList; +typedef struct LabelListStruct { + size_t n; /* number of labels in array */ + Label labels; /* labels, sorted in order by clock */ +} LabelListStruct; + +/* labelFind returns the index of the first entry in list with a clock + * value that's greater than 'clock', or list->n if there is no such + * label. The list is assumed to be sorted. + */ + +static size_t labelFind(LabelList list, ulongest_t clock) +{ + size_t low = 0, high = list->n; + while (low < high) { + size_t mid = (low + high) / 2; + assert(NONNEGATIVE(mid) && mid < list->n); + if (list->labels[mid].clock > clock) { + high = mid; + } else { + low = mid + 1; + } + } + assert(NONNEGATIVE(low) && low <= list->n); + assert(low == list->n || list->labels[low].clock > clock); + return low; +} + +/* recordLabel records a label: an association (made at the time given + * by 'clock') between an address and a string ID. These are encoded + * as two hexadecimal numbers in the string pointed to by 'p'. + * + * Note that the event log may have been generated on a platform with + * addresses larger than Word on the current platform. If that happens + * then we are scuppered because our Table code uses Word as the key + * type: there's nothing we can do except detect this bad case (see + * also the EventInit handling and warning code). * * We can and do handle the case where string IDs (which are Words on * the MPS platform) are larger than void* on the current platform. @@ -274,25 +326,50 @@ static void recordIntern(char *p) * probably a bad idea and maybe doomed to failure. */ -static void recordLabel(char *p) +static void recordLabel(mps_pool_t pool, ulongest_t clock, char *p) { ulongest_t address; - ulongest_t *stringIdP; + LabelList list; + Label newlabels; + mps_addr_t tmp; + size_t pos; Res res; - + address = parseHex(&p); if (address > (Word)-1) { (void)printf("label address too large!"); return; } - - stringIdP = malloc(sizeof(ulongest_t)); - if (stringIdP == NULL) - everror("Can't allocate space for a string's ID"); - *stringIdP = parseHex(&p); - res = TableDefine(labelTable, (Word)address, (void *)stringIdP); + + if (TableLookup(&tmp, labelTable, address)) { + list = tmp; + } else { + /* First label for this address */ + res = mps_alloc(&tmp, pool, sizeof(LabelListStruct)); + if (res != MPS_RES_OK) + everror("Can't allocate space for a label list"); + list = tmp; + list->n = 0; + res = TableDefine(labelTable, (Word)address, list); + if (res != ResOK) + everror("Couldn't create a label mapping."); + } + + res = mps_alloc(&tmp, pool, sizeof(LabelStruct) * (list->n + 1)); if (res != ResOK) - everror("Couldn't create an intern mapping."); + everror("Couldn't allocate space for list of labels."); + newlabels = tmp; + + pos = labelFind(list, clock); + memcpy(newlabels, list->labels, sizeof(LabelStruct) * pos); + newlabels[pos].clock = clock; + newlabels[pos].id = parseHex(&p); + memcpy(newlabels + pos + 1, list->labels + pos, + sizeof(LabelStruct) * (list->n - pos)); + if (list->n > 0) + mps_free(pool, list->labels, sizeof(LabelStruct) * list->n); + list->labels = newlabels; + ++ list->n; } /* output code */ @@ -308,20 +385,23 @@ static int hexWordWidth = (MPS_WORD_WIDTH+3)/4; /* printAddr -- output a ulongest_t in hex, with the interned string * if the value is in the label table */ -static void printAddr(ulongest_t addr, const char *ident) +static void printAddr(ulongest_t clock, ulongest_t addr, const char *ident) { - ulongest_t label; - void *alias; + void *tmp; printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr); - if (TableLookup(&alias, labelTable, addr)) { - label = *(ulongest_t*)alias; - putchar('['); - if (TableLookup(&alias, internTable, label)) - printStr((char *)alias); - else - printf("unknown label %" PRIuLONGEST, label); - putchar(']'); + if (TableLookup(&tmp, labelTable, addr)) { + LabelList list = tmp; + size_t pos = labelFind(list, clock); + if (pos > 0) { + ulongest_t id = list->labels[pos - 1].id; + putchar('['); + if (TableLookup(&tmp, internTable, id)) + printStr((char *)tmp); + else + printf("unknown label %" PRIXLONGEST, id); + putchar(']'); + } } putchar(' '); } @@ -332,7 +412,7 @@ static void printAddr(ulongest_t addr, const char *ident) #define processParamA(ident) \ val_hex = parseHex(&p); \ - printAddr(val_hex, #ident); + printAddr(clock, val_hex, #ident); #define processParamP processParamA #define processParamW processParamA @@ -375,7 +455,7 @@ static const char *eventName[EventCodeMAX+EventCodeMAX]; /* readLog -- read and parse log. Returns the number of events written. */ -static void readLog(FILE *input) +static void readLog(mps_pool_t pool, FILE *input) { int i; @@ -415,9 +495,9 @@ static void readLog(FILE *input) /* for a few particular codes, we do local processing. */ if (code == EventInternCode) { - recordIntern(q); + recordIntern(pool, q); } else if (code == EventLabelCode) { - recordLabel(q); + recordLabel(pool, clock, q); } else if (code == EventEventInitCode) { ulongest_t major, median, minor, maxCode, maxNameLen, wordWidth, clocksPerSec; major = parseHex(&q); /* EVENT_VERSION_MAJOR */ @@ -476,6 +556,9 @@ static void readLog(FILE *input) int main(int argc, char *argv[]) { + mps_arena_t arena; + mps_pool_t pool; + mps_res_t res; FILE *input; parseArgs(argc, argv); @@ -488,8 +571,20 @@ int main(int argc, char *argv[]) everror("unable to open %s", logFileName); } - createTables(); - readLog(input); + res = mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none); + if (res != MPS_RES_OK) + everror("failed to create arena: %d", res); + + res = mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none); + if (res != MPS_RES_OK) + everror("failed to create pool: %d", res); + + createTables(pool); + readLog(pool, input); + + mps_pool_destroy(pool); + mps_arena_destroy(arena); + (void)fclose(input); return 0; } diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c index 11e78ad29cb..21f2567cbaa 100644 --- a/mps/code/exposet0.c +++ b/mps/code/exposet0.c @@ -19,12 +19,9 @@ #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include + +#include /* fflush, printf, puts, stdout */ /* These values have been tuned in the hope of getting one dynamic collection. */ @@ -75,12 +72,6 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. */ - die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); } } @@ -115,15 +106,7 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, testlib_unused(fmt); testlib_unused(pool); testlib_unused(s); -#ifdef MPS_OS_W3 - __try { - dylan_mutate(object); - } __except(EXCEPTION_EXECUTE_HANDLER) { - error("Unexpected exception.\n"); - } -#else dylan_mutate(object); -#endif (*(unsigned long *)p)++; } diff --git a/mps/code/expt825.c b/mps/code/expt825.c index 5947a0cff68..5e775455909 100644 --- a/mps/code/expt825.c +++ b/mps/code/expt825.c @@ -34,10 +34,8 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* printf, fflush, stdout */ #define testArenaSIZE ((size_t)16<<20) diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index e8f7e251a6e..1466e514ff8 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -26,10 +26,8 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* printf */ #define testArenaSIZE ((size_t)16<<20) diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index dd6146851df..88895027286 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -22,14 +22,13 @@ #include "mpscamc.h" #include "mpscams.h" #include "mpscawl.h" +#include "mpsclo.h" #include "mpsavm.h" #include "fmtdy.h" #include "fmtdytst.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* fflush, printf, stdout */ #define testArenaSIZE ((size_t)16<<20) @@ -160,16 +159,16 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, while (mps_message_poll(arena)) { mps_message_t message; mps_addr_t objaddr; - cdie(mps_message_get(&message, arena, - mps_message_type_finalization()), - "get"); + cdie(mps_message_get(&message, arena, mps_message_type_finalization()), + "message_get"); mps_message_finalization_ref(&objaddr, arena, message); mps_message_discard(arena, message); ++ final_this_time; } finals += final_this_time; printf("%"PRIuLONGEST" objects finalized: total %"PRIuLONGEST - " of %"PRIuLONGEST"\n", final_this_time, finals, object_count); + " of %"PRIuLONGEST"\n", (ulongest_t)final_this_time, + (ulongest_t)finals, (ulongest_t)object_count); } cdie(finals == object_count, "Not all objects were finalized."); } @@ -183,6 +182,8 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n"); MPS_ARGS_BEGIN(args) { + /* Allocate into generation 0 so that they get finalized quickly. */ + MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent); die(mps_pool_create_k(&pool, arena, pool_class, args), @@ -221,8 +222,10 @@ int main(int argc, char *argv[]) die(mps_thread_reg(&thread, arena), "thread_reg\n"); test(arena, mps_class_amc()); - /* TODO: test(arena, mps_class_ams()); */ - /* TODO: test(arena, mps_class_awl()); */ + test(arena, mps_class_amcz()); + test(arena, mps_class_ams()); + test(arena, mps_class_awl()); + /* TODO: test(arena, mps_class_lo()); */ mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/fmtdytst.c b/mps/code/fmtdytst.c index 376c43aa7df..c7971098704 100644 --- a/mps/code/fmtdytst.c +++ b/mps/code/fmtdytst.c @@ -73,8 +73,12 @@ mps_res_t dylan_make_wrappers(void) * If the raw memory is large enough, initialises it to a dylan-vector, * whose slots are initialised to either dylan-ints, or valid refs, at * random. - * Caller must supply an array of (at least 1) valid refs to copy, via - * the "refs" and "nr_refs" arguments. + * + * Caller must supply an array of valid refs to copy, via the "refs" + * and "nr_refs" arguments. If "nr_refs" is 0, all slots are + * initialized to dylan-ints: this may be useful for making leaf + * objects. + * * (Makes a pad if the raw memory is too small to hold a dylan-vector) */ @@ -100,7 +104,7 @@ mps_res_t dylan_init(mps_addr_t addr, size_t size, for(i = 0; i < t; ++i) { mps_word_t r = rnd(); - if(r & 1) + if(nr_refs == 0 || (r & 1)) p[2+i] = ((r & ~(mps_word_t)3) | 1); /* random int */ else p[2+i] = (mps_word_t)refs[(r >> 1) % nr_refs]; /* random ptr */ diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c index 5299c8f3525..11900130a71 100644 --- a/mps/code/fmtscheme.c +++ b/mps/code/fmtscheme.c @@ -12,14 +12,8 @@ /* special objects */ -obj_t obj_empty; /* (), the empty list */ -obj_t obj_eof; /* end of file */ -obj_t obj_error; /* error indicator */ -obj_t obj_true; /* #t, boolean true */ -obj_t obj_false; /* #f, boolean false */ -obj_t obj_undefined; /* undefined result indicator */ -obj_t obj_tail; /* tail recursion indicator */ -obj_t obj_deleted; /* deleted key in hashtable */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ /* MPS globals */ diff --git a/mps/code/fotest.c b/mps/code/fotest.c index f3d683cf674..2729395c0df 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -28,7 +28,7 @@ #include "mpmtypes.h" #include "poolmfs.h" -#include +#include /* printf */ #define testArenaSIZE ((((size_t)3)<<24) - 4) @@ -181,7 +181,7 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); - alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN; + alignment = sizeof(void *) << (rnd() % 4); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, (64 + rnd() % 64) * 1024); MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, (1 + rnd() % 8) * 8); @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); - alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN; + alignment = sizeof(void *) << (rnd() % 4); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ALIGN, alignment); MPS_ARGS_ADD(args, MPS_KEY_MIN_SIZE, (1 + rnd() % 4) * 4); diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 61b6e925e94..2a18d1a7d10 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -7,18 +7,16 @@ */ #include "mps.c" - -#include -#include -#include -#include -#include #include "getopt.h" #include "testlib.h" - +#include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" +#include /* fprintf, printf, putchars, sscanf, stderr, stdout */ +#include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ +#include /* clock, CLOCKS_PER_SEC */ + #define RESMUST(expr) \ do { \ mps_res_t res = (expr); \ @@ -56,7 +54,7 @@ typedef struct gcthread_s *gcthread_t; typedef void *(*gcthread_fn_t)(gcthread_t thread); struct gcthread_s { - pthread_t pthread; + testthr_t thread; mps_thr_t mps_thread; mps_root_t reg_root; mps_ap_t ap; @@ -189,23 +187,12 @@ static void weave(gcthread_fn_t fn) for (t = 0; t < nthreads; ++t) { gcthread_t thread = &threads[t]; - int err; thread->fn = fn; - err = pthread_create(&thread->pthread, NULL, start, thread); - if (err != 0) { - fprintf(stderr, "Unable to create thread: %d\n", err); - exit(EXIT_FAILURE); - } + testthr_create(&thread->thread, start, thread); } - for (t = 0; t < nthreads; ++t) { - gcthread_t thread = &threads[t]; - int err = pthread_join(thread->pthread, NULL); - if (err != 0) { - fprintf(stderr, "Unable to join thread: %d\n", err); - exit(EXIT_FAILURE); - } - } + for (t = 0; t < nthreads; ++t) + testthr_join(&threads[t].thread, NULL); } static void weave1(gcthread_fn_t fn) @@ -331,8 +318,8 @@ int main(int argc, char *argv[]) { double mort = 0.0; cap = (size_t)strtoul(optarg, &p, 10); switch(toupper(*p)) { - case 'G': cap *= 1024; /* fall through */ - case 'M': cap *= 1024; /* fall through */ + case 'G': cap <<= 20; p++; break; + case 'M': cap <<= 10; p++; break; case 'K': p++; break; default: cap = 0; break; } @@ -353,9 +340,9 @@ int main(int argc, char *argv[]) { char *p; arenasize = (unsigned)strtoul(optarg, &p, 10); switch(toupper(*p)) { - case 'G': arenasize *= 1024; - case 'M': arenasize *= 1024; - case 'K': arenasize *= 1024; break; + case 'G': arenasize <<= 30; break; + case 'M': arenasize <<= 20; break; + case 'K': arenasize <<= 10; break; case '\0': break; default: fprintf(stderr, "Bad arena size %s\n", optarg); @@ -432,7 +419,8 @@ int main(int argc, char *argv[]) { argv += optind; printf("seed: %lu\n", seed); - + (void)fflush(stdout); + while (argc > 0) { for (i = 0; i < sizeof(pools) / sizeof(pools[0]); ++i) if (strcmp(argv[0], pools[i].name) == 0) diff --git a/mps/code/getopt.h b/mps/code/getopt.h index ad2a956608c..fb9c789d235 100644 --- a/mps/code/getopt.h +++ b/mps/code/getopt.h @@ -48,8 +48,6 @@ #ifndef _GETOPT_H_ #define _GETOPT_H_ -#include - /* * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension. * getopt() is declared here too for GNU programs. @@ -72,7 +70,6 @@ struct option { int val; }; -__BEGIN_DECLS int getopt_long(int, char * const *, const char *, const struct option *, int *); int getopt_long_only(int, char * const *, const char *, @@ -88,6 +85,5 @@ extern int optind, opterr, optopt; #define _OPTRESET_DECLARED extern int optreset; /* getopt(3) external variable */ #endif -__END_DECLS #endif /* !_GETOPT_H_ */ diff --git a/mps/code/global.c b/mps/code/global.c index 22326aa391f..5f635206bd9 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -397,25 +397,7 @@ void GlobalsFinish(Globals arenaGlobals) Arena arena; Rank rank; - /* Check that the tear-down is complete: that the client has - * destroyed all data structures associated with the arena. We do - * this *before* calling AVERT(Globals, arenaGlobals) because the - * AVERT will crash if there are any remaining data structures, and - * it is politer to assert than to crash. (The crash would happen - * because by this point in the code the control pool has been - * destroyed and so the address space containing all these rings has - * potentially been unmapped, and so RingCheck dereferences a - * pointer into that unmapped memory.) See job000652. */ arena = GlobalsArena(arenaGlobals); - AVER(RingIsSingle(&arena->formatRing)); - AVER(RingIsSingle(&arena->chainRing)); - AVER(RingIsSingle(&arena->messageRing)); - AVER(RingIsSingle(&arena->threadRing)); - for(rank = 0; rank < RankLIMIT; ++rank) - AVER(RingIsSingle(&arena->greyRing[rank])); - AVER(RingIsSingle(&arenaGlobals->poolRing)); - AVER(RingIsSingle(&arenaGlobals->rootRing)); - AVERT(Globals, arenaGlobals); STATISTIC_STAT(EVENT2(ArenaWriteFaults, arena, @@ -445,6 +427,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) TraceId ti; Trace trace; Chain defaultChain; + Rank rank; AVERT(Globals, arenaGlobals); @@ -499,6 +482,31 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arena->finalPool = NULL; PoolDestroy(pool); } + + /* Check that the tear-down is complete: that the client has + * destroyed all data structures associated with the arena. We do + * this here rather than in GlobalsFinish because by the time that + * is called, the control pool has been destroyed and so the address + * space containing all these rings has potentially been unmapped, + * and so RingCheck dereferences a pointer into that unmapped memory + * and we get a crash instead of an assertion. See job000652. + */ + AVER(RingIsSingle(&arena->formatRing)); + AVER(RingIsSingle(&arena->chainRing)); + AVER(RingIsSingle(&arena->messageRing)); + AVER(RingIsSingle(&arena->threadRing)); + AVER(RingIsSingle(&arenaGlobals->rootRing)); + for(rank = 0; rank < RankLIMIT; ++rank) + AVER(RingIsSingle(&arena->greyRing[rank])); + + /* At this point the following pools still exist: + * 0. arena->freeCBSBlockPoolStruct + * 1. arena->reservoirStruct + * 2. arena->controlPoolStruct + * 3. arena->controlPoolStruct.blockPoolStruct + * 4. arena->controlPoolStruct.spanPoolStruct + */ + AVER(RingLength(&arenaGlobals->poolRing) == 5); } @@ -617,6 +625,7 @@ void ArenaLeaveRecursive(Arena arena) * version. The format is platform-specific. We won't necessarily * publish this. */ +extern MutatorFaultContext mps_exception_info; MutatorFaultContext mps_exception_info = NULL; @@ -1131,7 +1140,7 @@ void ArenaSetEmergency(Arena arena, Bool emergency) AVERT(Arena, arena); AVERT(Bool, emergency); - EVENT2(ArenaSetEmergency, arena, emergency); + EVENT2(ArenaSetEmergency, arena, BOOL(emergency)); arena->emergency = emergency; } diff --git a/mps/code/landtest.c b/mps/code/landtest.c index b3f91eb0cc4..ef13e196600 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -26,9 +26,7 @@ #include "poolmfs.h" #include "testlib.h" -#include -#include -#include +#include /* printf */ SRCID(landtest, "$Id$"); diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index dc2595c511f..24dd32b9efe 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -17,10 +17,13 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ + -Wconversion \ + -Wduplicate-enum \ -Werror \ -Wextra \ -Winline \ -Wmissing-prototypes \ + -Wmissing-variable-declarations \ -Wnested-externs \ -Wno-extended-offsetof \ -Wpointer-arith \ diff --git a/mps/code/locbwcss.c b/mps/code/locbwcss.c index 0e40c254635..dbf54e7e881 100644 --- a/mps/code/locbwcss.c +++ b/mps/code/locbwcss.c @@ -11,8 +11,7 @@ #include "mpslib.h" #include "mps.h" -#include -#include +#include /* printf */ /* some constants */ diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c index a8237f7de72..75ded6f202a 100644 --- a/mps/code/lockcov.c +++ b/mps/code/lockcov.c @@ -4,19 +4,37 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ +#include "mps.h" +#include "mpsavm.h" +#include "mpscmfs.h" #include "mpm.h" #include "testlib.h" #include "mpslib.h" -#include /* for malloc & free */ + +#include /* printf */ int main(int argc, char *argv[]) { - Lock a = malloc(LockSize()); - Lock b = malloc(LockSize()); + mps_arena_t arena; + mps_pool_t pool; + mps_addr_t p; + Lock a, b; testlib_init(argc, argv); + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize()); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + + die(mps_alloc(&p, pool, LockSize()), "alloc a"); + a = p; + die(mps_alloc(&p, pool, LockSize()), "alloc b"); + b = p; + Insist(a != NULL); Insist(b != NULL); @@ -44,8 +62,11 @@ int main(int argc, char *argv[]) LockReleaseMPM(a); LockFinish(a); LockReleaseGlobalRecursive(); - free(a); - free(b); + + mps_free(pool, a, LockSize()); + mps_free(pool, b, LockSize()); + mps_pool_destroy(pool); + mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/lockutw3.c b/mps/code/lockut.c similarity index 77% rename from mps/code/lockutw3.c rename to mps/code/lockut.c index 43f486799df..e93bdea6815 100644 --- a/mps/code/lockutw3.c +++ b/mps/code/lockut.c @@ -1,30 +1,26 @@ -/* lockutw3.c: LOCK UTILIZATION TEST +/* lockut.c: LOCK UTILIZATION TEST * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ -#include /* malloc */ - +#include "mps.h" +#include "mpsavm.h" +#include "mpscmfs.h" #include "mpm.h" #include "testlib.h" -#include "mpslib.h" +#include "testthr.h" -#include "mpswin.h" - - -#ifndef MPS_OS_W3 -#error "Relies on Win32 threads" -#endif +#include /* printf */ #define nTHREADS 4 static Lock lock; -unsigned long shared, tmp; +static unsigned long shared, tmp; -void incR(unsigned long i) +static void incR(unsigned long i) { LockClaimRecursive(lock); if (i < 100) { @@ -40,7 +36,7 @@ void incR(unsigned long i) } -void inc(unsigned long i) +static void inc(unsigned long i) { incR( (i+1) >>1); i >>= 1; @@ -59,23 +55,33 @@ void inc(unsigned long i) #define COUNT 100000l -DWORD WINAPI thread0(void *p) +static void *thread0(void *p) { - (void)p; + testlib_unused(p); inc(COUNT); - return 0; + return NULL; } int main(int argc, char *argv[]) { - DWORD id; - HANDLE t[10]; + mps_arena_t arena; + mps_pool_t pool; + mps_addr_t p; + testthr_t t[10]; unsigned i; testlib_init(argc, argv); - lock = malloc(LockSize()); + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize()); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + + die(mps_alloc(&p, pool, LockSize()), "alloc"); + lock = p; Insist(lock != NULL); LockInit(lock); @@ -84,17 +90,19 @@ int main(int argc, char *argv[]) shared = 0; for(i = 0; i < nTHREADS; i++) - t[i] = CreateThread(NULL, 0, thread0, NULL, 0, &id); + testthr_create(&t[i], thread0, NULL); - for(i = 0; i < nTHREADS; i++) { - cdie(WaitForSingleObject(t[i], INFINITE) == WAIT_OBJECT_0, - "WaitForSingleObject"); - } + for(i = 0; i < nTHREADS; i++) + testthr_join(&t[i], NULL); Insist(shared == nTHREADS*COUNT); LockFinish(lock); + mps_free(pool, lock, LockSize()); + mps_pool_destroy(pool); + mps_arena_destroy(arena); + printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; } diff --git a/mps/code/locusss.c b/mps/code/locusss.c index 3dfbc78afe1..70cf313ed45 100644 --- a/mps/code/locusss.c +++ b/mps/code/locusss.c @@ -12,8 +12,7 @@ #include "mpslib.h" #include "mps.h" -#include -#include +#include /* printf */ /* some constants */ diff --git a/mps/code/locv.c b/mps/code/locv.c index 56c9a46d2c5..06d2722dac3 100644 --- a/mps/code/locv.c +++ b/mps/code/locv.c @@ -13,6 +13,8 @@ #include "mpsclo.h" #include "mpsavm.h" +#include /* printf */ + #define testArenaSIZE ((size_t)16<<20) diff --git a/mps/code/messtest.c b/mps/code/messtest.c index 7f96360f78e..96deeebfc58 100644 --- a/mps/code/messtest.c +++ b/mps/code/messtest.c @@ -10,8 +10,7 @@ #include "testlib.h" #include "mpslib.h" -#include -#include +#include /* printf */ SRCID(messtest, "$Id$"); diff --git a/mps/code/meter.h b/mps/code/meter.h index 7a7f8266e87..f1731400e42 100644 --- a/mps/code/meter.h +++ b/mps/code/meter.h @@ -1,7 +1,7 @@ /* meter.h: METER INTERFACE * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .sources: mps.design.metrics. * @@ -45,9 +45,12 @@ extern void MeterEmit(Meter meter); #define METER_ACC(meter, delta) \ STATISTIC(MeterAccumulate(&(meter), delta)) #if defined(STATISTICS) -#define METER_WRITE(meter, stream) MeterWrite(&(meter), stream) +#define METER_WRITE(meter, stream) BEGIN \ + Res _res = MeterWrite(&(meter), (stream)); \ + if (_res != ResOK) return _res; \ + END #elif defined(STATISTICS_NONE) -#define METER_WRITE(meter, stream) (ResOK) +#define METER_WRITE(meter, stream) NOOP #else #error "No statistics configured." #endif @@ -59,7 +62,7 @@ extern void MeterEmit(Meter meter); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/misc.h b/mps/code/misc.h index 6ba4be5f49d..809fd7e954a 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -1,7 +1,7 @@ /* misc.h: MISCELLANEOUS DEFINITIONS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * Small general things which are useful for C but aren't part of the @@ -50,6 +50,7 @@ typedef const struct SrcIdStruct { #define SRCID(id, scmid) \ static SrcIdStruct id ## FileSrcIdStruct = \ {__FILE__, (scmid), __DATE__, __TIME__}; \ + extern SrcId id ## SrcId; \ SrcId id ## SrcId = &id ## FileSrcIdStruct @@ -170,6 +171,16 @@ typedef const struct SrcIdStruct { ((type *)(void *)((char *)(p) - offsetof(type, field))) +/* BITFIELD -- coerce a value into a bitfield + * + * This coerces value to the given width and type in a way that avoids + * warnings from gcc -Wconversion about possible loss of data. + */ + +#define BITFIELD(type, value, width) ((type)value & (((type)1 << (width)) - 1)) +#define BOOL(v) BITFIELD(unsigned, (v), 1) + + /* Bit Sets -- sets of integers in [0,N-1]. * * Can be used on any unsigned integral type, ty. These definitions @@ -191,6 +202,7 @@ typedef const struct SrcIdStruct { #define BS_SUB(s1, s2) BS_SUPER((s2), (s1)) #define BS_IS_SINGLE(s) ( ((s) != 0) && (((s) & ((s)-1)) == 0) ) #define BS_SYM_DIFF(s1, s2) ((s1) ^ (s2)) +#define BS_BITFIELD(ty, s) BITFIELD(ty ## Set, (s), ty ## LIMIT) #endif /* misc_h */ @@ -198,7 +210,7 @@ typedef const struct SrcIdStruct { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 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 f544acca401..a46fdf5fb10 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -174,16 +174,16 @@ Word (WordAlignDown)(Word word, Align alignment) /* SizeIsP2 -- test whether a size is a power of two */ -Bool SizeIsP2(Size size) +Bool (SizeIsP2)(Size size) { - return WordIsP2((Word)size); + return SizeIsP2(size); } /* WordIsP2 -- tests whether a word is a power of two */ -Bool WordIsP2(Word word) +Bool (WordIsP2)(Word word) { - return word > 0 && (word & (word - 1)) == 0; + return WordIsP2(word); } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 9b12eb6ccb5..422327453dc 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -143,11 +143,13 @@ extern Bool ResIsAllocFailure(Res res); * SizeFloorLog2 returns the floor of the logarithm in base 2 of size. * size can be any positive non-zero value. */ -extern Bool SizeIsP2(Size size); +extern Bool (SizeIsP2)(Size size); +#define SizeIsP2(size) WordIsP2((Word)size) extern Shift SizeLog2(Size size); extern Shift SizeFloorLog2(Size size); -extern Bool WordIsP2(Word word); +extern Bool (WordIsP2)(Word word); +#define WordIsP2(word) ((word) > 0 && ((word) & ((word) - 1)) == 0) /* Formatted Output -- see , */ @@ -709,10 +711,10 @@ extern Addr (SegLimit)(Seg seg); #define SegSummary(seg) (((GCSeg)(seg))->summary) -#define SegSetPM(seg, mode) ((void)((seg)->pm = (mode))) -#define SegSetSM(seg, mode) ((void)((seg)->sm = (mode))) -#define SegSetDepth(seg, d) ((void)((seg)->depth = (d))) -#define SegSetNailed(seg, ts) ((void)((seg)->nailed = (ts))) +#define SegSetPM(seg, mode) ((void)((seg)->pm = BS_BITFIELD(Access, (mode)))) +#define SegSetSM(seg, mode) ((void)((seg)->sm = BS_BITFIELD(Access, (mode)))) +#define SegSetDepth(seg, d) ((void)((seg)->depth = BITFIELD(unsigned, (d), ShieldDepthWIDTH))) +#define SegSetNailed(seg, ts) ((void)((seg)->nailed = BS_BITFIELD(Trace, (ts)))) /* Buffer Interface -- see */ diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index 9dd25574417..339ae5b54f4 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -7,19 +7,14 @@ #include "mpscmv.h" #include "mpscmvff.h" +#include "mpscmfs.h" #include "mpslib.h" #include "mpsavm.h" #include "testlib.h" #include "mpslib.h" #include "mps.h" -#include -#include - -/* TODO: Decide whether we should support the MPS pool class externally, - create mpscmfs.h, and replace this extern with proper use of its - interface. */ -extern mps_class_t PoolClassMFS(void); +#include /* printf */ #define testArenaSIZE ((((size_t)64)<<20) - 4) @@ -156,8 +151,7 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options) printf("MFS\n"); fixedSizeSize = 13; - die(stress(PoolClassMFS(), - fixedSize, arena, (size_t)100000, fixedSizeSize), + die(stress(mps_class_mfs(), fixedSize, arena, (size_t)100000, fixedSizeSize), "stress MFS"); printf("MV\n"); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 3dd920758f0..80bbd298090 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -1,7 +1,7 @@ /* mpmst.h: MEMORY POOL MANAGER DATA STRUCTURES * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * .design: This header file crosses module boundaries. The relevant @@ -275,8 +275,8 @@ typedef struct SegStruct { /* segment structure */ RingStruct poolRing; /* link in list of segs in pool */ Addr limit; /* limit of segment */ unsigned depth : ShieldDepthWIDTH; /* see */ - AccessSet pm : AccessSetWIDTH; /* protection mode, */ - AccessSet sm : AccessSetWIDTH; /* shield mode, */ + AccessSet pm : AccessLIMIT; /* protection mode, */ + AccessSet sm : AccessLIMIT; /* shield mode, */ TraceSet grey : TraceLIMIT; /* traces for which seg is grey */ TraceSet white : TraceLIMIT; /* traces for which seg is white */ TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */ @@ -817,7 +817,7 @@ typedef struct AllocPatternStruct { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 5d1a195fe45..d8eebb7bcd6 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -287,7 +287,7 @@ typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream); #define AccessSetEMPTY ((AccessSet)0) /* */ #define AccessREAD ((AccessSet)(1<<0)) #define AccessWRITE ((AccessSet)(1<<1)) -#define AccessSetWIDTH (2) +#define AccessLIMIT (2) #define RefSetEMPTY BS_EMPTY(RefSet) #define RefSetUNIV BS_UNIV(RefSet) #define ZoneSetEMPTY BS_EMPTY(ZoneSet) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 24381fa5c02..8b87dd9e7fc 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ 3114A65B156E95B4001E0AA3 /* PBXTargetDependency */, 2231BB6D18CA986B002D6322 /* PBXTargetDependency */, 31D60034156D3D5A00337B26 /* PBXTargetDependency */, + 2286E4C918F4389E004111E2 /* PBXTargetDependency */, 2231BB6F18CA986D002D6322 /* PBXTargetDependency */, 3114A5A0156E915A001E0AA3 /* PBXTargetDependency */, 3114A6A7156E9739001E0AA3 /* PBXTargetDependency */, @@ -88,6 +89,10 @@ 224CC793175E1821002FF81B /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 224CC79F175E321C002FF81B /* mv2test.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A686156E9674001E0AA3 /* mv2test.c */; }; 224CC7A0175E322C002FF81B /* fotest.c in Sources */ = {isa = PBXBuildFile; fileRef = 224CC79E175E3202002FF81B /* fotest.c */; }; + 22561A9818F4265D00372C66 /* testthrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 22561A9718F4263300372C66 /* testthrix.c */; }; + 22561A9918F4266600372C66 /* testthrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 22561A9718F4263300372C66 /* testthrix.c */; }; + 22561A9A18F426BB00372C66 /* testthrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 22561A9718F4263300372C66 /* testthrix.c */; }; + 22561A9B18F426F300372C66 /* testthrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 22561A9718F4263300372C66 /* testthrix.c */; }; 2291A5B1175CAB2F001D4920 /* fmtdy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC6156BE48D00753214 /* fmtdy.c */; }; 2291A5B2175CAB2F001D4920 /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; 2291A5B3175CAB2F001D4920 /* fmthe.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAE4156BE6D500753214 /* fmthe.c */; }; @@ -113,6 +118,10 @@ 22C2ACA718BE400A006B3677 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 22C2ACA918BE400A006B3677 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 22C2ACB018BE4049006B3677 /* nailboardtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C2ACA018BE3FEC006B3677 /* nailboardtest.c */; }; + 22F846B518F437B900982BA7 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; + 22F846B718F437B900982BA7 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; + 22F846BE18F437D700982BA7 /* lockut.c in Sources */ = {isa = PBXBuildFile; fileRef = 22F846AF18F4379C00982BA7 /* lockut.c */; }; + 22F846BF18F437E000982BA7 /* testthrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 22561A9718F4263300372C66 /* testthrix.c */; }; 22FA176916E8D6FC0098B23F /* fmtdy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC6156BE48D00753214 /* fmtdy.c */; }; 22FA176A16E8D6FC0098B23F /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; 22FA176B16E8D6FC0098B23F /* fmthe.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAE4156BE6D500753214 /* fmthe.c */; }; @@ -327,6 +336,13 @@ remoteGlobalIDString = 2D604B9B16514B1A003AAF46; remoteInfo = mpseventtxt; }; + 2286E4C818F4389E004111E2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 22F846B018F437B900982BA7; + remoteInfo = lockut; + }; 2291A5AE175CAB2F001D4920 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -418,6 +434,13 @@ remoteGlobalIDString = 3104AFF1156D37A0000A585A; remoteInfo = all; }; + 22F846B218F437B900982BA7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 31EEABFA156AAF9D00714D05; + remoteInfo = mps; + }; 22FA176616E8D6FC0098B23F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -955,6 +978,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 22F846B818F437B900982BA7 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 22FA177016E8D6FC0098B23F /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1297,6 +1329,8 @@ 2231BB6918CA983C002D6322 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; }; 224CC799175E1821002FF81B /* fotest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fotest; sourceTree = BUILT_PRODUCTS_DIR; }; 224CC79E175E3202002FF81B /* fotest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fotest.c; sourceTree = ""; }; + 22561A9618F4263300372C66 /* testthr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testthr.h; sourceTree = ""; }; + 22561A9718F4263300372C66 /* testthrix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testthrix.c; sourceTree = ""; }; 2291A5A8175CAA51001D4920 /* poolmv2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = poolmv2.h; sourceTree = ""; }; 2291A5A9175CAA9B001D4920 /* awlutth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = awlutth.c; sourceTree = ""; }; 2291A5AA175CAA9B001D4920 /* exposet0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exposet0.c; sourceTree = ""; }; @@ -1317,6 +1351,8 @@ 22C2ACAF18BE400A006B3677 /* nailboardtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nailboardtest; sourceTree = BUILT_PRODUCTS_DIR; }; 22E30E821886FF1400D98EA9 /* nailboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nailboard.c; sourceTree = ""; }; 22E30E831886FF1400D98EA9 /* nailboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nailboard.h; sourceTree = ""; }; + 22F846AF18F4379C00982BA7 /* lockut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lockut.c; sourceTree = ""; }; + 22F846BD18F437B900982BA7 /* lockut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lockut; sourceTree = BUILT_PRODUCTS_DIR; }; 22C5C99A18EC6AEC004C63D4 /* failover.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = failover.c; sourceTree = ""; }; 22C5C99B18EC6AEC004C63D4 /* failover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failover.h; sourceTree = ""; }; 22C5C99C18EC6AEC004C63D4 /* land.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land.c; sourceTree = ""; }; @@ -1331,8 +1367,6 @@ 22FACED5188807FF000FDBC1 /* fmtno.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmtno.h; sourceTree = ""; }; 22FACED6188807FF000FDBC1 /* fmtscheme.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmtscheme.c; sourceTree = ""; }; 22FACED7188807FF000FDBC1 /* fmtscheme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmtscheme.h; sourceTree = ""; }; - 22FACED8188807FF000FDBC1 /* locbwcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locbwcss.c; sourceTree = ""; }; - 22FACED9188807FF000FDBC1 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; }; 22FACEDA1888088A000FDBC1 /* ss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ss.c; sourceTree = ""; }; 22FACEDB188808D5000FDBC1 /* mpscmfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpscmfs.h; sourceTree = ""; }; 22FACEDC18880933000FDBC1 /* poolmfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = poolmfs.h; sourceTree = ""; }; @@ -1670,6 +1704,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 22F846B618F437B900982BA7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 22F846B718F437B900982BA7 /* libmps.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 22FA176E16E8D6FC0098B23F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2087,6 +2129,7 @@ 3124CAB3156BE1B700753214 /* Tests */ = { isa = PBXGroup; children = ( + 22F846AF18F4379C00982BA7 /* lockut.c */, 3114A63D156E94EA001E0AA3 /* abqtest.c */, 22FACED1188807FF000FDBC1 /* airtest.c */, 3124CAF5156BE81100753214 /* amcss.c */, @@ -2134,6 +2177,8 @@ 3114A628156E949A001E0AA3 /* teletest.c */, 31EEAC9E156AB73400714D05 /* testlib.c */, 2291A5F0175CB7A4001D4920 /* testlib.h */, + 22561A9618F4263300372C66 /* testthr.h */, + 22561A9718F4263300372C66 /* testthrix.c */, 3114A6BA156E9768001E0AA3 /* walkt0.c */, 31D6005E156D3F4A00337B26 /* zcoll.c */, 31D6007B156D3FCC00337B26 /* zmess.c */, @@ -2227,6 +2272,7 @@ 2231BB6718CA97DC002D6322 /* locusss */, 22FACEED18880983000FDBC1 /* airtest */, 22C2ACAF18BE400A006B3677 /* nailboardtest */, + 22F846BD18F437B900982BA7 /* lockut */, ); name = Products; sourceTree = ""; @@ -2558,6 +2604,24 @@ productReference = 22C2ACAF18BE400A006B3677 /* nailboardtest */; productType = "com.apple.product-type.tool"; }; + 22F846B018F437B900982BA7 /* lockut */ = { + isa = PBXNativeTarget; + buildConfigurationList = 22F846B918F437B900982BA7 /* Build configuration list for PBXNativeTarget "lockut" */; + buildPhases = ( + 22F846B318F437B900982BA7 /* Sources */, + 22F846B618F437B900982BA7 /* Frameworks */, + 22F846B818F437B900982BA7 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 22F846B118F437B900982BA7 /* PBXTargetDependency */, + ); + name = lockut; + productName = lockcov; + productReference = 22F846BD18F437B900982BA7 /* lockut */; + productType = "com.apple.product-type.tool"; + }; 22FA176416E8D6FC0098B23F /* amcssth */ = { isa = PBXNativeTarget; buildConfigurationList = 22FA177116E8D6FC0098B23F /* Build configuration list for PBXNativeTarget "amcssth" */; @@ -3284,6 +3348,7 @@ 2231BB4C18CA97D8002D6322 /* locbwcss */, 31D60026156D3D3E00337B26 /* lockcov */, 2231BB5A18CA97DC002D6322 /* locusss */, + 22F846B018F437B900982BA7 /* lockut */, 3114A58F156E913C001E0AA3 /* locv */, 3114A694156E971B001E0AA3 /* messtest */, 31EEAC64156AB52600714D05 /* mpmss */, @@ -3363,6 +3428,7 @@ 2291A5B3175CAB2F001D4920 /* fmthe.c in Sources */, 2291A5B4175CAB2F001D4920 /* fmtno.c in Sources */, 2291A5B5175CAB2F001D4920 /* testlib.c in Sources */, + 22561A9918F4266600372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3408,6 +3474,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 22F846B318F437B900982BA7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 22F846BE18F437D700982BA7 /* lockut.c in Sources */, + 22F846B518F437B900982BA7 /* testlib.c in Sources */, + 22F846BF18F437E000982BA7 /* testthrix.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 22FA176716E8D6FC0098B23F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3418,6 +3494,7 @@ 22FA176B16E8D6FC0098B23F /* fmthe.c in Sources */, 22FA176C16E8D6FC0098B23F /* fmtno.c in Sources */, 22FA176D16E8D6FC0098B23F /* testlib.c in Sources */, + 22561A9818F4265D00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3694,6 +3771,7 @@ 318DA8D31892B27E0089718C /* testlib.c in Sources */, 6313D47318A4028E00EB03EF /* djbench.c in Sources */, 318DA8D21892B13B0089718C /* getoptl.c in Sources */, + 22561A9A18F426BB00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3801,6 +3879,7 @@ 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */, 6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */, 6313D46A18A400B200EB03EF /* getoptl.c in Sources */, + 22561A9B18F426F300372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3842,6 +3921,11 @@ target = 2D604B9B16514B1A003AAF46 /* mpseventtxt */; targetProxy = 2275798816C5422900B662B0 /* PBXContainerItemProxy */; }; + 2286E4C918F4389E004111E2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 22F846B018F437B900982BA7 /* lockut */; + targetProxy = 2286E4C818F4389E004111E2 /* PBXContainerItemProxy */; + }; 2291A5AD175CAB2F001D4920 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -3907,6 +3991,11 @@ target = 3104AFF1156D37A0000A585A /* all */; targetProxy = 22CDE92D16E9EB9300366D0A /* PBXContainerItemProxy */; }; + 22F846B118F437B900982BA7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 31EEABFA156AAF9D00714D05 /* mps */; + targetProxy = 22F846B218F437B900982BA7 /* PBXContainerItemProxy */; + }; 22FA176516E8D6FC0098B23F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -4410,6 +4499,27 @@ }; name = Release; }; + 22F846BA18F437B900982BA7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = lockut; + }; + name = Debug; + }; + 22F846BB18F437B900982BA7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = lockut; + }; + name = Release; + }; + 22F846BC18F437B900982BA7 /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = lockut; + }; + name = RASH; + }; 22FA177216E8D6FC0098B23F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5547,6 +5657,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 22F846B918F437B900982BA7 /* Build configuration list for PBXNativeTarget "lockut" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 22F846BA18F437B900982BA7 /* Debug */, + 22F846BB18F437B900982BA7 /* Release */, + 22F846BC18F437B900982BA7 /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 22FA177116E8D6FC0098B23F /* Build configuration list for PBXNativeTarget "amcssth" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index a4d8c3750b5..55396aee3fe 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -15,13 +15,8 @@ #include "fmtdytst.h" #include "mps.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -# include "mpsw3.h" -#endif -#include -#include -#include -#include + +#include /* printf */ #define exactRootsCOUNT 49 diff --git a/mps/code/mpswin.h b/mps/code/mpswin.h index 0840f1371a3..2f88fc25c19 100644 --- a/mps/code/mpswin.h +++ b/mps/code/mpswin.h @@ -11,11 +11,15 @@ #ifndef mpswin_h #define mpswin_h +#ifndef WIN32_LEAN_AND_MEAN /* Speed up the build process by excluding parts of windows.h that we * don't use. See */ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN +#else +#include +#endif #endif /* mpswin_h */ diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index 8744514662b..852c98949e7 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -30,26 +30,36 @@ static Count nailboardLevels(Count nails) } +/* nailboardNails -- return the total number of nails in the board */ + +static Count nailboardNails(Nailboard board) +{ + return RangeSize(&board->range) >> board->alignShift; +} + + /* nailboardLevelBits -- return the number of bits in the bit table * for the given level. */ -static Count nailboardLevelBits(Nailboard board, Index level) +static Count nailboardLevelBits(Count nails, Index level) { - /* Use <= rather than < because of .check.levels. */ - AVER(level <= board->levels); - return RangeSize(&board->range) >> (board->alignShift + level * LEVEL_SHIFT); + Shift shift = (Shift)(level * LEVEL_SHIFT); + return (nails + ((Count)1 << shift) - 1) >> shift; } Bool NailboardCheck(Nailboard board) { Index i; + Count nails; CHECKS(Nailboard, board); CHECKL(RangeCheck(&board->range)); CHECKL(0 < board->levels); - CHECKL(board->levels == nailboardLevels(nailboardLevelBits(board, 0))); - CHECKL(nailboardLevelBits(board, board->levels - 1) != 0); - CHECKL(nailboardLevelBits(board, board->levels) == 0); /* .check.levels */ + nails = nailboardNails(board); + CHECKL(board->levels == nailboardLevels(nails)); + CHECKL(nails == nailboardLevelBits(nails, 0)); + CHECKL(nailboardLevelBits(nails, board->levels - 1) != 0); + CHECKL(nailboardLevelBits(nails, board->levels) == 1); CHECKL(BoolCheck(board->newNails)); for (i = 0; i < board->levels; ++i) { CHECKL(board->level[i] != NULL); @@ -80,8 +90,7 @@ static Size nailboardSize(Count nails, Count levels) Size size; size = nailboardStructSize(levels); for (i = 0; i < levels; ++i) { - size += BTSize(nails); - nails >>= LEVEL_SHIFT; + size += BTSize(nailboardLevelBits(nails, i)); } return size; } @@ -130,11 +139,11 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment, p = PointerAdd(p, nailboardStructSize(levels)); for (i = 0; i < levels; ++i) { - AVER(nails > 0); + Count levelBits = nailboardLevelBits(nails, i); + AVER(levelBits > 0); board->level[i] = p; - BTResRange(board->level[i], 0, nails); - p = PointerAdd(p, BTSize(nails)); - nails >>= LEVEL_SHIFT; + BTResRange(board->level[i], 0, levelBits); + p = PointerAdd(p, BTSize(levelBits)); } board->sig = NailboardSig; @@ -154,7 +163,7 @@ void NailboardDestroy(Nailboard board, Arena arena) AVERT(Nailboard, board); AVERT(Arena, arena); - nails = nailboardLevelBits(board, 0); + nails = nailboardNails(board); size = nailboardSize(nails, board->levels); board->sig = SigInvalid; @@ -191,8 +200,10 @@ Bool (NailboardNewNails)(Nailboard board) static Index nailboardIndex(Nailboard board, Index level, Addr addr) { - return AddrOffset(RangeBase(&board->range), addr) + Index i = AddrOffset(RangeBase(&board->range), addr) >> (board->alignShift + level * LEVEL_SHIFT); + AVER_CRITICAL(i < nailboardLevelBits(nailboardNails(board), level)); + return i; } @@ -414,7 +425,7 @@ Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream) return res; for(i = 0; i < board->levels; ++i) { - Count levelNails = nailboardLevelBits(board, i); + Count levelNails = nailboardLevelBits(nailboardNails(board), i); Count resetNails = BTCountResRange(board->level[i], 0, levelNails); res = WriteF(stream, " Level $U ($U bits, $U set): ", i, levelNails, levelNails - resetNails, NULL); diff --git a/mps/code/nailboardtest.c b/mps/code/nailboardtest.c index a78ba4b3b9e..24bf3be36c2 100644 --- a/mps/code/nailboardtest.c +++ b/mps/code/nailboardtest.c @@ -12,6 +12,8 @@ #include "bt.h" #include "nailboard.h" +#include /* printf */ + static void test(mps_arena_t arena) { diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index bbc582676a3..aeb04454efe 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -32,7 +32,7 @@ static Nailboard amcSegNailboard(Seg seg); static Bool AMCCheck(AMC amc); static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO); static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO); -extern PoolClass AMCPoolClassGet(void); +extern PoolClass AMCZPoolClassGet(void); extern BufferClass amcBufClassGet(void); extern SegClass amcSegClassGet(void); @@ -2164,7 +2164,7 @@ static void amcWalkAll(Pool pool, FormattedObjectsStepMethod f, Arena arena; Ring ring, next, node; - AVER(IsSubclassPoly(pool->class, AMCPoolClassGet())); + AVER(IsSubclassPoly(pool->class, AMCZPoolClassGet())); arena = PoolArena(pool); ring = PoolSegRing(pool); @@ -2449,7 +2449,7 @@ static Bool AMCCheck(AMC amc) { CHECKS(AMC, amc); CHECKD(Pool, &amc->poolStruct); - CHECKL(IsSubclassPoly(amc->poolStruct.class, EnsureAMCPoolClass())); + CHECKL(IsSubclassPoly(amc->poolStruct.class, AMCZPoolClassGet())); CHECKL(RankSetCheck(amc->rankSet)); CHECKD_NOSIG(Ring, &amc->genRing); CHECKL(BoolCheck(amc->gensBooted)); diff --git a/mps/code/poolams.c b/mps/code/poolams.c index c67a2efd684..d769630f009 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -74,6 +74,11 @@ Bool AMSSegCheck(AMSSeg amsseg) CHECKD_NOSIG(BT, amsseg->nongreyTable); CHECKD_NOSIG(BT, amsseg->nonwhiteTable); + /* If tables are shared, they mustn't both be in use. */ + CHECKL(!(amsseg->ams->shareAllocTable + && amsseg->allocTableInUse + && amsseg->colourTablesInUse)); + return TRUE; } @@ -167,6 +172,10 @@ static Res amsCreateTables(AMS ams, BT *allocReturn, goto failWhite; } + /* Invalidate the colour tables in checking varieties. */ + AVER((BTResRange(nongreyTable, 0, length), TRUE)); + AVER((BTSetRange(nonwhiteTable, 0, length), TRUE)); + *allocReturn = allocTable; *nongreyReturn = nongreyTable; *nonwhiteReturn = nonwhiteTable; @@ -1023,7 +1032,8 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(limitIndex <= amsseg->firstFree); if (limitIndex == amsseg->firstFree) /* is it at the end? */ { amsseg->firstFree = initIndex; - } else { /* start using allocTable */ + } else if (!ams->shareAllocTable || !amsseg->colourTablesInUse) { + /* start using allocTable */ amsseg->allocTableInUse = TRUE; BTSetRange(amsseg->allocTable, 0, amsseg->firstFree); if (amsseg->firstFree < amsseg->grains) @@ -1415,16 +1425,20 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) /* doing that here (this can be called from RootScan, during flip). */ clientRef = *refIO; + AVER_CRITICAL(SegBase(seg) <= clientRef); + AVER_CRITICAL(clientRef < SegLimit(seg)); /* see .ref-limit */ base = AddrSub((Addr)clientRef, format->headerSize); /* can get an ambiguous reference too close to the base of the * segment, so when we subtract the header we are not in the * segment any longer. This isn't a real reference, * so we can just skip it. */ if (base < SegBase(seg)) { - return ResOK; + AVER_CRITICAL(ss->rank == RankAMBIG); + return ResOK; } i = AMS_ADDR_INDEX(seg, base); + AVER_CRITICAL(i < amsseg->grains); AVER_CRITICAL(!AMS_IS_INVALID_COLOUR(seg, i)); ss->wasMarked = TRUE; @@ -1584,12 +1598,13 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) /* preservedInPlaceCount is updated on fix */ trace->preservedInPlaceSize += (grains - amsseg->free) << ams->grainShift; + /* Ensure consistency of segment even if are just about to free it */ + amsseg->colourTablesInUse = FALSE; + SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); + if (amsseg->free == grains && SegBuffer(seg) == NULL) { /* No survivors */ SegFree(seg); - } else { - amsseg->colourTablesInUse = FALSE; - SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); } } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 6332a91b7cd..cbece0b41fe 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -305,10 +305,14 @@ DEFINE_SEG_CLASS(AWLSegClass, class) * it's possible to tweak them in a debugger. */ +extern Count AWLSegSALimit; Count AWLSegSALimit = AWL_SEG_SA_LIMIT; +extern Bool AWLHaveSegSALimit; Bool AWLHaveSegSALimit = AWL_HAVE_SEG_SA_LIMIT; +extern Count AWLTotalSALimit; Count AWLTotalSALimit = AWL_TOTAL_SA_LIMIT; +extern Bool AWLHaveTotalSALimit; Bool AWLHaveTotalSALimit = AWL_HAVE_TOTAL_SA_LIMIT; @@ -558,6 +562,7 @@ static Res AWLInit(Pool pool, ArgList args) AVERT(Format, format); pool->format = format; + pool->alignment = format->alignment; AVER(FUNCHECK(findDependent)); awl->findDependent = findDependent; @@ -570,7 +575,7 @@ static Res AWLInit(Pool pool, ArgList args) if (res != ResOK) goto failGenInit; - awl->alignShift = SizeLog2(pool->alignment); + awl->alignShift = SizeLog2(PoolAlignment(pool)); awl->size = (Size)0; awl->succAccesses = 0; @@ -937,7 +942,7 @@ static Res awlScanSinglePass(Bool *anyScannedReturn, i = awlIndexOfAddr(base, awl, p); if (!BTGet(awlseg->alloc, i)) { - p = AddrAdd(p, pool->alignment); + p = AddrAdd(p, PoolAlignment(pool)); continue; } hp = AddrAdd(p, format->headerSize); @@ -954,7 +959,8 @@ static Res awlScanSinglePass(Bool *anyScannedReturn, } objectLimit = AddrSub(objectLimit, format->headerSize); AVER(p < objectLimit); - p = AddrAlignUp(objectLimit, pool->alignment); + AVER(AddrIsAligned(objectLimit, PoolAlignment(pool))); + p = objectLimit; } AVER(p == limit); @@ -1051,7 +1057,7 @@ static Res AWLFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) switch(ss->rank) { case RankAMBIG: /* not a real pointer if not aligned or not allocated */ - if (!AddrIsAligned(base, pool->alignment) || !BTGet(awlseg->alloc, i)) + if (!AddrIsAligned(base, sizeof(void *)) || !BTGet(awlseg->alloc, i)) return ResOK; /* falls through */ case RankEXACT: @@ -1125,7 +1131,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) } q = format->skip(AddrAdd(p, format->headerSize)); q = AddrSub(q, format->headerSize); - q = AddrAlignUp(q, pool->alignment); + AVER(AddrIsAligned(q, PoolAlignment(pool))); j = awlIndexOfAddr(base, awl, q); AVER(j <= awlseg->grains); if(BTGet(awlseg->mark, i)) { @@ -1243,13 +1249,13 @@ static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, i = awlIndexOfAddr(base, awl, object); if (!BTGet(awlseg->alloc, i)) { /* This grain is free */ - object = AddrAdd(object, pool->alignment); + object = AddrAdd(object, PoolAlignment(pool)); continue; } object = AddrAdd(object, format->headerSize); next = format->skip(object); next = AddrSub(next, format->headerSize); - next = AddrAlignUp(next, pool->alignment); + AVER(AddrIsAligned(next, PoolAlignment(pool))); if (BTGet(awlseg->mark, i) && BTGet(awlseg->scanned, i)) (*f)(object, pool->format, pool, p, s); object = next; diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index fbb125a71f2..214b2b232d3 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -136,7 +136,7 @@ static Res MFSInit(Pool pool, ArgList args) mfs->sig = MFSSig; AVERT(MFS, mfs); - EVENT5(PoolInitMFS, pool, arena, extendBy, extendSelf, unitSize); + EVENT5(PoolInitMFS, pool, arena, extendBy, BOOL(extendSelf), unitSize); return ResOK; } diff --git a/mps/code/poolmv.h b/mps/code/poolmv.h index 098cd3eaa2e..8e6885254bc 100644 --- a/mps/code/poolmv.h +++ b/mps/code/poolmv.h @@ -1,41 +1,16 @@ /* poolmv.h: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .purpose: This is the interface to the manual-variable pool class. * - * .mv: Manual-variable pools manage variably-sized blocks of memory in a - * flexible manner. They have higher overheads than a fixed-size pool. + * .mv: Manual-variable pools manage variably-sized blocks of memory + * in a flexible manner. They have higher overheads than a fixed-size + * pool. * - * .init: This class adds the following arguments to PoolCreate: - * - * Size extendBy - * - * extendBy is the default number of bytes reserved by the pool at a time. - * A large size will make allocation cheaper but have a higher resource - * overhead. A typical value might be 65536. See note 2. - * - * Size avgSize - * - * avgSize is an estimate of the average size of an allocation, and is used - * to choose the size of internal tables. An accurate estimate will - * improve the efficiency of the pool. A low estimate will make the pool - * less space efficient. A high estimate will make the pool less time - * efficient. A typical value might be 32. avgSize must not be less than - * extendBy. - * - * Size maxSize - * - * maxSize is an estimate of the maximum total size that the pool will - * reach. Setting this parameter does not actually contrain the pool, but - * an accurate estimate will improve the efficiency of the pool. maxSize - * must not be less than extendBy. - * - * Notes - * 2. The documentation could suggest a segment size according to the - * distribution of allocation size requests. richard 1994-11-08 + * .design: See */ #ifndef poolmv_h @@ -59,7 +34,7 @@ extern Bool MVCheck(MV mv); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 9d73e358a42..5c0a8265d3b 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -81,7 +81,6 @@ typedef struct MVTStruct Bool abqOverflow; /* ABQ dropped some candidates */ /* .* */ Bool splinter; /* Saved splinter */ - Seg splinterSeg; /* Saved splinter seg */ Addr splinterBase; /* Saved splinter base */ Addr splinterLimit; /* Saved splinter size */ @@ -136,7 +135,7 @@ typedef struct MVTStruct DEFINE_POOL_CLASS(MVTPoolClass, this) { - INHERIT_CLASS(this, AbstractSegBufPoolClass); + INHERIT_CLASS(this, AbstractBufferPoolClass); this->name = "MVT"; this->size = sizeof(MVTStruct); this->offset = offsetof(MVTStruct, poolStruct); @@ -311,7 +310,6 @@ static Res MVTInit(Pool pool, ArgList args) mvt->maxSize = maxSize; mvt->fragLimit = fragLimit; mvt->splinter = FALSE; - mvt->splinterSeg = NULL; mvt->splinterBase = (Addr)0; mvt->splinterLimit = (Addr)0; @@ -400,9 +398,7 @@ static Bool MVTCheck(MVT mvt) if (mvt->splinter) { CHECKL(AddrOffset(mvt->splinterBase, mvt->splinterLimit) >= mvt->minSize); - CHECKD(Seg, mvt->splinterSeg); - CHECKL(mvt->splinterBase >= SegBase(mvt->splinterSeg)); - CHECKL(mvt->splinterLimit <= SegLimit(mvt->splinterSeg)); + CHECKL(mvt->splinterBase < mvt->splinterLimit); } CHECKL(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); @@ -937,7 +933,6 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer, } mvt->splinter = TRUE; - mvt->splinterSeg = BufferSeg(buffer); mvt->splinterBase = base; mvt->splinterLimit = limit; } @@ -984,8 +979,6 @@ static void MVTFree(Pool pool, Addr base, Size size) AVER(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); METER_ACC(mvt->exceptionReturns, SegSize(seg)); - if (SegBuffer(seg) != NULL) - BufferDetach(SegBuffer(seg), MVT2Pool(mvt)); MVTSegFree(mvt, seg); return; } @@ -1017,7 +1010,6 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) " availLimit: $U \n", (WriteFU)mvt->availLimit, " abqOverflow: $S \n", mvt->abqOverflow?"TRUE":"FALSE", " splinter: $S \n", mvt->splinter?"TRUE":"FALSE", - " splinterSeg: $P \n", (WriteFP)mvt->splinterSeg, " splinterBase: $A \n", (WriteFA)mvt->splinterBase, " splinterLimit: $A \n", (WriteFU)mvt->splinterLimit, " size: $U \n", (WriteFU)mvt->size, @@ -1036,68 +1028,37 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); if(res != ResOK) return res; - res = METER_WRITE(mvt->segAllocs, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->segFrees, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->bufferFills, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->bufferEmpties, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolFrees, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolSize, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolAllocated, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolAvailable, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolUnavailable, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolUtilization, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->finds, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->overflows, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->underflows, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->refills, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->refillPushes, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->returns, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->perfectFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->firstFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->secondFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->failures, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->emergencyContingencies, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->fragLimitContingencies, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->contingencySearches, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->contingencyHardSearches, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splinters, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splintersUsed, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splintersDropped, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->sawdust, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptions, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptionSplinters, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptionReturns, stream); - if (res != ResOK) return res; + METER_WRITE(mvt->segAllocs, stream); + METER_WRITE(mvt->segFrees, stream); + METER_WRITE(mvt->bufferFills, stream); + METER_WRITE(mvt->bufferEmpties, stream); + METER_WRITE(mvt->poolFrees, stream); + METER_WRITE(mvt->poolSize, stream); + METER_WRITE(mvt->poolAllocated, stream); + METER_WRITE(mvt->poolAvailable, stream); + METER_WRITE(mvt->poolUnavailable, stream); + METER_WRITE(mvt->poolUtilization, stream); + METER_WRITE(mvt->finds, stream); + METER_WRITE(mvt->overflows, stream); + METER_WRITE(mvt->underflows, stream); + METER_WRITE(mvt->refills, stream); + METER_WRITE(mvt->refillPushes, stream); + METER_WRITE(mvt->returns, stream); + METER_WRITE(mvt->perfectFits, stream); + METER_WRITE(mvt->firstFits, stream); + METER_WRITE(mvt->secondFits, stream); + METER_WRITE(mvt->failures, stream); + METER_WRITE(mvt->emergencyContingencies, stream); + METER_WRITE(mvt->fragLimitContingencies, stream); + METER_WRITE(mvt->contingencySearches, stream); + METER_WRITE(mvt->contingencyHardSearches, stream); + METER_WRITE(mvt->splinters, stream); + METER_WRITE(mvt->splintersUsed, stream); + METER_WRITE(mvt->splintersDropped, stream); + METER_WRITE(mvt->sawdust, stream); + METER_WRITE(mvt->exceptions, stream); + METER_WRITE(mvt->exceptionSplinters, stream); + METER_WRITE(mvt->exceptionReturns, stream); res = WriteF(stream, "}\n", NULL); return res; @@ -1175,7 +1136,7 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, { /* Can't use plain old SegClass here because we need to call * SegBuffer() in MVTFree(). */ - Res res = SegAlloc(segReturn, GCSegClassGet(), + Res res = SegAlloc(segReturn, SegClassGet(), SegPrefDefault(), size, MVT2Pool(mvt), withReservoirPermit, argsNone); @@ -1199,7 +1160,6 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, */ static void MVTSegFree(MVT mvt, Seg seg) { - Buffer buffer; Size size; size = SegSize(seg); @@ -1209,16 +1169,6 @@ static void MVTSegFree(MVT mvt, Seg seg) mvt->size -= size; mvt->availLimit = mvt->size * mvt->fragLimit / 100; AVER(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); - - /* If the client program allocates the exactly the entire buffer then - frees the allocated memory then we'll try to free the segment with - the buffer still attached. It's safe, but we must detach the buffer - first. See job003520 and job003672. */ - buffer = SegBuffer(seg); - if (buffer != NULL) { - AVER(BufferAP(buffer)->init == SegLimit(seg)); - BufferDetach(buffer, MVT2Pool(mvt)); - } SegFree(seg); METER_ACC(mvt->segFrees, size); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 6a530fb94bd..e50cf077f80 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -539,7 +539,7 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->sig = MVFFSig; AVERT(MVFF, mvff); EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align, - slotHigh, arenaHigh, firstFit); + BOOL(slotHigh), BOOL(arenaHigh), BOOL(firstFit)); return ResOK; failFailoverInit: diff --git a/mps/code/poolncv.c b/mps/code/poolncv.c index 6d77542db58..8b8dab2a8a1 100644 --- a/mps/code/poolncv.c +++ b/mps/code/poolncv.c @@ -10,6 +10,8 @@ #include "testlib.h" #include "mpslib.h" +#include /* printf */ + static void testit(ArenaClass class, ArgList args) { diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 6a36ae7db2b..5b5d150b8cc 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -36,27 +36,34 @@ SRCID(prmci3li, "$Id$"); MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + MRef gregs; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 7); + AVER(mfc->ucontext != NULL); + + /* TODO: The current arrangement of the fix operation (taking a Ref *) + forces us to pun these registers (actually `int` on LII3GC). We can + suppress the warning by casting through `void *` and this might make + it safe, but does it really? RB 2012-09-10 */ + AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs)); + gregs = (void *)mfc->ucontext->uc_mcontext.gregs; /* .source.i486 */ /* .assume.regref */ /* The register numbers (REG_EAX etc.) are defined in but only if _GNU_SOURCE is defined: see .feature.li in config.h. */ - /* TODO: The current arrangement of the fix operation (taking a Ref *) - forces us to pun these registers (actually `int` on LII3GC). We can - suppress the warning my casting through `char *` and this might make - it safe, but does it really? RB 2012-09-10 */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EAX]); - case 1: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ECX]); - case 2: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDX]); - case 3: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBX]); - case 4: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESP]); - case 5: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBP]); - case 6: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESI]); - case 7: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDI]); + case 0: return &gregs[REG_EAX]; + case 1: return &gregs[REG_ECX]; + case 2: return &gregs[REG_EDX]; + case 3: return &gregs[REG_EBX]; + case 4: return &gregs[REG_ESP]; + case 5: return &gregs[REG_EBP]; + case 6: return &gregs[REG_ESI]; + case 7: return &gregs[REG_EDI]; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index 786145fc084..eafeff61540 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -34,8 +34,13 @@ SRCID(prmci3li, "$Id$"); MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + THREAD_STATE_S *threadState; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 7); + AVER(mfc->threadState != NULL); + threadState = mfc->threadState; /* .source.i486 */ /* .assume.regref */ @@ -44,17 +49,17 @@ MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) config.h. */ /* TODO: The current arrangement of the fix operation (taking a Ref *) forces us to pun these registers (actually `int` on LII3GC). We can - suppress the warning my casting through `char *` and this might make + suppress the warning by casting through `void *` and this might make it safe, but does it really? RB 2012-09-10 */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->threadState->__eax); - case 1: return (MRef)((char *)&mfc->threadState->__ecx); - case 2: return (MRef)((char *)&mfc->threadState->__edx); - case 3: return (MRef)((char *)&mfc->threadState->__ebx); - case 4: return (MRef)((char *)&mfc->threadState->__esp); - case 5: return (MRef)((char *)&mfc->threadState->__ebp); - case 6: return (MRef)((char *)&mfc->threadState->__esi); - case 7: return (MRef)((char *)&mfc->threadState->__edi); + case 0: return (void *)&threadState->__eax; + case 1: return (void *)&threadState->__ecx; + case 2: return (void *)&threadState->__edx; + case 3: return (void *)&threadState->__ebx; + case 4: return (void *)&threadState->__esp; + case 5: return (void *)&threadState->__ebp; + case 6: return (void *)&threadState->__esi; + case 7: return (void *)&threadState->__edi; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index 2f8bf9afc62..c00c1359014 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -33,12 +33,19 @@ SRCID(prmci6li, "$Id$"); MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { - Word *gregs; + MRef gregs; + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 15); + AVER(mfc->ucontext != NULL); - gregs = (Word *)&mfc->ucontext->uc_mcontext.gregs; + /* TODO: The current arrangement of the fix operation (taking a Ref *) + forces us to pun these registers (actually `int` on LII6GC). We can + suppress the warning by casting through `void *` and this might make + it safe, but does it really? RB 2012-09-10 */ + AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs)); + gregs = (void *)mfc->ucontext->uc_mcontext.gregs; /* .assume.regref */ /* The register numbers (REG_RAX etc.) are defined in diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 02ccb840b6c..131447cd0cc 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -31,33 +31,38 @@ SRCID(prmci6li, "$Id$"); MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + THREAD_STATE_S *threadState; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 15); + AVER(mfc->threadState != NULL); + threadState = mfc->threadState; /* .assume.regref */ /* The register numbers (REG_RAX etc.) are defined in but only if _XOPEN_SOURCE is defined: see .feature.xc in config.h. */ /* MRef (a Word *) is not compatible with pointers to the register - types (actually a __uint64_t). To avoid aliasing optimization - problems, The registers are cast through (char *) */ + types (actually a __uint64_t). To avoid aliasing optimization + problems, the registers are cast through (void *). */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->threadState->__rax); - case 1: return (MRef)((char *)&mfc->threadState->__rcx); - case 2: return (MRef)((char *)&mfc->threadState->__rdx); - case 3: return (MRef)((char *)&mfc->threadState->__rbx); - case 4: return (MRef)((char *)&mfc->threadState->__rsp); - case 5: return (MRef)((char *)&mfc->threadState->__rbp); - case 6: return (MRef)((char *)&mfc->threadState->__rsi); - case 7: return (MRef)((char *)&mfc->threadState->__rdi); - case 8: return (MRef)((char *)&mfc->threadState->__r8); - case 9: return (MRef)((char *)&mfc->threadState->__r9); - case 10: return (MRef)((char *)&mfc->threadState->__r10); - case 11: return (MRef)((char *)&mfc->threadState->__r11); - case 12: return (MRef)((char *)&mfc->threadState->__r12); - case 13: return (MRef)((char *)&mfc->threadState->__r13); - case 14: return (MRef)((char *)&mfc->threadState->__r14); - case 15: return (MRef)((char *)&mfc->threadState->__r15); + case 0: return (void *)&threadState->__rax; + case 1: return (void *)&threadState->__rcx; + case 2: return (void *)&threadState->__rdx; + case 3: return (void *)&threadState->__rbx; + case 4: return (void *)&threadState->__rsp; + case 5: return (void *)&threadState->__rbp; + case 6: return (void *)&threadState->__rsi; + case 7: return (void *)&threadState->__rdi; + case 8: return (void *)&threadState->__r8; + case 9: return (void *)&threadState->__r9; + case 10: return (void *)&threadState->__r10; + case 11: return (void *)&threadState->__r11; + case 12: return (void *)&threadState->__r12; + case 13: return (void *)&threadState->__r13; + case 14: return (void *)&threadState->__r14; + case 15: return (void *)&threadState->__r15; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ diff --git a/mps/code/protxc.c b/mps/code/protxc.c index 8f62bb3a5df..1d2ae27917c 100644 --- a/mps/code/protxc.c +++ b/mps/code/protxc.c @@ -243,7 +243,7 @@ static void protCatchOne(void) different size" warnings in GCC, for the XCI3GC build. */ mfcStruct.address = (Addr)(Word)request.code[1]; AVER(sizeof(*mfcStruct.threadState) == sizeof(THREAD_STATE_S)); - mfcStruct.threadState = (THREAD_STATE_S *)request.old_state; + mfcStruct.threadState = (void *)request.old_state; if (ArenaAccess(mfcStruct.address, AccessREAD | AccessWRITE, @@ -282,6 +282,7 @@ static void protCatchOne(void) * handler won't cause a deadlock. */ +ATTRIBUTE_NORETURN static void *protCatchThread(void *p) { UNUSED(p); for (;;) diff --git a/mps/code/qs.c b/mps/code/qs.c index 31005b4fc9b..50fe8c48723 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -29,10 +29,9 @@ #include "mpscamc.h" #include "mpscmv.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* printf */ +#include /* qsort */ #define testArenaSIZE ((size_t)1000*1024) @@ -51,7 +50,7 @@ static mps_addr_t isMoved(mps_addr_t object); static void copy(mps_addr_t object, mps_addr_t to); static void pad(mps_addr_t base, size_t size); -struct mps_fmt_A_s fmt_A_s = +static struct mps_fmt_A_s fmt_A_s = { (mps_align_t)4, scan, skip, copy, @@ -318,14 +317,14 @@ static void validate(void) for(i = 0; i < listl; ++i) { cdie(((QSCell)reg[1])->tag == QSInt, "validate int"); if((mps_word_t)((QSCell)reg[1])->value != list[i]) { - (void)fprintf(stdout, "mps_res_t: Element %"PRIuLONGEST" of the " - "two lists do not match.\n", (ulongest_t)i); + printf("mps_res_t: Element %"PRIuLONGEST" of the " + "two lists do not match.\n", (ulongest_t)i); return; } reg[1] = (mps_addr_t)((QSCell)reg[1])->tail; } cdie(reg[1] == (mps_word_t)0, "validate end"); - (void)fprintf(stdout, "Note: Lists compare equal.\n"); + printf("Note: Lists compare equal.\n"); } diff --git a/mps/code/ring.c b/mps/code/ring.c index ff60149ce40..54902ec3818 100644 --- a/mps/code/ring.c +++ b/mps/code/ring.c @@ -1,7 +1,7 @@ /* ring.c: RING IMPLEMENTATION * * $Id$ - * Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of Rings. * @@ -52,6 +52,16 @@ Bool RingIsSingle(Ring ring) return (ring->next == ring); } +Size RingLength(Ring ring) +{ + Size size = 0; + Ring node, next; + AVERT(Ring, ring); + RING_FOR(node, ring, next) + ++ size; + return size; +} + /* RingInit -- initialize a ring node */ @@ -131,7 +141,7 @@ Ring (RingPrev)(Ring ring) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2003 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/ring.h b/mps/code/ring.h index d5b64076f6c..cbde6afe814 100644 --- a/mps/code/ring.h +++ b/mps/code/ring.h @@ -1,7 +1,7 @@ /* ring.h: RING INTERFACE * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. */ @@ -30,6 +30,7 @@ typedef struct RingStruct { /* double-ended queue structure */ extern Bool RingCheck(Ring ring); extern Bool RingCheckSingle(Ring ring); extern Bool RingIsSingle(Ring ring); +extern Size RingLength(Ring ring); /* .ring.init: */ extern void (RingInit)(Ring ring); @@ -115,7 +116,7 @@ extern Ring (RingPrev)(Ring ring); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/sac.c b/mps/code/sac.c index 435988cf867..3caf9ab893f 100644 --- a/mps/code/sac.c +++ b/mps/code/sac.c @@ -48,18 +48,20 @@ static Bool SACCheck(SAC sac) CHECKL(esac->_middle > 0); /* check classes above middle */ prevSize = esac->_middle; - for (j = sac->middleIndex + 1, i = 0; - j <= sac->classesCount; ++j, i += 2) { + for (j = sac->middleIndex + 1, i = 0; j < sac->classesCount; ++j, i += 2) { CHECKL(prevSize < esac->_freelists[i]._size); b = sacFreeListBlockCheck(&(esac->_freelists[i])); if (!b) return b; prevSize = esac->_freelists[i]._size; } /* check overlarge class */ - CHECKL(esac->_freelists[i-2]._size == SizeMAX); - CHECKL(esac->_freelists[i-2]._count == 0); - CHECKL(esac->_freelists[i-2]._count_max == 0); - CHECKL(esac->_freelists[i-2]._blocks == NULL); + CHECKL(prevSize < esac->_freelists[i]._size); + b = sacFreeListBlockCheck(&(esac->_freelists[i])); + if (!b) return b; + CHECKL(esac->_freelists[i]._size == SizeMAX); + CHECKL(esac->_freelists[i]._count == 0); + CHECKL(esac->_freelists[i]._count_max == 0); + CHECKL(esac->_freelists[i]._blocks == NULL); /* check classes below middle */ prevSize = esac->_middle; for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) { @@ -69,6 +71,7 @@ static Bool SACCheck(SAC sac) prevSize = esac->_freelists[i]._size; } /* check smallest class */ + CHECKL(prevSize > esac->_freelists[i]._size); CHECKL(esac->_freelists[i]._size == 0); b = sacFreeListBlockCheck(&(esac->_freelists[i])); return b; diff --git a/mps/code/seg.c b/mps/code/seg.c index 069b2c50049..31dd0759ff9 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -593,7 +593,7 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, if (ResOK != res) goto failMerge; - EVENT3(SegMerge, segLo, segHi, withReservoirPermit); + EVENT3(SegMerge, segLo, segHi, BOOL(withReservoirPermit)); /* Deallocate segHi object */ ControlFree(arena, segHi, class->size); AVERT(Seg, segLo); @@ -1200,7 +1200,7 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey) /* Internal method. Parameters are checked by caller */ gcseg = SegGCSeg(seg); arena = PoolArena(SegPool(seg)); - seg->grey = grey; + seg->grey = BS_BITFIELD(Trace, grey); /* If the segment is now grey and wasn't before, add it to the */ /* appropriate grey list so that TraceFindGrey can locate it */ @@ -1313,11 +1313,11 @@ static void gcSegSetWhite(Seg seg, TraceSet white) AVERT_CRITICAL(Tract, tract); AVER_CRITICAL(TRACT_SEG(&trseg, tract) && (trseg == seg)); - TractSetWhite(tract, white); + TractSetWhite(tract, BS_BITFIELD(Trace, white)); } AVER(addr == limit); - seg->white = white; + seg->white = BS_BITFIELD(Trace, white); } @@ -1350,7 +1350,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) arena = PoolArena(SegPool(seg)); oldRankSet = seg->rankSet; - seg->rankSet = rankSet; + seg->rankSet = BS_BITFIELD(Rank, rankSet); if (oldRankSet == RankSetEMPTY) { if (rankSet != RankSetEMPTY) { @@ -1427,7 +1427,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) wasShielded = (seg->rankSet != RankSetEMPTY && gcseg->summary != RefSetUNIV); willbeShielded = (rankSet != RankSetEMPTY && summary != RefSetUNIV); - seg->rankSet = rankSet; + seg->rankSet = BS_BITFIELD(Rank, rankSet); gcseg->summary = summary; if (willbeShielded && !wasShielded) { diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 21a8b8846ed..978c352e0dd 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -21,14 +21,9 @@ #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include -#include -#include + +#include /* fflush, printf, puts, stdout */ /* Forward declarations */ @@ -791,7 +786,7 @@ static void *test(void *arg, size_t s) &ambigRoots[0], ambigRootsCOUNT), "root_create_table(ambig)"); - (void)fputs(indent, stdout); + puts(indent); /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); diff --git a/mps/code/steptest.c b/mps/code/steptest.c index 4d6353e78df..deee85fef2e 100644 --- a/mps/code/steptest.c +++ b/mps/code/steptest.c @@ -14,12 +14,9 @@ #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include + +#include /* fflush, printf, putchar, stdout */ #define testArenaSIZE ((size_t)((size_t)64 << 20)) #define avLEN 3 @@ -74,19 +71,19 @@ static mps_addr_t ambigRoots[ambigRootsCOUNT]; /* Things we want to measure. Times are all in microseconds. */ -double alloc_time; /* Time spent allocating */ -double max_alloc_time; /* Max time taken to allocate one object */ -double step_time; /* Time spent in mps_arena_step returning 1 */ -double max_step_time; /* Max time of mps_arena_step returning 1 */ -double no_step_time; /* Time spent in mps_arena_step returning 0 */ -double max_no_step_time; /* Max time of mps_arena_step returning 0 */ +static double alloc_time; /* Time spent allocating */ +static double max_alloc_time; /* Max time taken to allocate one object */ +static double step_time; /* Time spent in mps_arena_step returning 1 */ +static double max_step_time; /* Max time of mps_arena_step returning 1 */ +static double no_step_time; /* Time spent in mps_arena_step returning 0 */ +static double max_no_step_time; /* Max time of mps_arena_step returning 0 */ -double total_clock_time; /* Time spent reading the clock */ -long clock_reads; /* Number of times clock is read */ -long steps; /* # of mps_arena_step calls returning 1 */ -long no_steps; /* # of mps_arena_step calls returning 0 */ -size_t alloc_bytes; /* # of bytes allocated */ -long commit_failures; /* # of times mps_commit fails */ +static double total_clock_time; /* Time spent reading the clock */ +static long clock_reads; /* Number of times clock is read */ +static long steps; /* # of mps_arena_step calls returning 1 */ +static long no_steps; /* # of mps_arena_step calls returning 0 */ +static size_t alloc_bytes; /* # of bytes allocated */ +static long commit_failures; /* # of times mps_commit fails */ /* Operating-system dependent timing. Defines two functions, void @@ -98,6 +95,8 @@ long commit_failures; /* # of times mps_commit fails */ #ifdef MPS_OS_W3 +#include "mpswin.h" + static HANDLE currentProcess; static void prepare_clock(void) @@ -152,7 +151,7 @@ static double my_clock(void) * on thrush.ravenbrook.com on 2002-06-28, clock_time goes from 5.43 * us near process start to 7.45 us later). */ -double clock_time; /* current estimate of time to read the clock */ +static double clock_time; /* current estimate of time to read the clock */ /* take at least this many microseconds to set the clock */ #define CLOCK_TIME_SET 10000 diff --git a/mps/code/teletest.c b/mps/code/teletest.c index 844fbc51329..1a6b1614553 100644 --- a/mps/code/teletest.c +++ b/mps/code/teletest.c @@ -12,7 +12,8 @@ #include "testlib.h" #include "mpslib.h" -#include +#include /* fflush, fgets, printf, stdin, stdout */ +#include /* exit, EXIT_SUCCESS, strtoul */ SRCID(teletest, "$Id$"); @@ -34,8 +35,8 @@ static void callControl(mps_word_t reset, mps_word_t flip) old = mps_telemetry_control(reset, flip); new = mps_telemetry_control((mps_word_t)0, (mps_word_t)0); - (void)printf(WORD_FORMAT " -> " WORD_FORMAT "\n", - (ulongest_t)old, (ulongest_t)new); + printf(WORD_FORMAT " -> " WORD_FORMAT "\n", + (ulongest_t)old, (ulongest_t)new); } diff --git a/mps/code/testlib.c b/mps/code/testlib.c index 18fe005ae5b..6ecedad0bd6 100644 --- a/mps/code/testlib.c +++ b/mps/code/testlib.c @@ -11,13 +11,11 @@ #include "clock.h" /* for EVENT_CLOCK */ #include "mps.h" #include "misc.h" /* for NOOP */ -#include -#include -#include -#ifdef MPS_OS_IA -struct itimerspec; /* stop complaints from time.h */ -#endif -#include + +#include /* fmod */ +#include /* fflush, printf, stderr, sscanf, vfprintf */ +#include /* abort, exit, getenv */ +#include /* time */ /* fail -- like assert, but (notionally) returns a value, so usable in an expression */ diff --git a/mps/code/testlib.h b/mps/code/testlib.h index 447834254f4..9c197cae839 100644 --- a/mps/code/testlib.h +++ b/mps/code/testlib.h @@ -12,14 +12,7 @@ #include "mps.h" #include "misc.h" /* for STR */ - -/* Include system header hackery. */ #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpswin.h" -#endif - -#include /* Suppress Visual C warnings at warning level 4, */ @@ -35,13 +28,10 @@ /* Suppress Pelles C warnings at warning level 2 */ -/* Some of these are also done in config.h. */ +/* This is also done in config.h. */ #ifdef MPS_BUILD_PC -/* "Structured Exception Handling is not portable." (mps_tramp). */ -#pragma warn(disable: 2008) - /* "Unreachable code" (AVER, if condition is constantly true). */ #pragma warn(disable: 2154) @@ -65,6 +55,19 @@ #endif +/* alloca -- memory allocator + * + * Windows calls this function _alloca() instead of alloca(). + * + */ + +#if defined(MPS_OS_W3) + +#define alloca _alloca + +#endif + + /* ulongest_t -- longest unsigned integer type * * Define a longest unsigned integer type for testing, scanning, and diff --git a/mps/code/testthr.h b/mps/code/testthr.h new file mode 100644 index 00000000000..341f4f407b5 --- /dev/null +++ b/mps/code/testthr.h @@ -0,0 +1,123 @@ +/* testthr.h: MULTI-THREADED TEST INTERFACE + * + * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * .purpose: Simple interface to threads that makes it possible to + * write test cases that are portable between Windows (using the + * implementation in testthrw3.c) and Unix (using the implementation + * in testthrix.c). + */ + +#ifndef testthr_h +#define testthr_h + +#include "mpstd.h" + + +/* testthr_routine_t -- type of thread routines + * + * Use the pthread type here and convert back and forth in the Windows + * implementation. + */ +typedef void *(*testthr_routine_t)(void *); + + +/* testthr_t -- type of thread identifiers + * + * It is necessary to define it here (even though it requires some + * #ifdefs) so that clients can allocate storage for them. + */ + +#if defined(MPS_OS_W3) + +#include "mpswin.h" + +/* On Windows, a thread is identified by a HANDLE. + * + * But use a structure so that the thread has somewhere to store its + * result for use by testthr_join. + */ +typedef struct testthr_t { + HANDLE handle; + testthr_routine_t start; + void *arg; /* argument to pass to start */ + void *result; /* result returned from start */ +} testthr_t; + +#elif defined(MPS_OS_FR) || defined(MPS_OS_LI) || defined(MPS_OS_XC) + +#include + +/* In pthreads, a thread is identified by a pthread_t, which is + * allowed "to be defined as a structure" [IEEE Std 1003.1, sys/types.h] + * + */ +typedef pthread_t testthr_t; + +#else +#error "Unknown platform: can't determine a type for testthr_t." +#endif + + +/* testthr_create -- create a thread + * + * Store the identifier of the newly created thread in *thread_o, and + * call start, passing arg as the single parameter. + */ + +void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg); + + +/* testthr_join -- wait for a thread to complete + * + * Suspend execution of the calling thread until the target thread + * terminates (if necessary), and if result_o is non-NULL, update + * *result_o with the return value of the thread's start. + */ + +void testthr_join(testthr_t *thread, void **result_o); + +#endif /* testthr_h */ + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 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/mpsw3.h b/mps/code/testthrix.c similarity index 69% rename from mps/code/mpsw3.h rename to mps/code/testthrix.c index f32b7a09831..f4c544e0b8a 100644 --- a/mps/code/mpsw3.h +++ b/mps/code/testthrix.c @@ -1,45 +1,32 @@ -/* mpsw3.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE, WINDOWS PART +/* testthrix.c: MULTI-THREADED TEST IMPLEMENTATION (POSIX THREADS) * - * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. - * - * .readership: customers, MPS developers. - * .sources: . + * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. */ -#ifndef mpsw3_h -#define mpsw3_h +#include "testlib.h" +#include "testthr.h" -#include "mps.h" /* needed for mps_tramp_t */ -#include "mpswin.h" /* needed for SEH filter */ +#include /* strerror */ +void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg) +{ + int res = pthread_create(thread_o, NULL, start, arg); + if (res != 0) + error("pthread_create failed with result %d (%s)", res, strerror(res)); +} -extern LONG mps_SEH_filter(LPEXCEPTION_POINTERS, void **, size_t *); -extern void mps_SEH_handler(void *, size_t); - - -#define mps_tramp(r_o, f, p, s) \ - MPS_BEGIN \ - void **_r_o = (r_o); \ - mps_tramp_t _f = (f); \ - void *_p = (p); \ - size_t _s = (s); \ - void *_hp = NULL; size_t _hs = 0; \ - __try { \ - *_r_o = (*_f)(_p, _s); \ - } __except(mps_SEH_filter(GetExceptionInformation(), \ - &_hp, &_hs)) { \ - mps_SEH_handler(_hp, _hs); \ - } \ - MPS_END - - -#endif /* mpsw3_h */ +void testthr_join(testthr_t *thread, void **result_o) +{ + int res = pthread_join(*thread, result_o); + if (res != 0) + error("pthread_join failed with result %d (%s)", res, strerror(res)); +} /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/testthrw3.c b/mps/code/testthrw3.c new file mode 100644 index 00000000000..cd5cf54ae79 --- /dev/null +++ b/mps/code/testthrw3.c @@ -0,0 +1,80 @@ +/* testthrw3.c: MULTI-THREADED TEST IMPLEMENTATION (WINDOWS) + * + * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + */ + +#include "testlib.h" +#include "testthr.h" + +static DWORD WINAPI testthr_start(LPVOID arg) +{ + testthr_t *thread = arg; + thread->result = (*thread->start)(thread->arg); + return 0; +} + +void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg) +{ + HANDLE res; + thread_o->start = start; + thread_o->arg = arg; + res = CreateThread(NULL, 0, testthr_start, thread_o, 0, NULL); + if (res == NULL) + error("CreateThread failed with error %lu", + (unsigned long)GetLastError()); + else + thread_o->handle = res; +} + +void testthr_join(testthr_t *thread, void **result_o) +{ + DWORD res = WaitForSingleObject(thread->handle, INFINITE); + if (res != WAIT_OBJECT_0) + error("WaitForSingleObject failed with result %lu (error %lu)", + (unsigned long)res, (unsigned long)GetLastError()); + if (result_o) + *result_o = thread->result; +} + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 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/trace.c b/mps/code/trace.c index 924badcd541..61e9d396155 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -797,10 +797,11 @@ void TraceDestroy(Trace trace) (TraceStatReclaim, trace, trace->reclaimCount, trace->reclaimSize)); + EVENT1(TraceDestroy, trace); + trace->sig = SigInvalid; trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace); trace->arena->flippedTraces = TraceSetDel(trace->arena->flippedTraces, trace); - EVENT1(TraceDestroy, trace); } @@ -1569,7 +1570,7 @@ static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i) Ring n, nn; RING_FOR(n, &desc->locusRing, nn) { PoolGen gen = RING_ELT(PoolGen, genRing, n); - EVENT11(TraceStartPoolGen, chain, top, i, desc, + EVENT11(TraceStartPoolGen, chain, BOOL(top), i, desc, desc->capacity, desc->mortality, desc->zones, gen->pool, gen->nr, gen->totalSize, gen->newSizeAtCreate); diff --git a/mps/code/version.c b/mps/code/version.c index 9f8d644e47a..4771c8a7c69 100644 --- a/mps/code/version.c +++ b/mps/code/version.c @@ -47,6 +47,7 @@ SRCID(version, "$Id$"); * (assuming we've made any substantial changes to the library this year). */ +extern char MPSCopyrightNotice[]; char MPSCopyrightNotice[] = "Portions copyright (c) 2010-2014 Ravenbrook Limited and Global Graphics Software."; @@ -59,6 +60,7 @@ char MPSCopyrightNotice[] = * see also guide.mps.version. */ +extern char MPSVersionString[]; char MPSVersionString[] = "@(#)Ravenbrook MPS, " "product." MPS_PROD_STRING ", " MPS_RELEASE ", platform." MPS_PF_STRING diff --git a/mps/code/vman.c b/mps/code/vman.c index db7795c9f2e..6ba3d0b9dff 100644 --- a/mps/code/vman.c +++ b/mps/code/vman.c @@ -1,7 +1,7 @@ /* vman.c: ANSI VM: MALLOC-BASED PSEUDO MEMORY MAPPING * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -117,13 +117,13 @@ void VMDestroy(VM vm) AVER(vm->mapped == (Size)0); AVER(vm->reserved == AddrOffset(vm->base, vm->limit)); + EVENT1(VMDestroy, vm); + memset((void *)vm->base, VMJunkBYTE, AddrOffset(vm->base, vm->limit)); free(vm->block); vm->sig = SigInvalid; - free(vm); - - EVENT1(VMDestroy, vm); + free(vm); } @@ -215,7 +215,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/vmix.c b/mps/code/vmix.c index 01a0919b820..0903a031a2c 100644 --- a/mps/code/vmix.c +++ b/mps/code/vmix.c @@ -1,7 +1,7 @@ /* vmix.c: VIRTUAL MEMORY MAPPING FOR UNIX (ISH) * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the virtual memory mapping * interface (vm.h) for Unix-like operating systems. It was created @@ -186,6 +186,8 @@ void VMDestroy(VM vm) AVERT(VM, vm); AVER(vm->mapped == (Size)0); + EVENT1(VMDestroy, vm); + /* This appears to be pretty pointless, since the descriptor */ /* page is about to vanish completely. However, munmap might fail */ /* for some reason, and this would ensure that it was still */ @@ -197,8 +199,6 @@ void VMDestroy(VM vm) r = munmap((void *)vm, (size_t)SizeAlignUp(sizeof(VMStruct), vm->align)); AVER(r == 0); - - EVENT1(VMDestroy, vm); } @@ -304,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/vmw3.c b/mps/code/vmw3.c index e82f14ccd51..5be8153c73c 100644 --- a/mps/code/vmw3.c +++ b/mps/code/vmw3.c @@ -1,7 +1,7 @@ /* vmw3.c: VIRTUAL MEMORY MAPPING FOR WIN32 * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .design: See . * @@ -191,6 +191,8 @@ void VMDestroy(VM vm) AVERT(VM, vm); AVER(vm->mapped == 0); + EVENT1(VMDestroy, vm); + /* This appears to be pretty pointless, since the vm descriptor page * is about to vanish completely. However, the VirtualFree might * fail and it would be nice to have a dead sig there. */ @@ -201,7 +203,6 @@ void VMDestroy(VM vm) b = VirtualFree((LPVOID)vm, (SIZE_T)0, MEM_RELEASE); AVER(b != 0); - EVENT1(VMDestroy, vm); } @@ -303,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/walk.c b/mps/code/walk.c index 3f7f67f99e1..4dd0d6b9e98 100644 --- a/mps/code/walk.c +++ b/mps/code/walk.c @@ -273,6 +273,20 @@ static Res rootWalk(Root root, void *p) } +/* rootWalkGrey -- make the root grey for the trace passed as p */ + +static Res rootWalkGrey(Root root, void *p) +{ + Trace trace = p; + + AVERT(Root, root); + AVERT(Trace, trace); + + RootGrey(root, trace); + return ResOK; +} + + /* ArenaRootsWalk -- walks all the root in the arena */ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, @@ -315,7 +329,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, } /* Make the roots grey so that they are scanned */ - res = RootsIterate(arenaGlobals, (RootIterateFn)RootGrey, (void *)trace); + res = RootsIterate(arenaGlobals, rootWalkGrey, trace); /* Make this trace look like any other trace. */ arena->flippedTraces = TraceSetAdd(arena->flippedTraces, trace); @@ -330,6 +344,16 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, break; } + /* Turn segments black again. */ + if (SegFirst(&seg, arena)) { + do { + if (PoolHasAttr(SegPool(seg), AttrGC)) { + SegSetGrey(seg, TraceSetDel(SegGrey(seg), trace)); + SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); + } + } while (SegNext(&seg, arena, seg)); + } + rootsStepClosureFinish(rsc); /* Make this trace look like any other finished trace. */ trace->state = TraceFINISHED; diff --git a/mps/code/walkt0.c b/mps/code/walkt0.c index 629a5276ead..929408fc4b4 100644 --- a/mps/code/walkt0.c +++ b/mps/code/walkt0.c @@ -13,15 +13,12 @@ #include "mpscamc.h" #include "mpscams.h" #include "mpscawl.h" +#include "mpsclo.h" #include "mpsavm.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif #include "mps.h" -#include -#include +#include /* printf */ #define testArenaSIZE ((size_t)((size_t)64 << 20)) #define avLEN 3 @@ -216,8 +213,10 @@ int main(int argc, char *argv[]) die(mps_thread_reg(&thread, arena), "thread_reg"); test(arena, mps_class_amc()); - test(arena, mps_class_awl()); + test(arena, mps_class_amcz()); /* TODO: test(arena, mps_class_ams()); -- see job003738 */ + test(arena, mps_class_awl()); + test(arena, mps_class_lo()); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 20cb8f06dc1..06ef499f5b7 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -62,11 +62,8 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include -#include /* clock */ + +#include /* fflush, printf, putchar, puts, stdout */ /* testChain -- generation parameters for the test */ diff --git a/mps/code/zmess.c b/mps/code/zmess.c index a97c10ea8f1..555e7377d2c 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -107,10 +107,8 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "mpstd.h" -#ifdef MPS_OS_W3 -#include "mpsw3.h" -#endif -#include + +#include /* printf */ #define testArenaSIZE ((size_t)16<<20) diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt index d54a58cf03c..dd3608d8990 100644 --- a/mps/design/nailboard.txt +++ b/mps/design/nailboard.txt @@ -187,8 +187,8 @@ Performance might be improved by special-casing the small levels. _`.future.limit`: In C and C++, a pointer to "one past the last element of an array object" (the limit of the object in our terminology) is a valid pointer and can be used in pointer arithmetic. -See §6.5.6.8–9 of [C1999]. So in theory a programmer could have such -as pointer as the only reference keeping an object alive, and still +See §6.5.6.8–9 of [C1999]_. So in theory a programmer could have such +a pointer as the only reference keeping an object alive, and still expect to be able to subtract from it to get back to the object. The current nailboard implementation does not support this use case. diff --git a/mps/manual/source/design/.p4ignore b/mps/manual/source/design/.p4ignore index 0e9be69cee0..2457ad19192 100644 --- a/mps/manual/source/design/.p4ignore +++ b/mps/manual/source/design/.p4ignore @@ -1,5 +1,6 @@ # The files in this directory are generated by the "mps" extension to Sphinx, # except the index and the "old designs" index. *.rst +*.svg !index.rst !old.rst diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index e73dbe4b934..57959f1ea0c 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -18,11 +18,14 @@ from sphinx.util.console import bold TYPES = ''' - AccessSet Accumulation Addr Align AP Arg Arena Attr Bool BT Buffer - Byte Clock Compare Count Epoch Format Fun Index LD Lock Message - Pointer Pool PThreadext Rank RankSet Ref Res Reservoir Ring Root - RootVar ScanState Seg Serial Shift Sig Size Space SplayNode - SplayTree Thread Trace TraceId TraceSet ULongest VM Word + AccessSet Accumulation Addr Align AllocFrame AllocPattern AP Arg + Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk + Clock Compare Count Epoch FindDelete Format FrameState Fun Globals + Index Land LD Lock Message MessageType MutatorFaultContext Page + Pointer Pool PThreadext Range Rank RankSet Ref Res Reservoir Ring + Root RootMode RootVar ScanState Seg SegBuf SegPref SegPrefKind + Serial Shift Sig Size Space SplayNode SplayTree StackContext + Thread Trace TraceId TraceSet ULongest VM Word ZoneSet ''' diff --git a/mps/manual/source/glossary/k.rst b/mps/manual/source/glossary/k.rst index 4033cce5fd5..d84d07711e1 100644 --- a/mps/manual/source/glossary/k.rst +++ b/mps/manual/source/glossary/k.rst @@ -14,7 +14,7 @@ Memory Management Glossary: K keyword argument - A argument to a function call that's identified by an + An argument to a function call that's identified by an associated keyword rather than by its position in the argument list. @@ -35,5 +35,3 @@ Memory Management Glossary: K The standard abbreviation is "kB", but "KB" is often used by people unfamiliar with the metric system. - - diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst index 4128339227a..79df0258804 100644 --- a/mps/manual/source/pool/awl.rst +++ b/mps/manual/source/pool/awl.rst @@ -282,11 +282,10 @@ the format of objects allocated in it: that it does not look like an aligned pointer. "Aligned pointer" means a word whose numeric value (that is, its - value when treated as an unsigned integer) is a multiple of the - architecture's :term:`natural alignment` (see - :c:macro:`MPS_PF_ALIGN`). If you're using a 32-bit architecture, - that means that an aligned pointer is a multiple of 4 and its bottom - two bits are both zero. + value when treated as an unsigned integer) is a multiple of the size + of a pointer. For you're using a 32-bit architecture, that means + that an aligned pointer is a multiple of 4 and its bottom two bits + are both zero. The bottom line is that references from an object in an AWL pool must be untagged and aligned, and integers must be tagged with a diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 433525f7362..361cd41c0b5 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -75,17 +75,19 @@ MV interface When creating an MV pool, :c:func:`mps_pool_create_k` may take three :term:`keyword arguments`: - * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the - :term:`size` of segment that the pool will request from the - :term:`arena`. + * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, + default 65536) is the :term:`size` of segment that the pool will + request from the :term:`arena`. - * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) is the - predicted mean size of blocks that will be allocated from the - pool. + * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) + is the predicted mean size of blocks that will be allocated from + the pool. This value must be smaller than, or equal to, the + value for :c:macro:`MPS_KEY_EXTEND_BY`. - * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`, default 65536) is the - predicted maximum size of blocks that will be allocated from the - pool. + * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`, + default 65536) is the predicted maximum size of blocks that will + be allocated from the pool. This value must be larger than, or + equal to, the value for :c:macro:`MPS_KEY_EXTEND_BY`. The mean and maximum sizes are *hints* to the MPS: the pool will be less efficient if these are wrong, but nothing will break. diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 294b6545b91..18cc8ed72e9 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -27,6 +27,45 @@ New features calling :c:func:`mps_pool_create_k`. +Interface changes +................. + +#. There is now a default value (currently 1 \ :term:`megabyte`) for + the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to + :c:func:`mps_arena_create_k` when creating a virtual memory arena. + See :c:func:`mps_arena_class_vm`. + + +Other changes +............. + +#. The :ref:`pool-ams` pool class no longer triggers the assertion + ``!AMS_IS_INVALID_COLOUR(seg, i)`` under rare circumstances + (namely, detaching an :term:`allocation point` from a :term:`grey` + segment when :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` is + ``FALSE``). See job001549_. + + .. _job001549: https://www.ravenbrook.com/project/mps/issue/job001549/ + +#. :c:func:`mps_arena_roots_walk` no longer triggers an assertion + failure when run twice in succession. See job003496_. + + .. _job003496: https://www.ravenbrook.com/project/mps/issue/job003496/ + +#. The alignment of :ref:`pool-awl` pools is now configurable via the + object format, as documented, and is no longer always + :c:macro:`MPS_PF_ALIGN`. See job003745_. + + .. _job003745: https://www.ravenbrook.com/project/mps/issue/job003745/ + +#. :program:`mpseventtxt` now successfully processes a telemetry log + containing multiple labels associated with the same address. See + job003756_. + + .. _job003756: https://www.ravenbrook.com/project/mps/issue/job003756/ + + + .. _release-notes-1.113: Release 1.113.0 diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 5220ece4007..1925117cc84 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -233,18 +233,18 @@ Virtual memory arenas more efficient. When creating a virtual memory arena, :c:func:`mps_arena_create_k` - requires one :term:`keyword argument`: + accepts one :term:`keyword argument` on all platforms: - * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`). is the - initial amount of virtual address space, in :term:`bytes (1)`, - that the arena will reserve (this space is initially reserved so - that the arena can subsequently use it without interference from - other parts of the program, but most of it is not committed, so - it doesn't require any RAM or backing store). The arena may - allocate more virtual address space beyond this initial - reservation as and when it deems it necessary. The MPS is most - efficient if you reserve an address space that is several times - larger than your peak memory usage. + * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default + 2\ :superscript:`20`) is the initial amount of virtual address + space, in :term:`bytes (1)`, that the arena will reserve (this + space is initially reserved so that the arena can subsequently + use it without interference from other parts of the program, but + most of it is not committed, so it doesn't require any RAM or + backing store). The arena may allocate more virtual address + space beyond this initial reservation as and when it deems it + necessary. The MPS is most efficient if you reserve an address + space that is several times larger than your peak memory usage. .. note:: @@ -252,8 +252,8 @@ Virtual memory arenas more times it has to extend its address space, the less efficient garbage collection will become. - An optional :term:`keyword argument` may be passed, but is - only used on the Windows operating system: + A second optional :term:`keyword argument` may be passed, but it + only has any effect on the Windows operating system: * :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`). If true, the arena will allocate address space starting at the @@ -273,8 +273,9 @@ Virtual memory arenas If the MPS fails to allocate memory for the internal arena structures, :c:func:`mps_arena_create_k` returns - :c:macro:`MPS_RES_MEMORY`. Either ``size`` was far too small or - the operating system refused to provide enough memory. + :c:macro:`MPS_RES_MEMORY`. Either :c:macro:`MPS_KEY_ARENA_SIZE` + was far too small or the operating system refused to provide + enough memory. For example:: diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 97ec2f73216..6b2e9452fc2 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -232,7 +232,7 @@ assertion that is listed here but for which you discovered a different cause), please :ref:`let us know ` so that we can improve this documentation. -``arenavm.c: BTIsResRange(vmChunk->pageTableMapped, 0, chunk->pageTablePages)`` +``sa.c: BTIsResRange(sa->mapped, 0, sa->length)`` The client program called :c:func:`mps_arena_destroy` without having destroyed all pools in that arena first. (The assertion is @@ -283,14 +283,6 @@ this documentation. point` instead. -``poolams.c: !AMS_IS_INVALID_COLOUR(seg, i)`` - - The client program failed to :term:`fix` a reference to an object - in an :ref:`pool-ams` pool, violating the :term:`tri-colour - invariant` that the MPS depends on for the correctness of its - :term:`incremental garbage collection`. - - ``poolams.c: AMS_ALLOCED(seg, i)`` The client program tried to :term:`fix` a :term:`reference` to a diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 91ac7ae6462..b9bbdae61bb 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -468,22 +468,27 @@ Object format introspection Each :term:`pool class` determines for which objects the stepper function is called. Typically, all validly formatted objects are - visited. During a :term:`trace` this will in general be only the - :term:`black` objects, though the :ref:`pool-lo` pool, for - example, will walk all objects since they are validly formatted - whether they are black or :term:`white`. :term:`Padding objects` - may be visited at the pool class's discretion: the :term:`client - program` should handle this case. - - .. seealso:: - - :ref:`topic-arena`. + visited. :term:`Padding objects` may be visited at the pool + class's discretion: the stepper function must handle this + case. .. note:: This function is intended for heap analysis, tuning, and debugging, not for frequent use in production. + .. warning:: + + If a garbage collection is currently in progress (that is, if + the arena is in the :term:`clamped ` or + :term:`unclamped state`), then only objects that are known to + be currently valid are visited. + + For the most reliable results, ensure the arena is in the + :term:`parked state` by calling :c:func:`mps_arena_park` + before calling this function (and release it by calling + :c:func:`mps_arena_release` afterwards, if desired). + .. c:type:: void (*mps_formatted_objects_stepper_t)(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, void *p, size_t s) @@ -515,10 +520,6 @@ Object format introspection It must not access other memory managed by the MPS. - .. seealso:: - - :ref:`topic-arena`. - Obsolete interface ------------------ diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 665daa91e64..3b3fbcb01ad 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -36,9 +36,8 @@ help with forming keyword argument lists:: } MPS_ARGS_END(args); The argument array must not be ``NULL``, and must end with -:c:macro:`MPS_KEY_ARGS_END`. If you don't want to pass any arguments, you can -either call the equivalent function that does not take keyword arguments -(named without the ``_k``) or pass :c:macro:`mps_args_none`. +:c:macro:`MPS_KEY_ARGS_END`. If you don't want to pass any arguments, +you can pass :c:macro:`mps_args_none`. When a function that takes keyword arguments returns, the keyword argument array has been *modified* to remove any arguments that have diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index f33de3516ce..a665aaf4b07 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -110,7 +110,7 @@ The MPS writes the telemetry to the log in an encoded form for speed. It can be decoded using the :ref:`mpseventcnv ` and :ref:`mpseventtxt ` programs:: - (gdb) shell mpseventcnv | mpseventtxt | sort > mpsio.txt + (gdb) shell mpseventcnv | sort | mpseventtxt > mpsio.txt The ``sort`` is useful because the events are not necessarily written to the telemetry file in time order, but each event starts with a diff --git a/mps/test/function/122.c b/mps/test/function/122.c index 6f1465289cb..4ba0c0c6090 100644 --- a/mps/test/function/122.c +++ b/mps/test/function/122.c @@ -133,7 +133,7 @@ static void test(void) die(allocrdumb(&a[0], aplo, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&a[1], apamc, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&a[3], apawl, 64, mps_rank_exact()), "alloc"); - a[2] = (mycell *)((int)a[3] | 4); + a[2] = (mycell *)((mps_word_t)a[3] | 4); die(allocrdumb(&b[0], aplo, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&b[1], apamc, 64, mps_rank_exact()), "alloc"); diff --git a/mps/test/function/40.c b/mps/test/function/40.c index c57f8c62ba5..5257e1fcfc1 100644 --- a/mps/test/function/40.c +++ b/mps/test/function/40.c @@ -66,7 +66,7 @@ static void test(void) comment("%i of 10.", i); UC; z[i] = allocone(ap, 1, 1); - if (i % 8 == 0) { z[i] = (mycell *) ((int)z[i] + 4); } /* error to scan this! */ + if (i % 8 == 0) { z[i] = (mycell *) ((mps_word_t)z[i] + 4); } /* error to scan this! */ } for (i=0; i<1000; i++) { diff --git a/mps/test/function/51.c b/mps/test/function/51.c index 7be804d666a..779445218ae 100644 --- a/mps/test/function/51.c +++ b/mps/test/function/51.c @@ -14,6 +14,7 @@ END_HEADER #include "testlib.h" #include "mpscawl.h" #include "mpscamc.h" +#include "mpscams.h" #include "mpsclo.h" #include "mpsavm.h" #include "rankfmt.h" @@ -94,15 +95,15 @@ static void finalpoll(mycell **ref, int faction) static void test(void) { - mps_pool_t poolamc, poolawl, poollo; + mps_pool_t poolamc, poolamcz, poolams, poolawl, poollo; mps_thr_t thread; mps_root_t root0, root1; mps_fmt_t format; mps_chain_t chain; - mps_ap_t apamc, apawl, aplo; + mps_ap_t apamc, apamcz, apams, apawl, aplo; - mycell *a, *b, *c, *d, *z; + mycell *a, *b, *c, *d, *e, *z; long int i,j; @@ -126,20 +127,39 @@ static void test(void) die(mmqa_pool_create_chain(&poolamc, arena, mps_class_amc(), format, chain), "create pool"); - cdie(mps_pool_create(&poolawl, arena, mps_class_awl(), format, getassociated), - "create pool"); + die(mmqa_pool_create_chain(&poolamcz, arena, mps_class_amcz(), format, chain), + "create pool"); - cdie(mps_pool_create(&poollo, arena, mps_class_lo(), format), - "create pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); + cdie(mps_pool_create_k(&poolams, arena, mps_class_ams(), args), + "create pool"); + } MPS_ARGS_END(args); - cdie(mps_ap_create(&apawl, poolawl, mps_rank_weak()), - "create ap"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); + MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, getassociated); + cdie(mps_pool_create_k(&poolawl, arena, mps_class_awl(), args), + "create pool"); + } MPS_ARGS_END(args); - cdie(mps_ap_create(&apamc, poolamc, mps_rank_exact()), - "create ap"); - - cdie(mps_ap_create(&aplo, poollo, mps_rank_exact()), - "create ap"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); + cdie(mps_pool_create_k(&poollo, arena, mps_class_lo(), args), + "create pool"); + } MPS_ARGS_END(args); + + cdie(mps_ap_create(&apawl, poolawl, mps_rank_weak()), "create ap"); + cdie(mps_ap_create(&apamc, poolamc, mps_rank_exact()), "create ap"); + cdie(mps_ap_create(&apamcz, poolamcz, mps_rank_exact()), "create ap"); + cdie(mps_ap_create(&apams, poolams, mps_rank_exact()), "create ap"); + cdie(mps_ap_create(&aplo, poollo, mps_rank_exact()), "create ap"); mps_message_type_enable(arena, mps_message_type_finalization()); @@ -150,13 +170,17 @@ static void test(void) for (j=0; j<1000; j++) { a = allocone(apamc, 2, mps_rank_exact()); - c = allocone(apawl, 2, mps_rank_weak()); - d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */ + b = allocone(apamcz, 2, mps_rank_exact()); /* rank irrelevant here! */ + c = allocone(apams, 2, mps_rank_exact()); + d = allocone(apawl, 2, mps_rank_weak()); + e = 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); - final_count += 4; + mps_finalize(arena, (mps_addr_t*)&e); + mps_finalize(arena, (mps_addr_t*)&e); + final_count += 6; } /* throw them all away and collect everything */ @@ -176,10 +200,12 @@ static void test(void) while (final_count != 0 && i < 10) { finalpoll(&z, FINAL_DISCARD); - if (mps_message_poll(arena) == 0) { + if (final_count != 0 && mps_message_poll(arena) == 0) { i++; - a = allocdumb(apawl, 1024, mps_rank_weak()); a = allocdumb(apamc, 1024, mps_rank_exact()); + a = allocdumb(apamcz, 1024, mps_rank_exact()); + a = allocdumb(apams, 1024, mps_rank_exact()); + a = allocdumb(apawl, 1024, mps_rank_weak()); a = allocdumb(aplo, 1024, mps_rank_exact()); mps_arena_collect(arena); comment(" %i", final_count); @@ -193,12 +219,16 @@ static void test(void) /* now to test leaving messages open for a long time! */ - mps_ap_destroy(apawl); mps_ap_destroy(apamc); + mps_ap_destroy(apamcz); + mps_ap_destroy(apams); + mps_ap_destroy(apawl); mps_ap_destroy(aplo); comment("Destroyed aps."); mps_pool_destroy(poolamc); + mps_pool_destroy(poolamcz); + mps_pool_destroy(poolams); mps_pool_destroy(poolawl); mps_pool_destroy(poollo); comment("Destroyed pools."); diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 64c72fe2982..fc00f37feb0 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -110,7 +110,7 @@ function/118.c function/119.c function/120.c % function/121.c -- job003495 -% function/122.c -- job003496 +function/122.c function/123.c function/124.c function/125.c diff --git a/mps/tool/branch b/mps/tool/branch index f60eccae235..686cdefa244 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -46,9 +46,9 @@ CHILD_RE = r'(?:{}|{})$'.format(TASK_BRANCH_RE, VERSION_BRANCH_RE) TASK_BRANCH_ENTRY = ''' - {child} + {date}/{task} Changes - {description} + {desc_html} In development (diffs). @@ -60,7 +60,7 @@ VERSION_BRANCH_ENTRY = ''' None. {parent}/...@{changelevel} - {description} + {desc_html} base
@@ -161,6 +161,9 @@ def main(argv): if not args.description: args.description = fmt("Branching {parent} to {child}.") print(fmt("description={description}")) + args.desc_html = re.sub(r'\b(job\d{6})\b', + fmt(r'\1'), + args.description) # Create the branch specification args.branch = fmt('{project}/{child}') diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect new file mode 100755 index 00000000000..97ff39dad74 --- /dev/null +++ b/mps/tool/p4-bisect @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# +# +# Ravenbrook +# +# +# P4-BISECT -- FIND CHANGE THAT INTRODUCED A BUG +# +# Gareth Rees, Ravenbrook Limited, 2014-04-14 +# +# +# 1. INTRODUCTION +# +# This script automates (or partly automates) the process of finding, +# by binary search, the change that introduced a bug. +# +# The interface is modelled closely on git-bisect(1). + +import argparse +from functools import partial +import json +from os import unlink +import p4 +import subprocess +import sys + +BISECT_FILE = '.p4-bisect' + +def error(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + exit(1) + +def sync(*filespecs): + try: + p4.do('sync', *filespecs) + except p4.Error as e: + if 'file(s) up-to-date' not in e.args[0]: + raise + +class State(object): + def __init__(self, **d): + self.filespec = d['filespec'] + self.changes = d['changes'] + if 'current' in d: + self.current = d['current'] + + @classmethod + def load(cls): + try: + with open(BISECT_FILE, 'r') as f: + return cls(**json.load(f)) + except FileNotFoundError: + error("p4-bisect not in progress here.") + + def save(self): + with open(BISECT_FILE, 'w') as f: + json.dump(vars(self), f) + + def update(self): + n = len(self.changes) + if n == 0: + print("no changes remaining.".format(**vars(self))) + elif n == 1: + print("{} change remaining: {}.".format(n, self.changes[0])) + elif n == 2: + print("{} changes remaining: [{}, {}]." + .format(n, self.changes[0], self.changes[-1])) + else: + print("{} changes remaining: [{}, ..., {}]." + .format(n, self.changes[0], self.changes[-1])) + if n > 0: + self.current = self.changes[n // 2] + print("Syncing to changelevel {current}.".format(**vars(self))) + sync(*['{}@{}'.format(f, self.current) for f in self.filespec]) + self.save() + +def help(parser, args): + parser.print_help() + +def start(args): + args.filespec = args.filespec or ['...'] + changes = sorted(int(c['change']) for c in p4.run('changes', *args.filespec)) + if not changes: + error("No changes for {}".format(' '.join(args.filespec))) + if args.first is None: + args.first = changes[0] + if args.last is None: + args.last = changes[-1] + state = State(filespec=args.filespec, + changes=[c for c in changes if args.first <= c <= args.last]) + state.update() + +def good(args): + state = State.load() + print("Change {current} good.".format(**vars(state))) + state.changes = [c for c in state.changes if c > state.current] + state.update() + +def bad(args): + state = State.load() + print("Change {current} bad.".format(**vars(state))) + state.changes = [c for c in state.changes if c < state.current] + state.update() + +def skip(args): + state = State.load() + print("Skipping change {current}.".format(**vars(state))) + state.changes.remove(state.current) + state.update() + +def reset(args): + state = State.load() + sync(*state.filespec) + unlink(BISECT_FILE) + +def run(args): + while True: + state = State.load() + if not state.changes: + break + result = subprocess.call([args.cmd] + args.args) + if result == 0: + good(None) + elif result == 125: + skip(None) + elif 0 < result < 128: + bad(None) + else: + exit(result) + +def main(argv): + parser = argparse.ArgumentParser(prog='p4-bisect') + subparsers = parser.add_subparsers() + a = subparsers.add_parser + + help_parser = a('help', help='show this help message') + help_parser.set_defaults(func=partial(help, parser)) + + start_parser = a('start', help='start a p4-bisect session') + aa = start_parser.add_argument + start_parser.add_argument('-f', '--filespec', action='append', + help='filespec to search') + start_parser.add_argument('first', nargs='?', type=int, + help='earliest changelevel to examine') + start_parser.add_argument('last', nargs='?', type=int, + help='latest changelevel to examine') + start_parser.set_defaults(func=start) + + good_parser = a('good', help='declare current revision good') + good_parser.set_defaults(func=good) + + bad_parser = a('bad', help='declare current revision bad') + bad_parser.set_defaults(func=bad) + + skip_parser = a('skip', help='skip current revision') + skip_parser.set_defaults(func=skip) + + reset_parser = a('reset', help='finish p4-bisect session') + reset_parser.set_defaults(func=reset) + + run_parser = a('run', help='run p4-bisect session automatically') + run_parser.add_argument('cmd', + help='command that determines if current ' + 'changelevel is good or bad') + run_parser.add_argument('args', nargs=argparse.REMAINDER, + help='arguments to pass to cmd') + run_parser.set_defaults(func=run) + + args = parser.parse_args(argv[1:]) + args.func(args) + +if __name__ == '__main__': + main(sys.argv) diff --git a/mps/tool/testopendylan b/mps/tool/testopendylan index 9c18938ef1e..a8aee4a0025 100755 --- a/mps/tool/testopendylan +++ b/mps/tool/testopendylan @@ -104,7 +104,7 @@ if [ -f "$REPO/Makefile" ]; then else ( cd -- "$REPO" && ./autogen.sh && - ./configure --with-mps="$MPS" --prefix="$PREFIX" + ./configure --with-gc=mps --with-gc-path="$MPS" --prefix="$PREFIX" ) fi ( cd -- "$REPO" && @@ -128,6 +128,9 @@ else ( # # 2014-03-20 GDR Created based on [WELCOME]. # +# 2014-04-14 GDR Updated configure args based on revised build +# instructions [WELCOME]. +# # # C. COPYRIGHT AND LICENCE # diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 7be1b135379..f4e06e56d09 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -24,12 +24,14 @@ set ALL_TEST_CASES=^ airtest.exe ^ amcss.exe ^ amcsshe.exe ^ + amcssth.exe ^ amsss.exe ^ amssshe.exe ^ apss.exe ^ arenacv.exe ^ awlut.exe ^ awluthe.exe ^ + awlutth.exe ^ btcv.exe ^ exposet0.exe ^ expt825.exe ^ @@ -39,7 +41,7 @@ set ALL_TEST_CASES=^ landtest.exe ^ locbwcss.exe ^ lockcov.exe ^ - lockutw3.exe ^ + lockut.exe ^ locusss.exe ^ locv.exe ^ messtest.exe ^ diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 290c124c0d8..a9d6cd87c33 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -36,6 +36,7 @@ ALL_TEST_CASES=" landtest locbwcss lockcov + lockut locusss locv messtest