ruby-changes:12041
From: ko1 <ko1@a...>
Date: Wed, 17 Jun 2009 06:07:45 +0900 (JST)
Subject: [ruby-changes:12041] Ruby:r23708 (trunk): * gc.c (rb_objspace_each_objects): New C API, added.
ko1 2009-06-17 06:07:26 +0900 (Wed, 17 Jun 2009) New Revision: 23708 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23708 Log: * gc.c (rb_objspace_each_objects): New C API, added. Modified files: trunk/ChangeLog trunk/gc.c Index: ChangeLog =================================================================== --- ChangeLog (revision 23707) +++ ChangeLog (revision 23708) @@ -1,3 +1,7 @@ +Wed Jun 17 06:05:03 2009 Koichi Sasada <ko1@a...> + + * gc.c (rb_objspace_each_objects): New C API, added. + Wed Jun 17 00:31:30 2009 Yukihiro Matsumoto <matz@r...> * test/ruby/test_argf.rb (TestArgf#test_skip): updated test Index: gc.c =================================================================== --- gc.c (revision 23707) +++ gc.c (revision 23708) @@ -2384,16 +2384,53 @@ 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 @@ 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 @@ 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 @@ rb_scan_args(argc, argv, "01", &of); } RETURN_ENUMERATOR(os, 1, &of); - return os_obj_of(&rb_objspace, of); + return os_obj_of(of); } /* -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/