static VALUE thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv) { if (!rb_block_given_p()) { rb_raise(rb_eThreadError, "must be called with a block"); } rb_vm_block_t *b = rb_vm_current_block(); assert(b != NULL); rb_vm_thread_t *t = GetThreadPtr(thread); rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm()); // The thread's group is always the parent's one. rb_thgroup_add(GetThreadPtr(rb_vm_current_thread())->group, thread); // Retain the Thread object to avoid a potential GC, the corresponding // release is done in rb_vm_thread_run(). rb_objc_retain((void *)thread); if (pthread_create(&t->thread, NULL, (void *(*)(void *))rb_vm_thread_run, (void *)thread) != 0) { rb_sys_fail("pthread_create() failed"); } return thread; }
static inline VALUE rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, int scope, bool pass_current_block) { SEL sel; if (mid == ID_ALLOCATOR) { sel = selAlloc; } else { const char *midstr = rb_id2name(mid); if (argc > 0 && midstr[strlen(midstr) - 1] != ':') { char buf[100]; snprintf(buf, sizeof buf, "%s:", midstr); sel = sel_registerName(buf); } else { sel = sel_registerName(midstr); } } void *cache = rb_vm_get_call_cache(sel); rb_vm_block_t *block = pass_current_block ? rb_vm_current_block() : NULL; return rb_vm_call_with_cache2(cache, block, recv, CLASS_OF(recv), sel, argc, argv); }
VALUE rb_method_call(VALUE method, SEL sel, int argc, VALUE *argv) { rb_vm_method_t *data; Data_Get_Struct(method, rb_vm_method_t, data); if (data->recv == Qundef) { rb_raise(rb_eTypeError, "can't call unbound method; bind first"); } int safe = -1; if (OBJ_TAINTED(method)) { safe = rb_safe_level(); if (rb_safe_level() < 4) { rb_set_safe_level_force(4); } } VALUE result = rb_vm_method_call(data, rb_vm_current_block(), argc, argv); if (safe >= 0) { rb_set_safe_level_force(safe); } return result; }
static inline VALUE rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, int scope, bool pass_current_block) { SEL sel; if (mid == ID_ALLOCATOR) { sel = selAlloc; } else { sel = rb_vm_id_to_sel(mid, argc); } rb_vm_block_t *block = pass_current_block ? rb_vm_current_block() : NULL; return rb_vm_call2(block, recv, CLASS_OF(recv), sel, argc, argv); }
static VALUE thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv) { if (!rb_block_given_p()) { rb_raise(rb_eThreadError, "must be called with a block"); } rb_vm_block_t *b = rb_vm_current_block(); assert(b != NULL); rb_vm_thread_t *t = GetThreadPtr(thread); if (t->thread != 0) { rb_raise(rb_eThreadError, "already initialized thread"); } rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm()); // The thread's group is always the parent's one. // The parent group might be nil (ex. if created from GCD). VALUE group = GetThreadPtr(rb_vm_current_thread())->group; if (group != Qnil) { thgroup_add_m(group, thread, false); } // Retain the Thread object to avoid a potential GC, the corresponding // release is done in rb_vm_thread_run(). GC_RETAIN(thread); // 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); // Register the thread to the core. We are doing this before actually // running it because the current thread might perform a method poking at // the current registered threads (such as Kernel#sleep) right after that. rb_vm_register_thread(thread); // 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; }
static rb_vm_block_t * get_prepared_block() { rb_vm_block_t *block = rb_vm_current_block(); if (block == NULL) { rb_raise(rb_eArgError, "block not given"); } #if GCD_BLOCKS_COPY_DVARS block = rb_vm_dup_block(block); for (int i = 0; i < block->dvars_size; i++) { VALUE *slot = block->dvars[i]; VALUE *new_slot = xmalloc(sizeof(VALUE)); GC_WB(new_slot, *slot); GC_WB(&block->dvars[i], new_slot); } #else rb_vm_block_make_detachable_proc(block); #endif GC_RETAIN(block); return block; }