From: Ivan Maidanski Date: Mon, 22 Oct 2018 08:04:36 +0000 (+0300) Subject: Enable disclaim_weakmap_test for the single-threaded environment X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6eba421;p=gc Enable disclaim_weakmap_test for the single-threaded environment (fix of commit 0cc2c0e7e) Issue #239 (bdwgc). Also, do some code refactoring and reformatting of disclaim_weakmap_test.c. * tests/disclaim_weakmap_test.c: Reformat code. * tests/disclaim_weakmap_test.c: Do not include stdarg.h, dbg_mlc.h, gc.h. * tests/disclaim_weakmap_test.c (THREAD_CNT): Rename to NTHREADS. * tests/disclaim_weakmap_test.c: Include errno.h, pthread.h, gc_atomic_ops.h only if GC_PTHREADS. * tests/disclaim_weakmap_test.c (NTHREADS): Set to 1 unless GC_PTHREADS. * tests/disclaim_weakmap_test.c [LINT2] (rand): Redefine to (int)GC_random() (to workaround a code defect reported by Coverity Scan). * tests/disclaim_weakmap_test.c (dief): Remove. * tests/disclaim_weakmap_test.c (FINALIZER_CLOSURE_FLAG, INVALIDATE_FLAG): New macro (used by weakmap_add, weakmap_disclaim). * tests/disclaim_weakmap_test.c (out_of_memory): Replace with CHECK_OOM(p). * tests/disclaim_weakmap_test.c (stat_added, stat_found, stat_removed, stat_skip_marked): Change type from volatile AO_t to unsigned (because it is accessed while holding the lock). * tests/disclaim_weakmap_test.c (struct weakmap): Add weakobj_kind field. * tests/disclaim_weakmap_test.c (weakmap_lock, weakmap_trylock, weakmap_unlock): No-op unless GC_PTHREADS. * tests/disclaim_weakmap_test.c (weakmap_add): Call GC_end_stubborn_change(). * tests/disclaim_weakmap_test.c (weakmap_add, weakmap_disclaim, weakmap_new): Call GC_PTR_STORE_AND_DIRTY(). * tests/disclaim_weakmap_test.c (weakmap_new): Call pthread_mutex_init() only if GC_PTHREADS. * tests/disclaim_weakmap_test.c (weakmap_destroy): New function (which calls pthread_mutex_destroy() if GC_PTHREADS). * tests/disclaim_weakmap_test.c (_weakobj_free_list, _weakobj_kind): Change global variable to local one declared in main(). * tests/disclaim_weakmap_test.c [TEST_MANUAL_VDB] (main): Call GC_set_manual_vdb_allowed(1). * tests/disclaim_weakmap_test.c [!NO_INCREMENTAL] (main): Call GC_enable_incremental(). * tests/disclaim_weakmap_test.c (main): Call GC_init_finalized_malloc() instead of multiple GC_register_displacement() calls; call weakmap_destroy(). * tests/disclaim_weakmap_test.c [!GC_PTHREADS] (main): Call test() once. * tests/tests.am (TESTS, check_PROGRAMS): Add disclaim_weakmap_test even if no THREADS. * tests/tests.am (disclaim_weakmap_test_SOURCES, disclaim_weakmap_test_LDADD): Define even if no THREADS. --- diff --git a/tests/disclaim_weakmap_test.c b/tests/disclaim_weakmap_test.c index 05922833..aa593ea5 100644 --- a/tests/disclaim_weakmap_test.c +++ b/tests/disclaim_weakmap_test.c @@ -14,351 +14,455 @@ /* This tests a case where disclaim notifiers sometimes return non-zero */ /* in order to protect objects from collection. */ -#include #include #include #include -#include -#include #ifdef HAVE_CONFIG_H /* For GC_[P]THREADS */ # include "config.h" #endif -#include "private/dbg_mlc.h" /* for oh type */ -#include "private/gc_atomic_ops.h" -#include "gc.h" -#include "gc_disclaim.h" +#include "gc_disclaim.h" /* includes gc.h */ #include "gc_mark.h" -#define THREAD_CNT 8 +#ifdef GC_PTHREADS +# ifndef NTHREADS +# define NTHREADS 8 +# endif +# include +# include +# include "private/gc_atomic_ops.h" /* for AO_t and AO_fetch_and_add1 */ +#else +# undef NTHREADS +# define NTHREADS 1 +#endif + +#ifdef LINT2 + /* Avoid include gc_priv.h. */ +# ifndef GC_API_PRIV +# define GC_API_PRIV GC_API +# endif +# ifdef __cplusplus + extern "C" { +# endif + GC_API_PRIV long GC_random(void); +# ifdef __cplusplus + } /* extern "C" */ +# endif +# undef rand +# define rand() (int)GC_random() +#endif /* LINT2 */ + #define POP_SIZE 200 -#define MUTATE_CNT (5000000/THREAD_CNT) -#define GROW_LIMIT (MUTATE_CNT/10) +#define MUTATE_CNT (5000000 / NTHREADS) +#define GROW_LIMIT (MUTATE_CNT / 10) #define WEAKMAP_CAPACITY 256 #define WEAKMAP_MUTEX_COUNT 32 -void -dief(int ec, const char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - vfprintf(stderr, fmt, va); - va_end(va); - fprintf(stderr, "\n"); - exit(ec); -} +/* FINALIZER_CLOSURE_FLAG definition matches the one in fnlz_mlc.c. */ +#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) +# define FINALIZER_CLOSURE_FLAG 0x2 +# define INVALIDATE_FLAG 0x1 +#else +# define FINALIZER_CLOSURE_FLAG 0x1 +# define INVALIDATE_FLAG 0x2 +#endif #define my_assert(e) \ if (!(e)) { \ - fflush(stdout); \ - fprintf(stderr, "Assertion failure, line %d: %s\n", __LINE__, #e); \ - exit(70); \ + fflush(stdout); \ + fprintf(stderr, "Assertion failure, line %d: %s\n", __LINE__, #e); \ + exit(70); \ } -void out_of_memory() { dief(69, "Out of memory."); } +#define CHECK_OOM(p) \ + do { \ + if (NULL == (p)) { \ + fprintf(stderr, "Out of memory\n"); \ + exit(69); \ + } \ + } while (0) -unsigned int -memhash(void *src, size_t len) +unsigned memhash(void *src, size_t len) { - unsigned int acc = 0; - size_t i; - my_assert(len % sizeof(GC_word) == 0); - for (i = 0; i < len / sizeof(GC_word); ++i) - acc = (2003*acc + ((GC_word *)src)[i]) / 3; - return acc; + unsigned acc = 0; + size_t i; + + my_assert(len % sizeof(GC_word) == 0); + for (i = 0; i < len / sizeof(GC_word); ++i) { + acc = (2003 * acc + ((GC_word *)src)[i]) / 3; + } + return acc; } -static void **_weakobj_free_list; -static unsigned int _weakobj_kind; +static unsigned stat_added; +static unsigned stat_found; +static unsigned stat_removed; +static unsigned stat_skip_marked; -static volatile AO_t stat_added = 0; -static volatile AO_t stat_found = 0; -static volatile AO_t stat_removed = 0; -static volatile AO_t stat_skip_locked = 0; -static volatile AO_t stat_skip_marked = 0; +#ifdef AO_HAVE_fetch_and_add1 + static volatile AO_t stat_skip_locked; +#else + static unsigned stat_skip_locked; +#endif struct weakmap_link { - GC_hidden_pointer obj; - struct weakmap_link *next; + GC_hidden_pointer obj; + struct weakmap_link *next; }; struct weakmap { +# ifdef GC_PTHREADS pthread_mutex_t mutex[WEAKMAP_MUTEX_COUNT]; - size_t key_size, obj_size, capacity; - struct weakmap_link **links; +# endif + size_t key_size; + size_t obj_size; + size_t capacity; + unsigned weakobj_kind; + struct weakmap_link **links; }; -void -weakmap_lock(struct weakmap *wm, unsigned int h) +void weakmap_lock(struct weakmap *wm, unsigned h) { +# ifdef GC_PTHREADS int err = pthread_mutex_lock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - if (err != 0) - dief(69, "pthread_mutex_lock: %s", strerror(err)); + my_assert(0 == err); +# else + (void)wm; (void)h; +# endif } -int -weakmap_trylock(struct weakmap *wm, unsigned int h) +int weakmap_trylock(struct weakmap *wm, unsigned h) { +# ifdef GC_PTHREADS int err = pthread_mutex_trylock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - if (err != 0 && err != EBUSY) - dief(69, "pthread_mutex_trylock: %s", strerror(err)); + if (err != 0 && err != EBUSY) { + fprintf(stderr, "pthread_mutex_trylock: %s\n", strerror(err)); + exit(69); + } return err; +# else + (void)wm; (void)h; + return 0; +# endif } -void -weakmap_unlock(struct weakmap *wm, unsigned int h) +void weakmap_unlock(struct weakmap *wm, unsigned h) { +# ifdef GC_PTHREADS int err = pthread_mutex_unlock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - if (err != 0) - dief(69, "pthread_mutex_unlock: %s", strerror(err)); + my_assert(0 == err); +# else + (void)wm; (void)h; +# endif } -static void *set_mark_bit(void *obj) { GC_set_mark_bit(obj); return NULL; } +void *GC_CALLBACK set_mark_bit(void *obj) +{ + GC_set_mark_bit(obj); + return NULL; +} -void * -weakmap_add(struct weakmap *wm, void *obj) +void *weakmap_add(struct weakmap *wm, void *obj) { - struct weakmap_link *link, *new_link, **first; - GC_word *new_base; - void *new_obj; - unsigned int h; - - /* Lock and look for an existing entry. */ - h = memhash(obj, wm->key_size); - first = &wm->links[h % wm->capacity]; - weakmap_lock(wm, h); - for (link = *first; link != NULL; link = link->next) { - void *old_obj = GC_REVEAL_POINTER(link->obj); - if (memcmp(old_obj, obj, wm->key_size) == 0) { - GC_call_with_alloc_lock(set_mark_bit, (GC_word *)old_obj - 1); - /* Pointers in the key part may have been freed and reused, */ - /* changing the keys without memcmp noticing. This is okay */ - /* as long as we update the mapped value. */ - if (memcmp((char *)old_obj + wm->key_size, - (char *)obj + wm->key_size, - wm->obj_size - wm->key_size) != 0) - memcpy((char *)old_obj + wm->key_size, - (char *)obj + wm->key_size, - wm->obj_size - wm->key_size); - weakmap_unlock(wm, h); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Found %p %#x.\n", old_obj, h); -# endif - AO_fetch_and_add1(&stat_found); - return old_obj; - } + struct weakmap_link *link, *new_link, **first; + GC_word *new_base; + void *new_obj; + unsigned h; + size_t key_size = wm->key_size; + + /* Lock and look for an existing entry. */ + h = memhash(obj, key_size); + first = &wm->links[h % wm->capacity]; + weakmap_lock(wm, h); + + for (link = *first; link != NULL; link = link->next) { + void *old_obj = GC_REVEAL_POINTER(link->obj); + + if (memcmp(old_obj, obj, key_size) == 0) { + GC_call_with_alloc_lock(set_mark_bit, (GC_word *)old_obj - 1); + /* Pointers in the key part may have been freed and reused, */ + /* changing the keys without memcmp noticing. This is okay */ + /* as long as we update the mapped value. */ + if (memcmp((char *)old_obj + key_size, (char *)obj + key_size, + wm->obj_size - key_size) != 0) { + memcpy((char *)old_obj + key_size, (char *)obj + key_size, + wm->obj_size - key_size); + GC_end_stubborn_change((char *)old_obj + key_size); + } + ++stat_found; + weakmap_unlock(wm, h); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Found %p, hash=%p\n", old_obj, (void *)(GC_word)h); +# endif + return old_obj; } + } + + /* Create new object. */ + new_base = (GC_word *)GC_generic_malloc(sizeof(GC_word) + wm->obj_size, + wm->weakobj_kind); + CHECK_OOM(new_base); + *new_base = (GC_word)wm | FINALIZER_CLOSURE_FLAG; + new_obj = (void *)(new_base + 1); + memcpy(new_obj, obj, wm->obj_size); + GC_end_stubborn_change(new_base); + + /* Add the object to the map. */ + new_link = GC_NEW(struct weakmap_link); + CHECK_OOM(new_link); + new_link->obj = GC_HIDE_POINTER(new_obj); + new_link->next = *first; + GC_END_STUBBORN_CHANGE(new_link); + GC_PTR_STORE_AND_DIRTY(first, new_link); + ++stat_added; + weakmap_unlock(wm, h); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Added %p, hash=%p\n", new_obj, (void *)(GC_word)h); +# endif + return new_obj; +} - /* Create new object. */ - new_base = (GC_word *)GC_generic_malloc(sizeof(GC_word) + wm->obj_size, - _weakobj_kind); - if (!new_base) out_of_memory(); - *new_base = (GC_word)wm | 1; - new_obj = (void *)(new_base + 1); - memcpy(new_obj, obj, wm->obj_size); - - /* Add the object to the map. */ - new_link = GC_NEW(struct weakmap_link); - if (!new_link) out_of_memory(); - new_link->obj = GC_HIDE_POINTER(new_obj); - new_link->next = *first; - *first = new_link; - - weakmap_unlock(wm, h); +int GC_CALLBACK weakmap_disclaim(void *obj_base) +{ + struct weakmap *wm; + struct weakmap_link **link; + GC_word hdr; + void *obj; + unsigned h; + + /* Decode header word. */ + hdr = *(GC_word *)obj_base; + if ((hdr & FINALIZER_CLOSURE_FLAG) == 0) + return 0; /* on GC free list, ignore it. */ + + my_assert((hdr & INVALIDATE_FLAG) == 0); + wm = (struct weakmap *)(hdr & ~(GC_word)FINALIZER_CLOSURE_FLAG); + obj = (GC_word *)obj_base + 1; + + /* Lock and check for mark. */ + h = memhash(obj, wm->key_size); + if (weakmap_trylock(wm, h) != 0) { +# ifdef AO_HAVE_fetch_and_add1 + AO_fetch_and_add1(&stat_skip_locked); +# else + ++stat_skip_locked; +# endif +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Skipping locked %p, hash=%p\n", obj, (void *)(GC_word)h); +# endif + return 1; + } + if (GC_is_marked(obj_base)) { # ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Added %p %#x.\n", new_obj, h); + printf("Skipping marked %p, hash=%p\n", obj, (void *)(GC_word)h); # endif - AO_fetch_and_add1(&stat_added); - return new_obj; + ++stat_skip_marked; + weakmap_unlock(wm, h); + return 1; + } + + /* Remove obj from wm. */ +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Removing %p, hash=%p\n", obj, (void *)(GC_word)h); +# endif + ++stat_removed; + *(GC_word *)obj_base |= INVALIDATE_FLAG; + for (link = &wm->links[h % wm->capacity];; link = &(*link)->next) { + void *old_obj; + + if (NULL == *link) { + fprintf(stderr, "Did not find %p\n", obj); + exit(70); + } + old_obj = GC_REVEAL_POINTER((*link)->obj); + if (old_obj == obj) + break; + my_assert(memcmp(old_obj, obj, wm->key_size) != 0); + } + GC_PTR_STORE_AND_DIRTY(link, (*link)->next); + weakmap_unlock(wm, h); + return 0; } -int -weakmap_disclaim(void *obj_base) +struct weakmap *weakmap_new(size_t capacity, size_t key_size, size_t obj_size, + unsigned weakobj_kind) { - struct weakmap *wm; - struct weakmap_link **link; - GC_word hdr; - void *obj; - unsigned int h; - - /* Decode header word. */ - hdr = *(GC_word *)obj_base; - if ((hdr & 1) == 0) return 0; /* on GC free list, ignore */ - my_assert((hdr & 2) == 0); /* assert not invalidated */ - wm = (struct weakmap *)(hdr & ~(GC_word)1); - obj = (GC_word *)obj_base + 1; - - /* Lock and check for mark. */ - h = memhash(obj, wm->key_size); - if (weakmap_trylock(wm, h) != 0) { -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Skipping locked %p %#x.\n", obj, h); -# endif - AO_fetch_and_add1(&stat_skip_locked); - return 1; - } - if (GC_is_marked(obj_base)) { -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Skipping marked %p %#x.\n", obj, h); -# endif - AO_fetch_and_add1(&stat_skip_marked); - weakmap_unlock(wm, h); - return 1; + struct weakmap *wm = GC_NEW(struct weakmap); + + CHECK_OOM(wm); +# ifdef GC_PTHREADS + { + int i; + for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { + int err = pthread_mutex_init(&wm->mutex[i], NULL); + my_assert(err == 0); + } } - - /* Remove obj from wm. */ -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Removing %p %#x.\n", obj, h); -# endif - AO_fetch_and_add1(&stat_removed); - *(GC_word *)obj_base |= 2; /* invalidate */ - link = &wm->links[h % wm->capacity]; - while (*link != NULL) { - void *old_obj = GC_REVEAL_POINTER((*link)->obj); - if (old_obj == obj) { - *link = (*link)->next; - weakmap_unlock(wm, h); - return 0; - } - else { - my_assert(memcmp(old_obj, obj, wm->key_size) != 0); - link = &(*link)->next; - } - } - dief(70, "Did not find %p.", obj); - weakmap_unlock(wm, h); - return 0; +# endif + wm->key_size = key_size; + wm->obj_size = obj_size; + wm->capacity = capacity; + wm->weakobj_kind = weakobj_kind; + GC_PTR_STORE_AND_DIRTY(&wm->links, + GC_MALLOC(sizeof(struct weakmap_link *) * capacity)); + CHECK_OOM(wm->links); + return wm; } -struct weakmap * -weakmap_new(size_t capacity, size_t key_size, size_t obj_size) +void weakmap_destroy(struct weakmap *wm) { +# ifdef GC_PTHREADS int i; - struct weakmap *wm = GC_NEW(struct weakmap); - if (!wm) out_of_memory(); - for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) - pthread_mutex_init(&wm->mutex[i], NULL); - wm->key_size = key_size; - wm->obj_size = obj_size; - wm->capacity = capacity; - wm->links = (struct weakmap_link **)GC_malloc(sizeof(struct weakmap_link *) - * capacity); - if (!wm->links) out_of_memory(); - memset(wm->links, 0, sizeof(struct weakmap_link *) * capacity); - return wm; + + for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { + (void)pthread_mutex_destroy(&wm->mutex[i]); + } +# else + (void)wm; +# endif } -static struct weakmap *_pair_hcset; +struct weakmap *pair_hcset; -#define PAIR_MAGIC_SIZE 16 +#define PAIR_MAGIC_SIZE 16 /* should not exceed sizeof(pair_magic) */ struct pair_key { - struct pair *car, *cdr; + struct pair *car, *cdr; }; + struct pair { - struct pair *car, *cdr; - char magic[PAIR_MAGIC_SIZE]; - int checksum; + struct pair *car; + struct pair *cdr; + char magic[PAIR_MAGIC_SIZE]; + int checksum; }; + static const char * const pair_magic = "PAIR_MAGIC_BYTES"; -struct pair * -pair_new(struct pair *car, struct pair *cdr) +struct pair *pair_new(struct pair *car, struct pair *cdr) { - struct pair tmpl; - memset(&tmpl, 0, sizeof(tmpl)); - tmpl.car = car; - tmpl.cdr = cdr; - memcpy(tmpl.magic, pair_magic, PAIR_MAGIC_SIZE); - tmpl.checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0); - return (struct pair *)weakmap_add(_pair_hcset, &tmpl); + struct pair tmpl; + + memset(&tmpl, 0, sizeof(tmpl)); /* To clear the paddings (to avoid */ + /* a compiler warning). */ + tmpl.car = car; + tmpl.cdr = cdr; + memcpy(tmpl.magic, pair_magic, PAIR_MAGIC_SIZE); + tmpl.checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0); + return (struct pair *)weakmap_add(pair_hcset, &tmpl); } -void -pair_check_rec(struct pair *p, int line) +void pair_check_rec(struct pair *p, int line) { - while (p) { - int checksum = 782; - if (memcmp(p->magic, pair_magic, PAIR_MAGIC_SIZE) != 0) - dief(70, "Magic bytes wrong for %p at %d.", (void *)p, line); - if (p->car) checksum += p->car->checksum; - if (p->cdr) checksum += p->cdr->checksum; - if (p->checksum != checksum) - dief(70, "Checksum failure for %p = (%p, %p) at %d.", - (void *)p, (void *)p->car, (void *)p->cdr, line); - switch (rand() % 2) { - case 0: p = p->car; break; - case 1: p = p->cdr; break; - } + while (p != NULL) { + int checksum = 782; + + if (memcmp(p->magic, pair_magic, PAIR_MAGIC_SIZE) != 0) { + fprintf(stderr, "Magic bytes wrong for %p at %d\n", (void *)p, line); + exit(70); + } + if (p->car != NULL) + checksum += p->car->checksum; + if (p->cdr != NULL) + checksum += p->cdr->checksum; + if (p->checksum != checksum) { + fprintf(stderr, "Checksum failure for %p = (%p, %p) at %d\n", + (void *)p, (void *)p->car, (void *)p->cdr, line); + exit(70); } + p = (rand() & 1) != 0 ? p->cdr : p->car; + } } void *test(void *data) { - int i; - struct pair *pop[POP_SIZE], *p0, *p1; - memset(pop, 0, sizeof(pop)); - for (i = 0; i < MUTATE_CNT; ++i) { - int bits = rand(); - int t = (bits >> 3) % POP_SIZE; - switch (bits % (i > GROW_LIMIT? 5 : 3)) { - case 0: case 3: - if (pop[t]) - pop[t] = pop[t]->car; - break; - case 1: case 4: - if (pop[t]) - pop[t] = pop[t]->cdr; - break; - case 2: - p0 = pop[rand() % POP_SIZE]; - p1 = pop[rand() % POP_SIZE]; - pop[t] = pair_new(p0, p1); - my_assert(pop[t] == pair_new(p0, p1)); - my_assert(pop[t]->car == p0); - my_assert(pop[t]->cdr == p1); - break; - } - pair_check_rec(pop[rand() % POP_SIZE], __LINE__); + int i; + struct pair *p0, *p1; + struct pair *pop[POP_SIZE]; + + memset(pop, 0, sizeof(pop)); + for (i = 0; i < MUTATE_CNT; ++i) { + int bits = rand(); + int t = (bits >> 3) % POP_SIZE; + + switch (bits % (i > GROW_LIMIT ? 5 : 3)) { + case 0: + case 3: + if (pop[t] != NULL) + pop[t] = pop[t]->car; + break; + case 1: + case 4: + if (pop[t] != NULL) + pop[t] = pop[t]->cdr; + break; + case 2: + p0 = pop[rand() % POP_SIZE]; + p1 = pop[rand() % POP_SIZE]; + pop[t] = pair_new(p0, p1); + my_assert(pair_new(p0, p1) == pop[t]); + my_assert(pop[t]->car == p0); + my_assert(pop[t]->cdr == p1); + break; } - return data; + pair_check_rec(pop[rand() % POP_SIZE], __LINE__); + } + return data; } -int main() +int main(void) { + unsigned weakobj_kind; + void **weakobj_free_list; +# ifdef GC_PTHREADS int i; - pthread_t th[THREAD_CNT]; - GC_set_all_interior_pointers(0); - GC_register_displacement(sizeof(GC_word)); - GC_register_displacement(sizeof(oh) + sizeof(GC_word)); - GC_register_displacement(1); - GC_register_displacement(sizeof(oh) + 1); - GC_INIT(); - - _weakobj_free_list = GC_new_free_list(); - if (!_weakobj_free_list) out_of_memory(); - _weakobj_kind = GC_new_kind(_weakobj_free_list, 0 | GC_DS_LENGTH, 1, 1); - GC_register_disclaim_proc(_weakobj_kind, weakmap_disclaim, 1); - _pair_hcset = weakmap_new(WEAKMAP_CAPACITY, - sizeof(struct pair_key), sizeof(struct pair)); - - for (i = 0; i < THREAD_CNT; ++i) { - int err = GC_pthread_create(&th[i], NULL, test, NULL); - if (err) - dief(69, "Failed to create thread # %d: %s", i, strerror(err)); + pthread_t th[NTHREADS]; +# endif + + GC_set_all_interior_pointers(0); /* for a stricter test */ +# ifdef TEST_MANUAL_VDB + GC_set_manual_vdb_allowed(1); +# endif + GC_INIT(); + GC_init_finalized_malloc(); /* to register the displacements */ +# ifndef NO_INCREMENTAL + GC_enable_incremental(); +# endif + + weakobj_free_list = GC_new_free_list(); + CHECK_OOM(weakobj_free_list); + weakobj_kind = GC_new_kind(weakobj_free_list, /* 0 | */ GC_DS_LENGTH, + 1 /* adjust */, 1 /* clear */); + GC_register_disclaim_proc(weakobj_kind, weakmap_disclaim, + 1 /* mark_unconditionally */); + pair_hcset = weakmap_new(WEAKMAP_CAPACITY, sizeof(struct pair_key), + sizeof(struct pair), weakobj_kind); + +# ifdef GC_PTHREADS + for (i = 0; i < NTHREADS; ++i) { + int err = pthread_create(&th[i], NULL, test, NULL); + if (err != 0) { + fprintf(stderr, "Failed to create thread #%d: %s\n", + i, strerror(err)); + exit(1); + } } - for (i = 0; i < THREAD_CNT; ++i) { - int err = GC_pthread_join(th[i], NULL); - if (err) - dief(69, "Failed to join thread # %d: %s", i, strerror(err)); + for (i = 0; i < NTHREADS; ++i) { + int err = pthread_join(th[i], NULL); + if (err != 0) { + fprintf(stderr, "Failed to join thread #%d: %s\n", i, strerror(err)); + exit(69); + } } - printf("%5d added, %6d found; %5d removed, %5d locked, %d marked; " - "%d remains\n", - (int)stat_added, (int)stat_found, (int)stat_removed, - (int)stat_skip_locked, (int)stat_skip_marked, - (int)(stat_added - stat_removed)); - return 0; +# else + (void)test(NULL); +# endif + weakmap_destroy(pair_hcset); + printf("%u added, %u found; %u removed, %u locked, %u marked; %u remains\n", + stat_added, stat_found, stat_removed, (unsigned)stat_skip_locked, + stat_skip_marked, stat_added - stat_removed); + return 0; } diff --git a/tests/tests.am b/tests/tests.am index e49aabaa..995cfea8 100644 --- a/tests/tests.am +++ b/tests/tests.am @@ -124,11 +124,12 @@ check_PROGRAMS += disclaim_bench disclaim_bench_SOURCES = tests/disclaim_bench.c disclaim_bench_LDADD = $(test_ldadd) -if THREADS TESTS += disclaim_weakmap_test$(EXEEXT) check_PROGRAMS += disclaim_weakmap_test disclaim_weakmap_test_SOURCES = tests/disclaim_weakmap_test.c -disclaim_weakmap_test_LDADD = $(test_ldadd) $(THREADDLLIBS) +disclaim_weakmap_test_LDADD = $(test_ldadd) +if THREADS +disclaim_weakmap_test_LDADD += $(THREADDLLIBS) endif endif