Created
November 17, 2013 15:38
-
-
Save crimsonwoods/7514698 to your computer and use it in GitHub Desktop.
This is experimental implementation to add thread support into mruby.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "mruby.h" | |
#include "mruby/thread.h" | |
#include "mruby/variable.h" | |
#include "mruby/gc.h" | |
#ifdef ENABLE_THREAD | |
typedef struct mrb_thread_impl { | |
mrb_state *mrb; | |
mrb_gem_thread_t thread; | |
} mrb_thread_impl; | |
extern void mrb_init_symtbl(mrb_state*); | |
extern void mrb_init_class(mrb_state*); | |
extern void mrb_init_object(mrb_state*); | |
extern void mrb_init_kernel(mrb_state*); | |
extern void mrb_init_comparable(mrb_state*); | |
extern void mrb_init_enumerable(mrb_state*); | |
extern void mrb_init_symbol(mrb_state*); | |
extern void mrb_init_exception(mrb_state*); | |
extern void mrb_init_proc(mrb_state*); | |
extern void mrb_init_string(mrb_state*); | |
extern void mrb_init_array(mrb_state*); | |
extern void mrb_init_hash(mrb_state*); | |
extern void mrb_init_heap(mrb_state*); | |
extern void mrb_init_numeric(mrb_state*); | |
extern void mrb_init_range(mrb_state*); | |
extern void mrb_init_gc(mrb_state*); | |
extern void mrb_init_math(mrb_state*); | |
extern void mrb_init_mrblib(mrb_state*); | |
extern void mrb_init_mrbgems(mrb_state*); | |
extern void mrb_final_core(mrb_state*); | |
extern void mrb_final_mrbgems(mrb_state*); | |
extern void mrb_free_heap(mrb_state *mrb); | |
#define DONE mrb_gc_arena_restore(mrb, 0); | |
static void | |
mrb_init_core_for_thread(mrb_state *mrb) | |
{ | |
mrb_init_class(mrb); DONE; | |
mrb_init_object(mrb); DONE; | |
mrb_init_kernel(mrb); DONE; | |
mrb_init_comparable(mrb); DONE; | |
mrb_init_enumerable(mrb); DONE; | |
mrb_init_symbol(mrb); DONE; | |
mrb_init_exception(mrb); DONE; | |
mrb_init_proc(mrb); DONE; | |
mrb_init_string(mrb); DONE; | |
mrb_init_array(mrb); DONE; | |
mrb_init_hash(mrb); DONE; | |
mrb_init_numeric(mrb); DONE; | |
mrb_init_range(mrb); DONE; | |
mrb_init_gc(mrb); DONE; | |
mrb_init_mrblib(mrb); DONE; | |
#ifndef DISABLE_GEMS | |
mrb_init_mrbgems(mrb); DONE; | |
#endif | |
} | |
void | |
mrb_final_core_for_thread(mrb_state *mrb) | |
{ | |
#ifndef DISABLE_GEMS | |
mrb_final_mrbgems(mrb); DONE; | |
#endif | |
} | |
static mrb_state* | |
mrb_vm_thread_open(mrb_state *mrb) | |
{ | |
static const mrb_state mrb_state_zero = { 0 }; | |
static const struct mrb_context mrb_context_zero = { 0 }; | |
mrb_state *thread_mrb; | |
#ifdef MRB_NAN_BOXING | |
mrb_assert(sizeof(void*) == 4); | |
#endif | |
thread_mrb = (mrb_state *)(*mrb->allocf)(NULL, NULL, sizeof(mrb_state), mrb->ud); | |
if (thread_mrb == NULL) return NULL; | |
*thread_mrb = mrb_state_zero; | |
thread_mrb->ud = mrb->ud; | |
thread_mrb->allocf = mrb->allocf; | |
thread_mrb->current_white_part = MRB_GC_WHITE_A; | |
mrb_init_heap(thread_mrb); | |
thread_mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); | |
*thread_mrb->c = mrb_context_zero; | |
thread_mrb->root_c = thread_mrb->c; | |
mrb_gem_vm_symtbl_rdlock(); | |
thread_mrb->name2sym = mrb->name2sym; | |
mrb_gem_vm_symtbl_rdunlock(); | |
mrb_init_core_for_thread(thread_mrb); | |
return thread_mrb; | |
} | |
struct alloca_header { | |
struct alloca_header *next; | |
char buf[]; | |
}; | |
static void | |
mrb_alloca_free(mrb_state *mrb) | |
{ | |
struct alloca_header *p; | |
struct alloca_header *tmp; | |
if (mrb == NULL) return; | |
p = mrb->mems; | |
while (p) { | |
tmp = p; | |
p = p->next; | |
mrb_free(mrb, tmp); | |
} | |
} | |
void | |
mrb_vm_thread_close(mrb_state *mrb) | |
{ | |
mrb_final_core_for_thread(mrb); | |
/* free */ | |
mrb_gc_free_gv(mrb); | |
mrb_free_context(mrb, mrb->root_c); | |
mrb_free_heap(mrb); | |
mrb_alloca_free(mrb); | |
mrb_free(mrb, mrb); | |
} | |
mrb_state * | |
mrb_vm_get_thread_state(mrb_thread thread) | |
{ | |
return ((mrb_thread_impl*)thread)->mrb; | |
} | |
mrb_bool | |
mrb_vm_attach_thread(mrb_state *mrb, mrb_thread *thread) | |
{ | |
mrb_thread_impl *entry = NULL; | |
if ((mrb == NULL) || (thread == NULL)) { | |
/* invalid parameter */ | |
return FALSE; | |
} | |
mrb_gem_vm_thread_rdlock(); | |
int i; | |
for (i = 0; i < MRB_VM_THREAD_MAX; ++i) { | |
if (mrb->thread_table[i] != NULL) { | |
continue; | |
} | |
mrb_gem_vm_thread_rdunlock(); | |
mrb_gem_vm_thread_wrlock(); | |
if (mrb->thread_table[i] != NULL) { | |
mrb_gem_vm_thread_wrunlock(); | |
mrb_gem_vm_thread_rdlock(); | |
continue; | |
} | |
entry = (mrb_thread_impl*)mrb_malloc(mrb, sizeof(mrb_thread_impl)); | |
mrb->thread_table[i] = (mrb_thread)entry; | |
mrb_gem_vm_thread_wrunlock(); | |
break; | |
} | |
if (entry == NULL) { | |
mrb_gem_vm_thread_rdunlock(); | |
return FALSE; | |
} | |
entry->mrb = mrb_vm_thread_open(mrb); | |
entry->thread = mrb_gem_thread_get_self(entry->mrb); | |
if (entry->mrb == NULL) { | |
mrb_free(mrb, entry); | |
return FALSE; | |
} | |
*thread = (mrb_thread)entry; | |
return TRUE; | |
} | |
void | |
mrb_vm_detach_thread(mrb_state *mrb, mrb_thread thread) | |
{ | |
if (thread == NULL) { | |
return; | |
} | |
mrb_thread_impl *entry = NULL; | |
mrb_gem_vm_thread_rdlock(); | |
int i; | |
for (i = 0; i < MRB_VM_THREAD_MAX; ++i) { | |
if (mrb->thread_table[i] != thread) { | |
continue; | |
} | |
mrb_gem_vm_thread_rdunlock(); | |
mrb_gem_vm_thread_wrlock(); | |
if (mrb->thread_table[i] == NULL) { | |
mrb_gem_vm_thread_wrunlock(); | |
mrb_gem_vm_thread_rdlock(); | |
continue; | |
} | |
entry = (mrb_thread_impl*)mrb->thread_table[i]; | |
mrb->thread_table[i] = NULL; | |
mrb_gem_vm_thread_wrunlock(); | |
break; | |
} | |
mrb_gem_thread_free(entry->mrb, entry->thread); | |
mrb_vm_thread_close(entry->mrb); | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MRUBY_THREAD_H | |
#define MRUBY_THREAD_H | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
struct mrb_state; | |
typedef struct mrb_state mrb_state; | |
typedef void *mrb_thread; | |
#ifdef ENABLE_THREAD | |
/* | |
* 'mrbgem' that supports thread must implement these functions. | |
*/ | |
extern mrb_bool mrb_gem_vm_rwlock_init(void); | |
extern void mrb_gem_vm_rwlock_destroy(void); | |
extern mrb_bool mrb_gem_vm_thread_rdlock(void); | |
extern void mrb_gem_vm_thread_rdunlock(void); | |
extern mrb_bool mrb_gem_vm_thread_wrlock(void); | |
extern void mrb_gem_vm_thread_wrunlock(void); | |
extern mrb_bool mrb_gem_vm_heap_rdlock(void); | |
extern void mrb_gem_vm_heap_rdunlock(void); | |
extern mrb_bool mrb_gem_vm_heap_wrlock(void); | |
extern void mrb_gem_vm_heap_wrunlock(void); | |
extern mrb_bool mrb_gem_vm_symtbl_rdlock(void); | |
extern void mrb_gem_vm_symtbl_rdunlock(void); | |
extern mrb_bool mrb_gem_vm_symtbl_wrlock(void); | |
extern void mrb_gem_vm_symtbl_wrunlock(void); | |
extern mrb_bool mrb_gem_vm_globals_rdlock(void); | |
extern void mrb_gem_vm_globals_rdunlock(void); | |
extern mrb_bool mrb_gem_vm_globals_wrlock(void); | |
extern void mrb_gem_vm_globals_wrunlock(void); | |
typedef void *mrb_gem_thread_t; | |
extern mrb_gem_thread_t mrb_gem_thread_get_self(mrb_state *mrb); | |
extern mrb_bool mrb_gem_thread_equals(mrb_state *mrb, mrb_gem_thread_t t1, mrb_gem_thread_t t2); | |
extern mrb_value mrb_gem_thread_join(mrb_state *mrb, mrb_gem_thread_t t); | |
extern void mrb_gem_thread_free(mrb_state *mrb, mrb_gem_thread_t t); | |
#endif | |
#ifdef ENABLE_THREAD | |
#define RWLOCK_INIT() mrb_gem_vm_rwlock_init() | |
#define RWLOCK_DESTROY() mrb_gem_vm_rwlock_destroy() | |
#define VM_HEAP_RDLOCK() mrb_gem_vm_heap_rdlock() | |
#define VM_HEAP_RDUNLOCK() mrb_gem_vm_heap_rdunlock() | |
#define VM_HEAP_WRLOCK() mrb_gem_vm_heap_wrlock() | |
#define VM_HEAP_WRUNLOCK() mrb_gem_vm_heap_wrunlock() | |
#define VM_SYMTBL_RDLOCK() mrb_gem_vm_symtbl_rdlock() | |
#define VM_SYMTBL_RDUNLOCK() mrb_gem_vm_symtbl_rdunlock() | |
#define VM_SYMTBL_WRLOCK() mrb_gem_vm_symtbl_wrlock() | |
#define VM_SYMTBL_WRUNLOCK() mrb_gem_vm_symtbl_wrunlock() | |
#define VM_GLOBALS_RDLOCK() mrb_gem_vm_globals_rdlock() | |
#define VM_GLOBALS_RDUNLOCK() mrb_gem_vm_globals_rdunlock() | |
#define VM_GLOBAL_WRLOCK() mrb_gem_vm_globals_wrlock() | |
#define VM_GLOBAL_WRUNLOCK() mrb_gem_vm_globals_wrunlock() | |
#else | |
#define VM_HEAP_RDLOCK() ((void)0) | |
#define VM_HEAP_RDUNLOCK() ((void)0) | |
#define VM_HEAP_WRLOCK() ((void)0) | |
#define VM_HEAP_WRUNLOCK() ((void)0) | |
#define VM_SYMTBL_RDLOCK() ((void)0) | |
#define VM_SYMTBL_RDUNLOCK() ((void)0) | |
#define VM_SYMTBL_WRLOCK() ((void)0) | |
#define VM_SYMTBL_WRUNLOCK() ((void)0) | |
#define VM_GLOBALS_RDLOCK() ((void)0) | |
#define VM_GLOBALS_RDUNLOCK() ((void)0) | |
#define VM_GLOBAL_WRLOCK() ((void)0) | |
#define VM_GLOBAL_WRUNLOCK() ((void)0) | |
#endif | |
#ifdef ENABLE_THREAD | |
#define MRB_VM_THREAD_MAX 32 | |
#define MRB_VM_THREAD_TABLE mrb_thread thread_table[MRB_VM_THREAD_MAX] | |
#else | |
#define MRB_VM_THREAD_TABLE | |
#endif | |
#ifdef ENABLE_THREAD | |
extern mrb_state *mrb_vm_get_thread_state(mrb_thread thread); | |
extern mrb_bool mrb_vm_attach_thread(mrb_state *mrb, mrb_thread *thread); | |
extern void mrb_vm_detach_thread(mrb_state *mrb, mrb_thread thread); | |
#endif | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment