Revision: 2930 http://trac.macosforge.org/projects/ruby/changeset/2930 Author: lsansonetti@apple.com Date: 2009-10-30 19:34:41 -0700 (Fri, 30 Oct 2009) Log Message: ----------- implemented VM cleanup + make sure Threads do not leak resources anymore Modified Paths: -------------- MacRuby/trunk/include/ruby/intern.h MacRuby/trunk/thread.c MacRuby/trunk/vm.cpp Modified: MacRuby/trunk/include/ruby/intern.h =================================================================== --- MacRuby/trunk/include/ruby/intern.h 2009-10-30 19:05:50 UTC (rev 2929) +++ MacRuby/trunk/include/ruby/intern.h 2009-10-31 02:34:41 UTC (rev 2930) @@ -612,6 +612,7 @@ VALUE rb_struct_define_without_accessor(const char *, VALUE, rb_alloc_func_t, ...); /* thread.c */ VALUE rb_thgroup_add(VALUE group, VALUE thread); +void rb_thread_remove_from_group(VALUE thread); typedef void rb_unblock_function_t(void *); typedef VALUE rb_blocking_function_t(void *); VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1, Modified: MacRuby/trunk/thread.c =================================================================== --- MacRuby/trunk/thread.c 2009-10-30 19:05:50 UTC (rev 2929) +++ MacRuby/trunk/thread.c 2009-10-31 02:34:41 UTC (rev 2930) @@ -11,15 +11,25 @@ #include "ruby/node.h" #include "vm.h" +VALUE rb_cThread; +VALUE rb_cThGroup; +VALUE rb_cMutex; + typedef struct rb_vm_mutex { pthread_mutex_t mutex; rb_vm_thread_t *thread; } rb_vm_mutex_t; -VALUE rb_cThread; -VALUE rb_cThGroup; -VALUE rb_cMutex; +#define GetMutexPtr(obj) ((rb_vm_mutex_t *)DATA_PTR(obj)) +typedef struct { + bool enclosed; + VALUE threads; + VALUE mutex; +} rb_thread_group_t; + +#define GetThreadGroupPtr(obj) ((rb_thread_group_t *)DATA_PTR(obj)) + #if 0 static VALUE thread_s_new(int argc, VALUE *argv, VALUE klass) @@ -53,12 +63,21 @@ // Retain the Thread object to avoid a potential GC, the corresponding // release is done in rb_vm_thread_run(). - rb_objc_retain((void *)thread); + GC_RETAIN(thread); - if (pthread_create(&t->thread, NULL, (void *(*)(void *))rb_vm_thread_run, + // Prepare attributes for the thread. + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + // Launch it. + if (pthread_create(&t->thread, &attr, (void *(*)(void *))rb_vm_thread_run, (void *)thread) != 0) { rb_sys_fail("pthread_create() failed"); } + pthread_attr_destroy(&attr); return thread; } @@ -138,7 +157,14 @@ if (t->status != THREAD_DEAD) { if (timeout == Qnil) { // No timeout given: block until the thread finishes. - pthread_assert(pthread_join(t->thread, NULL)); + //pthread_assert(pthread_join(t->thread, NULL)); + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 10000000; + while (t->status != THREAD_DEAD) { + nanosleep(&ts, NULL); + pthread_yield_np(); + } } else { // Timeout given: sleep then check if the thread is dead. @@ -1083,13 +1109,9 @@ * were created. */ -typedef struct { - bool enclosed; - VALUE threads; -} rb_thread_group_t; +static VALUE mutex_s_alloc(VALUE self, SEL sel); +static VALUE mutex_initialize(VALUE self, SEL sel); -#define GetThreadGroupPtr(obj) ((rb_thread_group_t *)DATA_PTR(obj)) - static VALUE thgroup_s_alloc(VALUE self, SEL sel) { @@ -1097,6 +1119,11 @@ sizeof(rb_thread_group_t)); t->enclosed = false; GC_WB(&t->threads, rb_ary_new()); + + VALUE mutex = mutex_s_alloc(rb_cMutex, 0); + mutex_initialize(mutex, 0); + GC_WB(&t->mutex, mutex); + return Data_Wrap_Struct(rb_cThGroup, NULL, NULL, t); } @@ -1181,6 +1208,18 @@ * tg group now #<Thread:0x401b3c90> */ +static inline void +thgroup_lock(rb_thread_group_t *tg) +{ + pthread_assert(pthread_mutex_lock(&GetMutexPtr(tg->mutex)->mutex)); +} + +static inline void +thgroup_unlock(rb_thread_group_t *tg) +{ + pthread_assert(pthread_mutex_unlock(&GetMutexPtr(tg->mutex)->mutex)); +} + static VALUE thgroup_add(VALUE group, SEL sel, VALUE thread) { @@ -1197,10 +1236,14 @@ rb_raise(rb_eThreadError, "can't move from the enclosed thread group"); } + thgroup_lock(old_tg); rb_ary_delete(old_tg->threads, thread); + thgroup_unlock(old_tg); } + thgroup_lock(new_tg); rb_ary_push(new_tg->threads, thread); + thgroup_unlock(new_tg); GC_WB(&t->group, group); return group; @@ -1212,6 +1255,21 @@ return thgroup_add(group, 0, thread); } +void +rb_thread_remove_from_group(VALUE thread) +{ + rb_vm_thread_t *t = GetThreadPtr(thread); + rb_thread_group_t *tg = GetThreadGroupPtr(t->group); + thgroup_lock(tg); + if (rb_ary_delete(tg->threads, thread) != thread) { + printf("trying to remove a thread (%p) from a group that doesn't "\ + "contain it\n", (void *)thread); + abort(); + } + thgroup_unlock(tg); + t->group = Qnil; +} + /* * Document-class: Mutex * @@ -1251,8 +1309,6 @@ return Data_Wrap_Struct(rb_cMutex, NULL, NULL, t); } -#define GetMutexPtr(obj) ((rb_vm_mutex_t *)DATA_PTR(obj)) - static VALUE mutex_initialize(VALUE self, SEL sel) { Modified: MacRuby/trunk/vm.cpp =================================================================== --- MacRuby/trunk/vm.cpp 2009-10-30 19:05:50 UTC (rev 2929) +++ MacRuby/trunk/vm.cpp 2009-10-31 02:34:41 UTC (rev 2930) @@ -258,7 +258,6 @@ RoxorCore::~RoxorCore(void) { - call_all_finalizers(); // TODO } @@ -332,7 +331,17 @@ RoxorVM::~RoxorVM(void) { - // TODO + for (std::map<void *, rb_vm_block_t *>::iterator i = blocks.begin(); + i != blocks.end(); + ++i) { + GC_RELEASE(i->second); + } + blocks.clear(); + + GC_RELEASE(backref); + GC_RELEASE(broken_with); + GC_RELEASE(last_status); + GC_RELEASE(errinfo); } static void @@ -3630,7 +3639,7 @@ s->throw_value = Qnil; s->nested = 1; catch_jmp_bufs[tag] = s; - rb_objc_retain((void *)tag); + GC_RETAIN(tag); } else { s = iter->second; @@ -3654,7 +3663,7 @@ s = iter->second; free(s); catch_jmp_bufs.erase(iter); - rb_objc_release((void *)tag); + GC_RELEASE(tag); } return retval; @@ -3888,7 +3897,7 @@ GET_CORE()->register_thread(thread); // Release the thread now. - rb_objc_release((void *)thread); + GC_RELEASE(thread); rb_vm_thread_t *t = GetThreadPtr(thread); @@ -3921,6 +3930,7 @@ pthread_cleanup_pop(0); + rb_thread_remove_from_group(thread); GET_CORE()->unregister_thread(thread); rb_objc_gc_unregister_thread(); @@ -4447,7 +4457,11 @@ printf("functions all=%ld compiled=%ld\n", RoxorCompiler::module->size(), GET_CORE()->get_functions_compiled()); #endif - - delete RoxorCore::shared; - RoxorCore::shared = NULL; + + + // XXX: deleting the core is not safe at this point because there might be + // threads still running and trying to unregister. +// delete RoxorCore::shared; +// RoxorCore::shared = NULL; + GET_CORE()->call_all_finalizers(); }