static mrb_value mrb_thread_init(mrb_state* mrb, mrb_value self) { mrb_value proc = mrb_nil_value(); mrb_int argc; mrb_value* argv; mrb_get_args(mrb, "&*", &proc, &argv, &argc); if (!mrb_nil_p(proc) && MRB_PROC_CFUNC_P(mrb_proc_ptr(proc))) { mrb_raise(mrb, E_RUNTIME_ERROR, "forking C defined block"); } if (!mrb_nil_p(proc)) { int i, l; mrb_thread_context* context = (mrb_thread_context*) malloc(sizeof(mrb_thread_context)); context->mrb_caller = mrb; context->mrb = mrb_open_allocf(mrb->allocf, mrb->allocf_ud); migrate_all_symbols(mrb, context->mrb); context->proc = mrb_proc_new(mrb, mrb_proc_ptr(proc)->body.irep); context->proc->target_class = context->mrb->object_class; context->argc = argc; context->argv = calloc(sizeof (mrb_value), context->argc); context->result = mrb_nil_value(); context->alive = TRUE; for (i = 0; i < context->argc; i++) { context->argv[i] = migrate_simple_value(mrb, argv[i], context->mrb); } { mrb_value gv = mrb_funcall(mrb, self, "global_variables", 0, NULL); l = RARRAY_LEN(gv); for (i = 0; i < l; i++) { mrb_int len; int ai = mrb_gc_arena_save(mrb); mrb_value k = mrb_ary_entry(gv, i); mrb_value o = mrb_gv_get(mrb, mrb_symbol(k)); if (is_safe_migratable_simple_value(mrb, o, context->mrb)) { const char *p = mrb_sym2name_len(mrb, mrb_symbol(k), &len); mrb_gv_set(context->mrb, mrb_intern_static(context->mrb, p, len), migrate_simple_value(mrb, o, context->mrb)); } mrb_gc_arena_restore(mrb, ai); } } mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "context"), mrb_obj_value( Data_Wrap_Struct(mrb, mrb->object_class, &mrb_thread_context_type, (void*) context))); pthread_create(&context->thread, NULL, &mrb_thread_func, (void*) context); } return self; }
static mrb_value mrb_thread_init(mrb_state* mrb, mrb_value self) { mrb_value proc = mrb_nil_value(); int argc; mrb_value* argv; mrb_get_args(mrb, "&*", &proc, &argv, &argc); if (!mrb_nil_p(proc)) { int i; mrb_thread_context* context = (mrb_thread_context*) malloc(sizeof(mrb_thread_context)); context->mrb_caller = mrb; context->mrb = mrb_open(); context->proc = mrb_proc_ptr(proc); context->argc = argc; context->argv = argv; context->argv = calloc(sizeof (mrb_value), context->argc); context->result = mrb_nil_value(); for (i = 0; i < context->argc; i++) { context->argv[i] = migrate_simple_value(mrb, argv[i], context->mrb); } mrb_iv_set(mrb, self, mrb_intern_cstr(mrb, "context"), mrb_obj_value( Data_Wrap_Struct(mrb, mrb->object_class, &mrb_thread_context_type, (void*) context))); pthread_create(&context->thread, NULL, &mrb_thread_func, (void*) context); } return self; }
static mrb_value mrb_thread_join(mrb_state* mrb, mrb_value self) { mrb_value value_context = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "context")); mrb_thread_context* context = NULL; Data_Get_Struct(mrb, value_context, &mrb_thread_context_type, context); pthread_join(context->thread, NULL); context->result = migrate_simple_value(mrb, context->result, mrb); mrb_close(context->mrb); context->mrb = NULL; return context->result; }
static mrb_value mrb_queue_unshift(mrb_state* mrb, mrb_value self) { mrb_value arg; mrb_queue_context* context = DATA_PTR(self); mrb_queue_lock(mrb, self); mrb_get_args(mrb, "o", &arg); mrb_ary_unshift(context->mrb, context->queue, migrate_simple_value(mrb, arg, context->mrb)); mrb_queue_unlock(mrb, self); if (pthread_mutex_unlock(&context->queue_lock) != 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "cannot unlock"); } return mrb_nil_value(); }
static void migrate_simple_iv(mrb_state *mrb, mrb_value v, mrb_state *mrb2, mrb_value v2) { mrb_value ivars = mrb_obj_instance_variables(mrb, v); struct RArray *a = mrb_ary_ptr(ivars); mrb_value iv; mrb_int i; for (i=0; i<a->len; i++) { mrb_sym sym = mrb_symbol(a->ptr[i]); mrb_sym sym2 = migrate_sym(mrb, sym, mrb2); iv = mrb_iv_get(mrb, v, sym); mrb_iv_set(mrb2, v2, sym2, migrate_simple_value(mrb, iv, mrb2)); } }
static mrb_value mrb_queue_shift(mrb_state* mrb, mrb_value self) { mrb_value ret; mrb_queue_context* context = DATA_PTR(self); int len; mrb_queue_lock(mrb, self); len = RARRAY_LEN(context->queue); mrb_queue_unlock(mrb, self); if (len == 0) { if (pthread_mutex_lock(&context->queue_lock) != 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "cannot lock"); } } mrb_queue_lock(mrb, self); ret = migrate_simple_value(context->mrb, mrb_ary_shift(context->mrb, context->queue), mrb); mrb_queue_unlock(mrb, self); return ret; }
// based on https://gist.github.com/3066997 static mrb_value migrate_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { mrb_value nv; switch (mrb_type(v)) { case MRB_TT_OBJECT: case MRB_TT_EXCEPTION: { struct RObject *o = mrb_obj_ptr(v); mrb_value path = mrb_class_path(mrb, o->c); struct RClass *c; if (mrb_nil_p(path)) { mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate class"); } c = mrb_class_get(mrb2, RSTRING_PTR(path)); nv = mrb_obj_value(mrb_obj_alloc(mrb2, mrb_type(v), c)); } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: nv = v; break; case MRB_TT_SYMBOL: nv = mrb_symbol_value(migrate_sym(mrb, mrb_symbol(v), mrb2)); break; case MRB_TT_FLOAT: nv = mrb_float_value(mrb2, mrb_float(v)); break; case MRB_TT_STRING: nv = mrb_str_new(mrb2, RSTRING_PTR(v), RSTRING_LEN(v)); break; case MRB_TT_RANGE: { struct RRange *r = mrb_range_ptr(v); nv = mrb_range_new(mrb2, migrate_simple_value(mrb, r->edges->beg, mrb2), migrate_simple_value(mrb, r->edges->end, mrb2), r->excl); } break; case MRB_TT_ARRAY: { struct RArray *a0, *a1; int i; a0 = mrb_ary_ptr(v); nv = mrb_ary_new_capa(mrb2, a0->len); a1 = mrb_ary_ptr(nv); for (i=0; i<a0->len; i++) { int ai = mrb_gc_arena_save(mrb2); a1->ptr[i] = migrate_simple_value(mrb, a0->ptr[i], mrb2); a1->len++; mrb_gc_arena_restore(mrb2, ai); } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; nv = mrb_hash_new(mrb2); ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { int ai = mrb_gc_arena_save(mrb2); mrb_value k = migrate_simple_value(mrb, mrb_ary_entry(ka, i), mrb2); mrb_value o = migrate_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2); mrb_hash_set(mrb2, nv, k, o); mrb_gc_arena_restore(mrb2, ai); } } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_DATA: if (!is_safe_migratable_datatype(DATA_TYPE(v))) mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); nv = v; DATA_PTR(nv) = DATA_PTR(v); DATA_TYPE(nv) = DATA_TYPE(v); migrate_simple_iv(mrb, v, mrb2, nv); break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); break; } return nv; }
// based on https://gist.github.com/3066997 static mrb_value migrate_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { mrb_value nv = mrb_nil_value(); nv.tt = v.tt; switch (mrb_type(v)) { case MRB_TT_OBJECT: nv.value.p = v.value.p; break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: nv.value.i = v.value.i; break; case MRB_TT_SYMBOL: nv = mrb_symbol_value(mrb_intern_str(mrb2, v)); break; case MRB_TT_FLOAT: nv.value.f = v.value.f; break; case MRB_TT_STRING: nv = mrb_str_new(mrb2, RSTRING_PTR(v), RSTRING_LEN(v)); break; case MRB_TT_ARRAY: { struct RArray *a0, *a1; int i; a0 = mrb_ary_ptr(v); nv = mrb_ary_new_capa(mrb2, a0->len); a1 = mrb_ary_ptr(nv); for (i=0; i<a0->len; i++) { int ai = mrb_gc_arena_save(mrb2); a1->ptr[i] = migrate_simple_value(mrb, a0->ptr[i], mrb2); a1->len++; mrb_gc_arena_restore(mrb2, ai); } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; nv = mrb_hash_new(mrb2); ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { int ai = mrb_gc_arena_save(mrb2); mrb_value k = migrate_simple_value(mrb, mrb_ary_entry(ka, i), mrb2); mrb_value o = migrate_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2); mrb_hash_set(mrb2, nv, k, o); mrb_gc_arena_restore(mrb2, ai); } } break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); break; } return nv; }