summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-06-16 21:07:26 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-06-16 21:07:26 +0000
commit06f833e6d5b096afa294725044c1f54e5ae9c414 (patch)
tree1d776d47824eba9d158bca97a5ffae8d509a7238 /gc.c
parent6883f97a0e8c0ab95171e2723e4bf6a7e603134b (diff)
* gc.c (rb_objspace_each_objects): New C API, added.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23708 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c102
1 files changed, 90 insertions, 12 deletions
diff --git a/gc.c b/gc.c
index 6d3c34e0bb..8ba17c6565 100644
--- a/gc.c
+++ b/gc.c
@@ -2384,16 +2384,53 @@ Init_heap(void)
init_heap(&rb_objspace);
}
-static VALUE
-os_obj_of(rb_objspace_t *objspace, VALUE of)
+/*
+ * rb_objspace_each_objects() is special C API to walk through
+ * Ruby object space. This C API is too difficult to use it.
+ * To be frank, you should not use it. Or you need to read the
+ * source code of this function and understand what this function does.
+ *
+ * 'callback' will be called several times (the number of heap slot,
+ * at current implementation) with:
+ * vstart: a pointer to the first living object of the heap_slot.
+ * vend: a pointer to next to the valid heap_slot area.
+ * stride: a distance to next VALUE.
+ *
+ * If callback() returns non-zero, the iteration will be stopped.
+ *
+ * This is a sample callback code to iterate liveness objects:
+ *
+ * int
+ * sample_callback(void *vstart, void *vend, int stride, void *data) {
+ * VALUE v = (VALUE)vstart;
+ * for (; v != (VALUE)vend; v += stride) {
+ * if (RBASIC(v)->flasgs) { // liveness check
+ * // do something with live object 'v'
+ * }
+ * return 0; // continue to iteration
+ * }
+ *
+ * Note: 'vstart' is not a top of heap_slot. This point the first
+ * living object to grasp at least one object to avoid GC issue.
+ * This means that you can not walk through all Ruby object slot
+ * including freed object slot.
+ *
+ * Note: On this implementation, 'stride' is same as sizeof(RVALUE).
+ * However, there are possibilities to pass variable values with
+ * 'stride' with some reasons. You must use stride instead of
+ * use some constant value in the iteration.
+ */
+void
+rb_objspace_each_objects(int (*callback)(void *vstart, void *vend,
+ size_t stride, void *d),
+ void *data)
{
size_t i;
- size_t n = 0;
RVALUE *membase = 0;
- RVALUE *p, *pend;
+ RVALUE *pstart, *pend;
+ rb_objspace_t *objspace = &rb_objspace;
volatile VALUE v;
- rb_garbage_collect();
i = 0;
while (i < heaps_used) {
while (0 < i && (uintptr_t)membase < (uintptr_t)heaps[i-1].membase)
@@ -2404,8 +2441,38 @@ os_obj_of(rb_objspace_t *objspace, VALUE of)
break;
membase = heaps[i].membase;
- p = heaps[i].slot; pend = p + heaps[i].limit;
- for (;p < pend; p++) {
+ pstart = heaps[i].slot;
+ pend = pstart + heaps[i].limit;
+
+ for (; pstart != pend; pstart++) {
+ if (pstart->as.basic.flags) {
+ v = (VALUE)pstart; /* acquire to save this object */
+ break;
+ }
+ }
+ if (pstart != pend) {
+ if ((*callback)(pstart, pend, sizeof(RVALUE), data)) {
+ return;
+ }
+ }
+ }
+
+ return;
+}
+
+struct os_each_struct {
+ size_t num;
+ VALUE of;
+};
+
+static int
+os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
+{
+ struct os_each_struct *oes = (struct os_each_struct *)data;
+ RVALUE *p = (RVALUE *)vstart, *pend = (RVALUE *)vend;
+ volatile VALUE v;
+
+ for (; p != pend; p++) {
if (p->as.basic.flags) {
switch (BUILTIN_TYPE(p)) {
case T_NONE:
@@ -2414,20 +2481,31 @@ os_obj_of(rb_objspace_t *objspace, VALUE of)
case T_ZOMBIE:
continue;
case T_CLASS:
- if (FL_TEST(p, FL_SINGLETON)) continue;
+ if (FL_TEST(p, FL_SINGLETON))
+ continue;
default:
if (!p->as.basic.klass) continue;
v = (VALUE)p;
- if (!of || rb_obj_is_kind_of(v, of)) {
+ if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
rb_yield(v);
- n++;
+ oes->num++;
}
}
}
}
+
+ return 0;
}
- return SIZET2NUM(n);
+static VALUE
+os_obj_of(VALUE of)
+{
+ struct os_each_struct oes;
+
+ oes.num = 0;
+ oes.of = of;
+ rb_objspace_each_objects(os_obj_of_i, &oes);
+ return SIZET2NUM(oes.num);
}
/*
@@ -2476,7 +2554,7 @@ os_each_obj(int argc, VALUE *argv, VALUE os)
rb_scan_args(argc, argv, "01", &of);
}
RETURN_ENUMERATOR(os, 1, &of);
- return os_obj_of(&rb_objspace, of);
+ return os_obj_of(of);
}
/*