mrb_value cfunc_rubyvm_task_wait(mrb_state *mrb, mrb_value self) { struct queue_task *task = DATA_PTR(self); if(task->status == queue_task_queued || task->status == queue_task_running) { pthread_mutex_lock(&task->sync_mutex); pthread_cond_wait(&task->sync_cond, &task->sync_mutex); pthread_mutex_unlock(&task->sync_mutex); } return task_arg_to_mrb_value(mrb, task->result); }
void* cfunc_rubyvm_open(void *args) { struct cfunc_rubyvm_data *data = args; mrb_state *mrb = mrb_open(); data->state = mrb; #ifdef DISABLE_GEMS init_cfunc_module(mrb); #endif int n = mrb_read_irep(mrb, data->mrb_data); mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb)); if (mrb->exc) { return NULL; } while(true) { pthread_mutex_lock(&data->queue_mutex); while(data->queue->length == 0) { pthread_cond_wait(&data->queue_cond, &data->queue_mutex); } struct queue_task *task = vector_dequeue(data->queue); task->status = queue_task_running; mrb_sym taskname = mrb_intern(mrb, task->name); int args_len = task->args_len; mrb_value *args = mrb_malloc(mrb, sizeof(struct task_arg) * task->args_len); int i; for(i=0; i<task->args_len; ++i) { args[i] = task_arg_to_mrb_value(data->state, task->args[i]); } pthread_mutex_unlock(&data->queue_mutex); mrb_value result = mrb_funcall_argv(mrb, mrb_top_self(data->state), taskname, args_len, args); task->result = mrb_value_to_task_arg(mrb, result); task->status = queue_task_finished; pthread_cond_signal(&task->sync_cond); mrb_free(mrb, args); free_queue_task(mrb, task); } return NULL; }
mrb_value task_arg_to_mrb_value(mrb_state *mrb, struct task_arg* arg) { mrb_value v; mrb_type(v) = arg->tt; switch (arg->tt) { case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: v.value.i = arg->value.i; break; case MRB_TT_FLOAT: v.value.f = arg->value.f; break; case MRB_TT_SYMBOL: v.value.sym = mrb_intern(mrb, arg->value.string.ptr); break; case MRB_TT_STRING: v = mrb_str_new(mrb, arg->value.string.ptr, arg->value.string.len); break; case MRB_TT_ARRAY: { v = mrb_ary_new_capa(mrb, arg->value.array.len); struct RArray *ary = mrb_ary_ptr(v); ary->len = arg->value.array.len; int i; for(i=0; i<arg->value.array.len; i++) { ary->ptr[i] = task_arg_to_mrb_value(mrb, arg->value.array.ptr[i]); } } break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot pass to other RubyVM"); break; } return v; }
mrb_value cfunc_rubyvm_task_result(mrb_state *mrb, mrb_value self) { struct queue_task *task = DATA_PTR(self); return task_arg_to_mrb_value(mrb, task->result); }