]> granicus.if.org Git - gc/commitdiff
Make heap walker accept callback
authorIvan Maidanski <ivmai@mail.ru>
Tue, 4 Aug 2015 22:20:32 +0000 (01:20 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 4 Aug 2015 22:24:11 +0000 (01:24 +0300)
* alloc.c (GC_mercury_callback_reachable_object): Remove.
* include/gc.h (GC_mercury_callback_reachable_object): Likewise.
* include/private/gc_priv.h (GC_mercury_enumerate_reachable_objects):
Likewise.
* alloc.c (GC_finish_collection): Do not call
GC_mercury_enumerate_reachable_objects.
* include/gc_mark.h (GC_reachable_object_proc): New public typedef.
* include/gc_mark.h (GC_enumerate_reachable_objects_inner): New API
function declaration.
* reclaim.c (enumerate_reachable_s): New struct type.
* reclaim.c (GC_mercury_do_enumerate_reachable_objects): Rename to
GC_do_enumerate_reachable_objects; replace while() with for(); use 2nd
argument to pass client callback and custom data; call client callback
(passed via the argument) instead of
GC_mercury_callback_reachable_object; pass object size in bytes
instead of words to client callback.
* reclaim.c (GC_mercury_enumerate_reachable_objects): Rename to
GC_enumerate_reachable_objects_inner; decorate with GC_API/GC_CALL;
add 2 arguments (client callback and custom data); remove assertion
for GC_mercury_callback_reachable_object; add assertion for acquired
lock.
* tests/test.c: Include gc_mark.h unconditionally.
* tests/test.c (reachable_objs_counter,
reachable_objs_count_enumerator): New function.
* tests/test.c (check_heap_stats): New local variable "obj_count";
invoke GC_call_with_alloc_lock(reachable_objs_count_enumerator);
print final number of reachable objects.

alloc.c
include/gc.h
include/gc_mark.h
include/private/gc_priv.h
reclaim.c
tests/test.c

diff --git a/alloc.c b/alloc.c
index 0a77fe5365f5e9ea773f524d6d5382a65336604c..9eb1c06e51641f3e341dcab8bd4bcdf3cbd4269b 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -63,10 +63,6 @@ word GC_non_gc_bytes = 0;  /* Number of bytes not intended to be collected */
 
 word GC_gc_no = 0;
 
-void (*GC_mercury_callback_reachable_object)(GC_word *, size_t) = NULL;
-                           /* Callbacks for mercury to notify   */
-                           /* the runtime of certain events     */
-
 #ifndef GC_DISABLE_INCREMENTAL
   GC_INNER int GC_incremental = 0;      /* By default, stop the world.  */
 #endif
@@ -934,9 +930,6 @@ STATIC void GC_finish_collection(void)
         }
 #   endif
     COND_DUMP;
-    if (GC_mercury_callback_reachable_object) {
-       GC_mercury_enumerate_reachable_objects();
-    }
     if (GC_find_leak) {
       /* Mark all objects on the free list.  All objects should be      */
       /* marked when we're done.                                        */
index e98431ca86721364817069819c2aef9198bd5bfb..d1423818664cf726829847922dc1a0b094095ab3 100644 (file)
@@ -392,9 +392,6 @@ GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
 GC_API void GC_CALL GC_set_time_limit(unsigned long);
 GC_API unsigned long GC_CALL GC_get_time_limit(void);
 
-GC_API void (*GC_mercury_callback_reachable_object)(GC_word *, size_t);
-                /* This object on the heap is reachable. */
-
 /* Public procedures */
 
 /* Set whether the GC will allocate executable memory pages or not.     */
index 28d2005a91d202be9223b47db786a1b17a718991..7edb7f5ec70c52f4e601cf3e11f9ccb2a5d86475 100644 (file)
@@ -289,6 +289,16 @@ typedef void (GC_CALLBACK * GC_push_other_roots_proc)(void);
 GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
 GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
 
+/* Walk the GC heap visiting all reachable objects.  Assume the caller  */
+/* holds the allocation lock.  Object base pointer, object size and     */
+/* client custom data are passed to the callback (holding the lock).    */
+typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */,
+                                                size_t /* bytes */,
+                                                void * /* client_data */);
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+                                GC_reachable_object_proc,
+                                void * /* client_data */) GC_ATTR_NONNULL(1);
+
 #ifdef __cplusplus
   } /* end of extern "C" */
 #endif
index e369a7cc2b97a793394907fdd2cb7cad153684aa..f3f0718ee72d3d7fba34c6be6ec52ae482d2b0c3 100644 (file)
@@ -2082,8 +2082,6 @@ void GC_print_static_roots(void);
 
 extern word GC_fo_entries; /* should be visible in extra/MacOS.c */
 
-GC_INNER void GC_mercury_enumerate_reachable_objects(void);
-
 #ifdef KEEP_BACK_PTRS
    GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest);
    GC_INNER void GC_marked_for_finalization(ptr_t dest);
index 0685f937cdd5671bce35ea70924806299d52f544..4f40cbb43fbebdadfe05a39f8bce5059154a66d0 100644 (file)
--- a/reclaim.c
+++ b/reclaim.c
@@ -773,38 +773,45 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
   }
 #endif /* !EAGER_SWEEP && ENABLE_DISCLAIM */
 
-STATIC void GC_mercury_do_enumerate_reachable_objects(struct hblk *hbp,
-    word dummy)
+struct enumerate_reachable_s {
+  GC_reachable_object_proc proc;
+  void *client_data;
+};
+
+STATIC void GC_do_enumerate_reachable_objects(struct hblk *hbp, word ped)
 {
-    struct hblkhdr * hhdr = HDR(hbp);
-    size_t sz = hhdr -> hb_sz;
-    size_t bit_no;
-    char *p, *plim;
+  struct hblkhdr *hhdr = HDR(hbp);
+  size_t sz = hhdr -> hb_sz;
+  size_t bit_no;
+  char *p, *plim;
 
-    if (GC_block_empty(hhdr)) {
-        return;
-    }
+  if (GC_block_empty(hhdr)) {
+    return;
+  }
 
-    p = hbp->hb_body;
-    bit_no = 0;
-    if (sz > MAXOBJBYTES) { /* one big object */
-        plim = p;
-    } else {
-        plim = hbp->hb_body + HBLKSIZE - sz;
-    }
-    /* Go through all words in block. */
-    while (p <= plim) {
-        if (mark_bit_from_hdr(hhdr, bit_no)) {
-            GC_mercury_callback_reachable_object((GC_word *)p,
-               BYTES_TO_WORDS(sz));
-        }
-        bit_no += MARK_BIT_OFFSET(sz);
-        p += sz;
+  p = hbp->hb_body;
+  if (sz > MAXOBJBYTES) { /* one big object */
+    plim = p;
+  } else {
+    plim = hbp->hb_body + HBLKSIZE - sz;
+  }
+  /* Go through all words in block. */
+  for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) {
+    if (mark_bit_from_hdr(hhdr, bit_no)) {
+      ((struct enumerate_reachable_s *)ped)->proc(p, sz,
+                        ((struct enumerate_reachable_s *)ped)->client_data);
     }
+  }
 }
 
-GC_INNER void GC_mercury_enumerate_reachable_objects(void)
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+                                                GC_reachable_object_proc proc,
+                                                void *client_data)
 {
-    GC_ASSERT(GC_mercury_callback_reachable_object);
-    GC_apply_to_all_blocks(GC_mercury_do_enumerate_reachable_objects, (word)0);
+  struct enumerate_reachable_s ed;
+
+  GC_ASSERT(I_HOLD_LOCK());
+  ed.proc = proc;
+  ed.client_data = client_data;
+  GC_apply_to_all_blocks(GC_do_enumerate_reachable_objects, (word)&ed);
 }
index 9607bddf591239f5f8ca161471b629ce165fc0a4..a8604b843d375978fcfdbcf7ed5a4b5cdcfa5ba7 100644 (file)
@@ -260,9 +260,10 @@ sexpr cons (sexpr x, sexpr y)
 }
 # endif
 
+#include "gc_mark.h"
+
 #ifdef GC_GCJ_SUPPORT
 
-#include "gc_mark.h"
 #include "gc_gcj.h"
 
 /* The following struct emulates the vtable in gcj.     */
@@ -1396,6 +1397,32 @@ void run_one_test(void)
       GC_log_printf("Finished %p\n", (void *)&start_time);
 }
 
+void GC_CALLBACK reachable_objs_counter(void *obj, size_t size,
+                                        void *pcounter)
+{
+  if (0 == size) {
+    GC_printf("Reachable object has zero size\n");
+    FAIL;
+  }
+  if (GC_base(obj) != obj) {
+    GC_printf("Invalid reachable object base passed by enumerator: %p\n",
+              obj);
+    FAIL;
+  }
+  if (GC_size(obj) != size) {
+    GC_printf("Invalid reachable object size passed by enumerator: %lu\n",
+              (unsigned long)size);
+    FAIL;
+  }
+  (*(unsigned *)pcounter)++;
+}
+
+void * GC_CALLBACK reachable_objs_count_enumerator(void *pcounter)
+{
+  GC_enumerate_reachable_objects_inner(reachable_objs_counter, pcounter);
+  return NULL;
+}
+
 #define NUMBER_ROUND_UP(v, bound) ((((v) + (bound) - 1) / (bound)) * (bound))
 
 void check_heap_stats(void)
@@ -1411,6 +1438,7 @@ void check_heap_stats(void)
         int late_finalize_count = 0;
 #     endif
 #   endif
+    unsigned obj_count = 0;
 
 #   ifdef VERY_SMALL_CONFIG
     /* The upper bounds are a guess, which has been empirically */
@@ -1468,6 +1496,8 @@ void check_heap_stats(void)
           FAIL;
         }
       }
+    (void)GC_call_with_alloc_lock(reachable_objs_count_enumerator,
+                                  &obj_count);
     GC_printf("Completed %u tests\n", n_tests);
     GC_printf("Allocated %d collectable objects\n", collectable_count);
     GC_printf("Allocated %d uncollectable objects\n",
@@ -1540,6 +1570,7 @@ void check_heap_stats(void)
             (unsigned long)max_heap_sz);
         FAIL;
     }
+    GC_printf("Final number of reachable objects is %u\n", obj_count);
 
 #   ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
       /* Get global counters (just to check the functions work).  */