Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
146 lines (138 sloc) 3.55 KB
diff --git a/gc.c b/gc.c
index 6381eb1..487ee60 100644
--- a/source/gc.c
+++ b/source/gc.c
@@ -192,6 +192,76 @@ static void run_final();
static VALUE nomem_error;
static void garbage_collect();
+/* likely */
+#if __GNUC__ >= 3
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else /* __GNUC__ >= 3 */
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif /* __GNUC__ >= 3 */
+
+typedef struct gc_event_hook {
+ rb_gc_event_hook_func_t func;
+ rb_gc_event_t events;
+ struct gc_event_hook *next;
+} rb_gc_event_hook_t;
+
+static rb_gc_event_hook_t *gc_event_hooks;
+
+#define EXEC_GC_EVENT_HOOK(event, obj) \
+ do { \
+ rb_gc_event_hook_t *hook = gc_event_hooks; \
+ rb_gc_event_hook_func_t hook_func; \
+ rb_gc_event_t events; \
+ \
+ while (hook) { \
+ hook_func = hook->func; \
+ events = hook->events; \
+ hook = hook->next; \
+ if (events & event) \
+ (*hook_func)(event, obj); \
+ } \
+ } while (0)
+
+void
+rb_gc_add_event_hook(func, events)
+ rb_gc_event_hook_func_t func;
+ rb_gc_event_t events;
+{
+ rb_gc_event_hook_t *hook;
+
+ hook = ALLOC(rb_gc_event_hook_t);
+ hook->func = func;
+ hook->events = events;
+ hook->next = gc_event_hooks;
+ gc_event_hooks = hook;
+}
+
+int
+rb_gc_remove_event_hook(func)
+ rb_gc_event_hook_func_t func;
+{
+ rb_gc_event_hook_t *prev, *hook;
+
+ prev = NULL;
+ hook = gc_event_hooks;
+ while (hook) {
+ if (hook->func == func) {
+ if (prev) {
+ prev->next = hook->next;
+ }
+ else {
+ gc_event_hooks = hook->next;
+ }
+ xfree(hook);
+ return 0;
+ }
+ prev = hook;
+ hook = hook->next;
+ }
+ return -1;
+}
NORETURN(void rb_exc_jump _((VALUE)));
@@ -1008,6 +1078,9 @@ rb_newobj()
#endif
live_objects++;
allocated_objects++;
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_NEWOBJ, obj);
+ }
return obj;
}
@@ -1893,6 +1966,9 @@ static int
obj_free(obj)
VALUE obj;
{
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_OBJFREE, obj);
+ }
switch (BUILTIN_TYPE(obj)) {
case T_NIL:
case T_FIXNUM:
@@ -2191,6 +2267,9 @@ garbage_collect()
/* This assumes that all registers are saved into the jmp_buf (and stack) */
rb_setjmp(save_regs_gc_mark);
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_START, Qnil);
+ }
#if STACK_WIPE_SITES & 0x400
# ifdef nativeAllocA
if (__stack_past (top, stack_limit)) {
@@ -2211,6 +2290,9 @@ garbage_collect()
#else
garbage_collect_0(top);
#endif
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_END, Qnil);
+ }
}
void
diff --git a/node.h b/node.h
index 3e60603..af7a3fd 100644
--- a/source/node.h
+++ b/source/node.h
@@ -375,6 +375,19 @@ NODE *rb_copy_node_scope _((NODE *, NODE *));
void rb_add_event_hook _((rb_event_hook_func_t,rb_event_t));
int rb_remove_event_hook _((rb_event_hook_func_t));
+typedef unsigned int rb_gc_event_t;
+
+#define RUBY_GC_EVENT_NONE 0x00
+#define RUBY_GC_EVENT_START 0x01
+#define RUBY_GC_EVENT_END 0x02
+#define RUBY_GC_EVENT_NEWOBJ 0x04
+#define RUBY_GC_EVENT_OBJFREE 0x08
+#define RUBY_GC_EVENT_ALL 0xff
+
+typedef void (*rb_gc_event_hook_func_t) _((rb_gc_event_t,VALUE));
+void rb_gc_add_event_hook _((rb_gc_event_hook_func_t,rb_gc_event_t));
+int rb_gc_remove_event_hook _((rb_gc_event_hook_func_t));
+
#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
#include <ucontext.h>
#define USE_CONTEXT