Skip to content

Instantly share code, notes, and snippets.

@crimsonwoods
Created November 17, 2013 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crimsonwoods/7514698 to your computer and use it in GitHub Desktop.
Save crimsonwoods/7514698 to your computer and use it in GitHub Desktop.
This is experimental implementation to add thread support into mruby.
#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
#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