]> granicus.if.org Git - gc/commitdiff
Enable disclaim_weakmap_test for the single-threaded environment
authorIvan Maidanski <ivmai@mail.ru>
Mon, 22 Oct 2018 08:04:36 +0000 (11:04 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 22 Oct 2018 08:13:42 +0000 (11:13 +0300)
(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.

tests/disclaim_weakmap_test.c
tests/tests.am

index 059228330adb132ec94f6bc6ec4fb2596e33484b..aa593ea56493f1d7e68579d72efec3912e502aff 100644 (file)
 /* This tests a case where disclaim notifiers sometimes return non-zero */
 /* in order to protect objects from collection.                         */
 
-#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <pthread.h>
-#include <stdarg.h>
 
 #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 <errno.h>
+# include <pthread.h>
+# 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;
 }
index e49aabaa27046965661bc673b3841461610de584..995cfea84877210b2c58cf7859c344c79024348f 100644 (file)
@@ -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