yarv-diff:111
From: ko1 atdot.net
Date: 30 Sep 2005 06:08:46 -0000
Subject: [yarv-diff:111] r267 - trunk
Author: ko1
Date: 2005-09-30 15:08:45 +0900 (Fri, 30 Sep 2005)
New Revision: 267
Added:
trunk/thread.c
trunk/thread_pthread.h
Modified:
trunk/ChangeLog
trunk/common.mk
trunk/eval.c
trunk/eval_intern.h
trunk/eval_thread.c
trunk/gc.c
trunk/insns.def
trunk/test.rb
trunk/yarv.h
trunk/yarvcore.c
trunk/yarvcore.h
Log:
* thread.c, common.mk : add thread.c
* thread.c, gc.c, eval_thread.c, yarvcore.c, yarvcore.h :
support native thread (on pthread)
* insns.def : add YARV_CHECK_INTS() check
* yarv.h : add GET_VM() macro
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/ChangeLog 2005-09-30 06:08:45 UTC (rev 267)
@@ -4,6 +4,18 @@
# from Mon, 03 May 2004 01:24:19 +0900
#
+2005-09-30(Fri) 14:59:29 +0900 Koichi Sasada <ko1 atdot.net>
+
+ * thread.c, common.mk : add thread.c
+
+ * thread.c, gc.c, eval_thread.c, yarvcore.c, yarvcore.h :
+ support native thread (on pthread)
+
+ * insns.def : add YARV_CHECK_INTS() check
+
+ * yarv.h : add GET_VM() macro
+
+
2005-09-29(Thu) 22:43:08 +0900 Koichi Sasada <ko1 atdot.net>
* eval_intern.h, eval_thread.c : move thread_status to eval_intern.h
Modified: trunk/common.mk
===================================================================
--- trunk/common.mk 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/common.mk 2005-09-30 06:08:45 UTC (rev 267)
@@ -67,6 +67,7 @@
vm_dump.$(OBJEXT) \
yarvcore.$(OBJEXT) \
yarvsubst.$(OBJEXT) \
+ thread.$(OBJEXT) \
$(MISSING)
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
@@ -273,6 +274,12 @@
{$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
+thread.$(OBJEXT): {$(VPATH)}thread.c {$(VPATH)}eval_intern.h \
+ {$(VPATH)}ruby.h config.h \
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
+ {$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \
+ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
+
file.$(OBJEXT): {$(VPATH)}file.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.h \
@@ -373,6 +380,7 @@
debug.$(OBJEXT): {$(VPATH)}debug.h
yarvsubst.$(OBJEXT): {$(VPATH)}yarv.h
+
BASERUBY = ruby
INSNS2VMOPT = $(CPPFLAGS) --srcdir=$(srcdir)
Modified: trunk/eval.c
===================================================================
--- trunk/eval.c 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/eval.c 2005-09-30 06:08:45 UTC (rev 267)
@@ -94,6 +94,9 @@
#endif
char **rb_origenviron;
+jmp_buf function_call_may_return_twice_jmp_buf;
+int function_call_may_return_twice_false = 0;
+
void rb_call_inits _((void));
void Init_stack _((VALUE*));
void Init_heap _((void));
Modified: trunk/eval_intern.h
===================================================================
--- trunk/eval_intern.h 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/eval_intern.h 2005-09-30 06:08:45 UTC (rev 267)
@@ -147,8 +147,8 @@
"%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \
"%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); })
#else
-static jmp_buf function_call_may_return_twice_jmp_buf;
-int function_call_may_return_twice_false = 0;
+extern jmp_buf function_call_may_return_twice_jmp_buf;
+extern int function_call_may_return_twice_false;
#define FUNCTION_CALL_MAY_RETURN_TWICE \
(function_call_may_return_twice_false ? \
setjmp(function_call_may_return_twice_jmp_buf) : \
@@ -260,13 +260,6 @@
#define SCOPE_SET(f) (scope_vmode=(f))
#define SCOPE_TEST(f) (scope_vmode&(f))
-enum thread_status {
- THREAD_TO_KILL,
- THREAD_RUNNABLE,
- THREAD_STOPPED,
- THREAD_KILLED,
-};
-
struct ruby_env {
struct ruby_env *prev;
struct FRAME *frame;
Modified: trunk/eval_thread.c
===================================================================
--- trunk/eval_thread.c 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/eval_thread.c 2005-09-30 06:08:45 UTC (rev 267)
@@ -103,13 +103,6 @@
/* +infty, for this purpose */
#define DELAY_INFTY 1E30
-#if !defined HAVE_PAUSE
-# if defined _WIN32 && !defined __CYGWIN__
-# define pause() Sleep(INFINITE)
-# else
-# define pause() sleep(0x7fffffff)
-# endif
-#endif
#ifdef NFDBITS
void
@@ -266,7 +259,7 @@
int safe;
- enum thread_status status;
+ enum yarv_thread_status status;
int wait_for;
int fd;
rb_fdset_t readfds;
@@ -306,7 +299,7 @@
int safe;
- enum thread_status status;
+ enum yarv_thread_status status;
int wait_for;
int fd;
rb_fdset_t readfds;
@@ -378,7 +371,7 @@
static const char *
thread_status_name(status)
- enum thread_status status;
+ enum yarv_thread_status status;
{
switch (status) {
case THREAD_RUNNABLE:
@@ -765,62 +758,6 @@
return Qfalse;
}
-void
-rb_thread_wait_for(time)
- struct timeval time;
-{
- double date;
-
- if (rb_thread_critical ||
- curr_thread == curr_thread->next ||
- curr_thread->status == THREAD_TO_KILL) {
- int n;
- int thr_critical = rb_thread_critical;
-#ifndef linux
- double d, limit;
- limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6;
-#endif
- for (;;) {
- rb_thread_critical = Qtrue;
- TRAP_BEG;
- n = select(0, 0, 0, 0, &time);
- rb_thread_critical = thr_critical;
- TRAP_END;
- if (n == 0) return;
- if (n < 0) {
- switch (errno) {
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- return;
- default:
- rb_sys_fail("sleep");
- }
- }
-#ifndef linux
- d = limit - timeofday();
-
- time.tv_sec = (int)d;
- time.tv_usec = (int)((d - (int)d)*1e6);
- if (time.tv_usec < 0) {
- time.tv_usec += (long)1e6;
- time.tv_sec -= 1;
- }
- if (time.tv_sec < 0) return;
-#endif
- }
- }
-
- date = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6;
- curr_thread->status = THREAD_STOPPED;
- curr_thread->delay = date;
- curr_thread->wait_for = WAIT_TIME;
- rb_thread_schedule();
-}
-
-void rb_thread_sleep_forever _((void));
-
int
rb_thread_alone()
{
@@ -920,7 +857,7 @@
VALUE
rb_thread_current()
{
- return 0;
+ return GET_THREAD()->self;
}
@@ -1163,7 +1100,7 @@
VALUE
rb_thread_stop()
{
- enum thread_status last_status = THREAD_RUNNABLE;
+ enum yarv_thread_status last_status = THREAD_RUNNABLE;
rb_thread_critical = 0;
if (curr_thread == curr_thread->next) {
@@ -1204,27 +1141,7 @@
rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
}
-void
-rb_thread_sleep_forever()
-{
- int thr_critical = rb_thread_critical;
- if (curr_thread == curr_thread->next ||
- curr_thread->status == THREAD_TO_KILL) {
- rb_thread_critical = Qtrue;
- TRAP_BEG;
- pause();
- rb_thread_critical = thr_critical;
- TRAP_END;
- return;
- }
- curr_thread->delay = DELAY_INFTY;
- curr_thread->wait_for = WAIT_TIME;
- curr_thread->status = THREAD_STOPPED;
- rb_thread_schedule();
-}
-
-
/*
* call-seq:
* thr.priority => integer
@@ -1489,34 +1406,6 @@
/* cause EINTR */
}
-static pthread_t time_thread;
-extern rb_nativethread_t ruby_thid;
-
-static void*
-thread_timer(void *dummy)
-{
- for (;;) {
-#ifdef HAVE_NANOSLEEP
- struct timespec req, rem;
-
- req.tv_sec = 0;
- req.tv_nsec = 10000000;
- nanosleep(&req, &rem);
-#else
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
- select(0, NULL, NULL, NULL, &tv);
-#endif
- if (!rb_thread_critical) {
- rb_thread_pending = 1;
- if (rb_trap_immediate) {
- pthread_kill(ruby_thid, SIGVTALRM);
- }
- }
- }
-}
-
void
rb_thread_start_timer()
{
@@ -1567,7 +1456,7 @@
int rb_thread_tick = THREAD_TICK;
#endif
-NORETURN(static void rb_thread_terminated _((rb_thread_t, int, enum thread_status)));
+NORETURN(static void rb_thread_terminated _((rb_thread_t, int, enum yarv_thread_status)));
static VALUE rb_thread_yield _((VALUE, rb_thread_t));
static void
@@ -1615,7 +1504,7 @@
rb_thread_terminated(th, state, status)
rb_thread_t th;
int state;
- enum thread_status status;
+ enum yarv_thread_status status;
{
if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
th->flags |= THREAD_RAISED;
@@ -2094,159 +1983,7 @@
return Qnil; /* not reached */
}
-VALUE
-rb_thread_local_aref(thread, id)
- VALUE thread;
- ID id;
-{
- rb_thread_t th;
- VALUE val;
-
- th = rb_thread_check(thread);
- if (ruby_safe_level >= 4 && th != curr_thread) {
- rb_raise(rb_eSecurityError, "Insecure: thread locals");
- }
- if (!th->locals) return Qnil;
- if (st_lookup(th->locals, id, &val)) {
- return val;
- }
- return Qnil;
-}
-
-
/*
- * call-seq:
- * thr[sym] => obj or nil
- *
- * Attribute Reference---Returns the value of a thread-local variable, using
- * either a symbol or a string name. If the specified variable does not exist,
- * returns <code>nil</code>.
- *
- * a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
- * b = Thread.new { Thread.current[:name] = "B"; Thread.stop }
- * c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
- * Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
- *
- * <em>produces:</em>
- *
- * #<Thread:0x401b3b3c sleep>: C
- * #<Thread:0x401b3bc8 sleep>: B
- * #<Thread:0x401b3c68 sleep>: A
- * #<Thread:0x401bdf4c run>:
- */
-
-static VALUE
-rb_thread_aref(thread, id)
- VALUE thread, id;
-{
- return rb_thread_local_aref(thread, rb_to_id(id));
-}
-
-VALUE
-rb_thread_local_aset(thread, id, val)
- VALUE thread;
- ID id;
- VALUE val;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (ruby_safe_level >= 4 && th != curr_thread) {
- rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
- }
- if (OBJ_FROZEN(thread)) rb_error_frozen("thread locals");
-
- if (!th->locals) {
- th->locals = st_init_numtable();
- }
- if (NIL_P(val)) {
- st_delete(th->locals, (st_data_t*)&id, 0);
- return Qnil;
- }
- st_insert(th->locals, id, val);
-
- return val;
-}
-
-
-/*
- * call-seq:
- * thr[sym] = obj => obj
- *
- * Attribute Assignment---Sets or creates the value of a thread-local variable,
- * using either a symbol or a string. See also <code>Thread#[]</code>.
- */
-
-static VALUE
-rb_thread_aset(thread, id, val)
- VALUE thread, id, val;
-{
- return rb_thread_local_aset(thread, rb_to_id(id), val);
-}
-
-
-/*
- * call-seq:
- * thr.key?(sym) => true or false
- *
- * Returns <code>true</code> if the given string (or symbol) exists as a
- * thread-local variable.
- *
- * me = Thread.current
- * me[:oliver] = "a"
- * me.key?(:oliver) #=> true
- * me.key?(:stanley) #=> false
- */
-
-static VALUE
-rb_thread_key_p(thread, id)
- VALUE thread, id;
-{
- rb_thread_t th = rb_thread_check(thread);
-
- if (!th->locals) return Qfalse;
- if (st_lookup(th->locals, rb_to_id(id), 0))
- return Qtrue;
- return Qfalse;
-}
-
-static int
-thread_keys_i(key, value, ary)
- ID key;
- VALUE value, ary;
-{
- rb_ary_push(ary, ID2SYM(key));
- return ST_CONTINUE;
-}
-
-
-/*
- * call-seq:
- * thr.keys => array
- *
- * Returns an an array of the names of the thread-local variables (as Symbols).
- *
- * thr = Thread.new do
- * Thread.current[:cat] = 'meow'
- * Thread.current["dog"] = 'woof'
- * end
- * thr.join #=> #<Thread:0x401b3f10 dead>
- * thr.keys #=> [:dog, :cat]
- */
-
-static VALUE
-rb_thread_keys(thread)
- VALUE thread;
-{
- rb_thread_t th = rb_thread_check(thread);
- VALUE ary = rb_ary_new();
-
- if (th->locals) {
- st_foreach(th->locals, thread_keys_i, ary);
- }
- return ary;
-}
-
-/*
* call-seq:
* thr.inspect => string
*
@@ -2577,6 +2314,9 @@
void
Init_Thread()
{
+ recursive_key = rb_intern("__recursive_key__");
+ return;
+ /*
VALUE cThGroup;
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
@@ -2622,11 +2362,6 @@
rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
rb_define_method(rb_cThread, "group", rb_thread_group, 0);
- rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
- rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
- rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
- rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
-
rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
rb_cCont = rb_define_class("Continuation", rb_cObject);
@@ -2646,7 +2381,7 @@
rb_define_const(cThGroup, "Default", thgroup_default);
rb_global_variable(&thgroup_default);
- recursive_key = rb_intern("__recursive_key__");
+ */
}
static VALUE
Modified: trunk/gc.c
===================================================================
--- trunk/gc.c 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/gc.c 2005-09-30 06:08:45 UTC (rev 267)
@@ -18,6 +18,7 @@
#include "node.h"
#include "env.h"
#include "re.h"
+#include "yarvcore.h"
#include <stdio.h>
#include <setjmp.h>
#include <sys/types.h>
@@ -420,16 +421,10 @@
# define STACK_LEVEL_MAX 655300
#endif
-NOINLINE(static void set_stack_end(VALUE **stack_end_p));
+NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
-static void
-set_stack_end(VALUE **stack_end_p)
-{
- VALUE stack_end;
- *stack_end_p = &stack_end;
-}
-#define SET_STACK_END VALUE *stack_end; set_stack_end(&stack_end)
-#define STACK_END (stack_end)
+#define YARV_SET_STACK_END yarv_set_stack_end(&th->machine_stack_end)
+#define STACK_END (th->machine_stack_end)
#if defined(sparc) || defined(__sparc__)
# define STACK_LENGTH (rb_gc_stack_start - STACK_END + 0x80)
@@ -448,13 +443,13 @@
#else
static int grow_direction;
static int
-stack_grow_direction(addr)
- VALUE *addr;
+stack_grow_direction(VALUE *addr)
{
- SET_STACK_END;
+ yarv_thread_t *th = GET_THREAD();
+ YARV_SET_STACK_END;
- if (STACK_END > addr) return grow_direction = 1;
- return grow_direction = -1;
+ if (STACK_END > addr) return grow_direction = 1;
+ return grow_direction = -1;
}
# define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0)
# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b)
@@ -463,25 +458,26 @@
#define GC_WATER_MARK 512
#define CHECK_STACK(ret) do {\
- SET_STACK_END;\
+ YARV_SET_STACK_END;\
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
} while (0)
int
ruby_stack_length(VALUE **p)
{
- SET_STACK_END;
- if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END);
- return STACK_LENGTH;
+ yarv_thread_t *th = GET_THREAD();
+ YARV_SET_STACK_END;
+ if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END);
+ return STACK_LENGTH;
}
int
ruby_stack_check(void)
{
- int ret;
-
- CHECK_STACK(ret);
- return ret;
+ int ret;
+ yarv_thread_t *th = GET_THREAD();
+ CHECK_STACK(ret);
+ return ret;
}
#define MARK_STACK_MAX 1024
@@ -1250,120 +1246,132 @@
static int
garbage_collect(void)
{
- struct gc_list *list;
- struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
- jmp_buf save_regs_gc_mark;
- SET_STACK_END;
+ struct gc_list *list;
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
+ jmp_buf save_regs_gc_mark;
+ yarv_thread_t *th = GET_THREAD();
- if (!heaps) return Qfalse;
-#ifdef HAVE_NATIVETHREAD
- if (!is_ruby_native_thread()) {
- rb_bug("cross-thread violation on rb_gc()");
+ YARV_SET_STACK_END;
+
+ if (!heaps) return Qfalse;
+
+ if (dont_gc || during_gc) {
+ if (!freelist) {
+ add_heap();
}
-#endif
- if (dont_gc || during_gc) {
- if (!freelist) {
- add_heap();
- }
- return Qfalse;
- }
- if (during_gc) return Qfalse;
- during_gc++;
+ return Qfalse;
+ }
+ if (during_gc) return Qfalse;
+ during_gc++;
- init_mark_stack();
+ init_mark_stack();
- /* mark frame stack */
- for (frame = ruby_frame; frame; frame = frame->prev) {
- rb_gc_mark_frame(frame);
- if (frame->tmp) {
- struct FRAME *tmp = frame->tmp;
- while (tmp) {
- rb_gc_mark_frame(tmp);
- tmp = tmp->prev;
- }
- }
+ /* mark frame stack */
+ for (frame = ruby_frame; frame; frame = frame->prev) {
+ rb_gc_mark_frame(frame);
+ if (frame->tmp) {
+ struct FRAME *tmp = frame->tmp;
+ while (tmp) {
+ rb_gc_mark_frame(tmp);
+ tmp = tmp->prev;
+ }
}
- gc_mark((VALUE)ruby_scope, 0);
- gc_mark((VALUE)ruby_dyna_vars, 0);
- if (finalizer_table) {
- mark_tbl(finalizer_table, 0);
- }
+ }
+ gc_mark((VALUE)ruby_scope, 0);
+ gc_mark((VALUE)ruby_dyna_vars, 0);
+ if (finalizer_table) {
+ mark_tbl(finalizer_table, 0);
+ }
- FLUSH_REGISTER_WINDOWS;
- /* This assumes that all registers are saved into the jmp_buf (and stack) */
- setjmp(save_regs_gc_mark);
- mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+ FLUSH_REGISTER_WINDOWS;
+ /* This assumes that all registers are saved into the jmp_buf (and stack) */
+ setjmp(save_regs_gc_mark);
+ mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+
#if STACK_GROW_DIRECTION < 0
- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
+ rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
#elif STACK_GROW_DIRECTION > 0
- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
+ rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end);
#else
- if ((VALUE*)STACK_END < rb_gc_stack_start)
- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
- else
- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
+ if ((VALUE*)STACK_END < rb_gc_stack_start)
+ rb_gc_mark_locations(th->machine_stack_end, th->machin_stack_start);
+ else
+ rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end + 1);
#endif
#ifdef __ia64__
- /* mark backing store (flushed register window on the stack) */
- /* the basic idea from guile GC code */
- {
- ucontext_t ctx;
- VALUE *top, *bot;
+ /* mark backing store (flushed register window on the stack) */
+ /* the basic idea from guile GC code */
+ {
+ ucontext_t ctx;
+ VALUE *top, *bot;
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
- _Unwind_Context *unwctx = _UNW_createContextForSelf();
+ _Unwind_Context *unwctx = _UNW_createContextForSelf();
#endif
- getcontext(&ctx);
- mark_locations_array((VALUE*)&ctx.uc_mcontext,
- ((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE)));
+ getcontext(&ctx);
+ mark_locations_array((VALUE*)&ctx.uc_mcontext,
+ ((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE)));
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
- _UNW_currentContext(unwctx);
- bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP);
- top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE);
- _UNW_destroyContext(unwctx);
+ _UNW_currentContext(unwctx);
+ bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP);
+ top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE);
+ _UNW_destroyContext(unwctx);
#else
- bot = (VALUE*)__libc_ia64_register_backing_store_base;
- top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE;
+ bot = (VALUE*)__libc_ia64_register_backing_store_base;
+ top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE;
#endif
- rb_gc_mark_locations(bot, top);
- }
+ rb_gc_mark_locations(bot, top);
+ }
#endif
#if defined(__human68k__) || defined(__mc68000__)
- rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
- (VALUE*)((char*)rb_gc_stack_start + 2));
+ rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
+ (VALUE*)((char*)rb_gc_stack_start + 2));
#endif
- rb_gc_mark_threads();
+ rb_gc_mark_threads();
- /* mark protected global variables */
- for (list = global_List; list; list = list->next) {
- rb_gc_mark_maybe(*list->varptr);
- }
- rb_mark_end_proc();
- rb_gc_mark_global_tbl();
+ /* mark protected global variables */
+ for (list = global_List; list; list = list->next) {
+ rb_gc_mark_maybe(*list->varptr);
+ }
+ rb_mark_end_proc();
+ rb_gc_mark_global_tbl();
- rb_mark_tbl(rb_class_tbl);
- rb_gc_mark_trap_list();
+ rb_mark_tbl(rb_class_tbl);
+ rb_gc_mark_trap_list();
- /* mark generic instance variables for special constants */
- rb_mark_generic_ivar_tbl();
+ /* mark generic instance variables for special constants */
+ rb_mark_generic_ivar_tbl();
- rb_gc_mark_parser();
+ rb_gc_mark_parser();
- /* gc_mark objects whose marking are not completed*/
- while (!MARK_STACK_EMPTY){
- if (mark_stack_overflow){
- gc_mark_all();
- }
- else {
- gc_mark_rest();
- }
+ /* gc_mark objects whose marking are not completed*/
+ while (!MARK_STACK_EMPTY){
+ if (mark_stack_overflow){
+ gc_mark_all();
}
- gc_sweep();
+ else {
+ gc_mark_rest();
+ }
+ }
+ gc_sweep();
- return Qtrue;
+ return Qtrue;
}
void
+yarv_machine_stack_mark(yarv_thread_t *th)
+{
+#if STACK_GROW_DIRECTION < 0
+ rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
+#elif STACK_GROW_DIRECTION > 0
+ rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end);
+#else
+#error "TODO"
+#endif
+}
+
+
+void
rb_gc(void)
{
garbage_collect();
Modified: trunk/insns.def
===================================================================
--- trunk/insns.def 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/insns.def 2005-09-30 06:08:45 UTC (rev 267)
@@ -1364,6 +1364,7 @@
(VALUE val)
(VALUE val)
{
+ YARV_CHECK_INTS();
POP_CONTROL_STACK_FRAME(th);
RESTORE_REGS();
}
Modified: trunk/test.rb
===================================================================
--- trunk/test.rb 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/test.rb 2005-09-30 06:08:45 UTC (rev 267)
@@ -1,9 +1,13 @@
-p YARVCore::VM::Thread.new{
-
+10.times{|e|
+ Thread.new(e){|le|
+ 10000.times{|i|
+ p [le, i]
+ }
+ }
}
+sleep 10
-
__END__
require 'test_req'
Added: trunk/thread.c
===================================================================
--- trunk/thread.c 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/thread.c 2005-09-30 06:08:45 UTC (rev 267)
@@ -0,0 +1,497 @@
+/*
+ * YARVCore::VM::Thread
+ */
+
+/*
+ YARV Thread Desgin
+
+ mode 1: Userlevel Thread
+ Same as traditional ruby thread.
+
+ mode 2: Native Thread with Giant VM lock
+ Using pthread (or Windows thread) and Ruby threads run concurrent.
+
+ mode 3: Native Thread with fine grain lock
+ Using pthread and Ruby threads run concurrent or parallel.
+
+------------------------------------------------------------------------
+
+ mode 2:
+ A thread has mutex (GIL: Global Interpreter Lock) can run. When
+ thread scheduling, running thread release GIL. If running thread
+ try blocking operation, this thread must release GIL and another
+ thread can continue this flow. After blocking operation, thread
+ must check interrupt (CHECK_INTS).
+
+ Every VM can run parallel.
+
+ Ruby threads are scheduled by OS thread scheduler.
+
+------------------------------------------------------------------------
+
+ mode 3:
+ Every threads run concurrent and to access shared object exclusive
+ access control is needed. For example, to access String object or
+ Array object, fine grain lock must be locked every time.
+ */
+
+
+/* for pthread (mode 2) */
+
+#include "eval_intern.h"
+
+#define THREAD_DEBUG 0
+
+#if THREAD_DEBUG
+#define thead_debug printf
+#else
+#define thead_debug if(0)printf
+#endif
+
+
+/********************************************************************************/
+
+void
+static thread_cleanup_func(void *th_ptr)
+{
+ yarv_thread_t *th = th_ptr;
+ rb_hash_delete(GET_VM()->living_threads, th->self);
+ th->status = THREAD_KILLED;
+ th->machine_stack_start = th->machine_stack_end = 0;
+}
+
+VALUE th_eval_body(yarv_thread_t *th);
+
+NOINLINE(static int
+ thread_start_func_2(yarv_thread_t *th, VALUE *stack_start));
+
+static int
+thread_start_func_2(yarv_thread_t *th, VALUE *stack_start)
+{
+ VALUE args = th->first_args;
+ yarv_proc_t *proc;
+ GetProcVal(th->first_proc, proc);
+
+ th->machine_stack_start = stack_start;
+
+ thead_debug("start: %p\n", th);
+ GIL_LOCK_BEGIN();
+ yarv_set_current_running_thread(th);
+ thead_debug("get_lock, start: %p\n", th);
+ th->value = th_invoke_proc(th, proc, RARRAY(args)->len, RARRAY(args)->ptr);
+ th->status = THREAD_KILLED;
+ thead_debug("end: %p\n", th);
+ rb_hash_delete(GET_VM()->living_threads, th->self);
+
+ GIL_LOCK_END();
+
+ return 0;
+}
+
+static void *
+thread_start_func_1(void *th_ptr)
+{
+ yarv_thread_t *th = th_ptr;
+ VALUE stack_start;
+ /* ignore self and klass */
+
+ native_cleanup_push(thread_cleanup_func, th);
+
+ /* run */
+ thread_start_func_2(th, &stack_start);
+ thread_cleanup_func(th);
+ native_cleanup_pop(0);
+ return 0;
+}
+
+#if HAVE_PTHREAD_H
+int
+native_thread_crteate(yarv_thread_t *th)
+{
+ pthread_attr_t attr;
+ size_t stack_size = 16 * 1024;
+ int err;
+
+ thead_debug("create: %p, stack size: %d\n", th, stack_size);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, stack_size);
+ err = pthread_create(&th->thread_id, &attr, thread_start_func_1, th);
+ if(err != 0){
+ th->status = THREAD_KILLED;
+ rb_raise(rb_eThreadError, "can't create Thread (%d)", err);
+ }
+ return err;
+}
+#else
+#error "unsupported"
+#endif
+
+static VALUE
+yarv_thread_s_new(VALUE klass, VALUE args)
+{
+ yarv_thread_t *th;
+ VALUE thval;
+
+ /* create thread object */
+ thval= rb_class_new_instance(0, 0, cYarvThread);
+ GetThreadVal(thval, th);
+ rb_hash_aset(GET_VM()->living_threads, thval, Qtrue);
+
+ /* setup thread environment */
+ th->first_args = args;
+ th->first_proc = rb_block_proc();
+
+ /* kick thread */
+ native_thread_crteate(th);
+ return thval;
+}
+
+static VALUE
+yarv_thread_join(int argc, VALUE *argv, VALUE self)
+{
+ yarv_thread_t *th;
+ int err;
+ GetThreadVal(self, th);
+
+ if(th->status == THREAD_KILLED){
+ return self;
+ }
+
+ GIL_UNLOCK_BEGIN();
+ err = native_thread_join(th->thread_id, 0);
+ GIL_UNLOCK_END();
+
+ switch(err){
+ case EDEADLK:
+ rb_raise(rb_eThreadError, "can't join current thread (cause dead lock)");
+ }
+ return self;
+}
+
+static VALUE
+yarv_thread_value(VALUE self)
+{
+ yarv_thread_t *th;
+ yarv_thread_join(0, 0, self);
+ GetThreadVal(self, th);
+ return th->value;
+}
+
+#if !defined HAVE_PAUSE
+# if defined _WIN32 && !defined __CYGWIN__
+# define pause() Sleep(INFINITE)
+# else
+# define pause() sleep(0x7fffffff)
+# endif
+#endif
+
+void
+rb_thread_sleep_forever()
+{
+ GIL_UNLOCK_BEGIN();
+ pause();
+ GIL_UNLOCK_END();
+}
+
+static double
+timeofday(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
+}
+
+static void
+sleep_timeval(struct timeval time)
+{
+#ifndef linux
+ double d, limit;
+ limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6;
+#endif
+ for (;;) {
+ int n = select(0, 0, 0, 0, &time);
+ if (n == 0) return;
+ if (n < 0) {
+ switch (errno) {
+ case EINTR:
+#ifdef ERESTART
+ case ERESTART:
+#endif
+ return;
+ default:
+ rb_sys_fail("sleep");
+ }
+ }
+#ifndef linux
+ d = limit - timeofday();
+
+ time.tv_sec = (int)d;
+ time.tv_usec = (int)((d - (int)d)*1e6);
+ if (time.tv_usec < 0) {
+ time.tv_usec += (long)1e6;
+ time.tv_sec -= 1;
+ }
+ if (time.tv_sec < 0) return;
+#endif
+ }
+}
+
+void
+rb_thread_wait_for(struct timeval time)
+{
+ double date;
+
+ CSL_UNLOCK_BEGIN();
+ GIL_UNLOCK_BEGIN();
+ sleep_timeval(time);
+ GIL_UNLOCK_END();
+ CSL_UNLOCK_END();
+}
+
+static VALUE
+yarv_thread_s_current(VALUE klass){
+ return GET_THREAD()->self;
+}
+
+static VALUE
+yarv_thread_s_main(VALUE klass){
+ return GET_VM()->main_thread;
+}
+
+
+VALUE
+rb_thread_local_aref(VALUE thread, ID id)
+{
+ yarv_thread_t *th;
+ VALUE val;
+
+ GetThreadVal(thread, th);
+ if(ruby_safe_level >= 4 && th != GET_THREAD()){
+ rb_raise(rb_eSecurityError, "Insecure: thread locals");
+ }
+ if(!th->local_storage){
+ return Qnil;
+ }
+ if(st_lookup(th->local_storage, id, &val)){
+ return val;
+ }
+ return Qnil;
+}
+
+
+/*
+ * call-seq:
+ * thr[sym] => obj or nil
+ *
+ * Attribute Reference---Returns the value of a thread-local variable, using
+ * either a symbol or a string name. If the specified variable does not exist,
+ * returns <code>nil</code>.
+ *
+ * a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
+ * b = Thread.new { Thread.current[:name] = "B"; Thread.stop }
+ * c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
+ * Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
+ *
+ * <em>produces:</em>
+ *
+ * #<Thread:0x401b3b3c sleep>: C
+ * #<Thread:0x401b3bc8 sleep>: B
+ * #<Thread:0x401b3c68 sleep>: A
+ * #<Thread:0x401bdf4c run>:
+ */
+
+static VALUE
+rb_thread_aref(VALUE thread, VALUE id)
+{
+ return rb_thread_local_aref(thread, rb_to_id(id));
+}
+
+VALUE
+rb_thread_local_aset(VALUE thread, ID id, VALUE val)
+{
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+
+ if(ruby_safe_level >= 4 && th != GET_THREAD()){
+ rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
+ }
+ if(OBJ_FROZEN(thread)){
+ rb_error_frozen("thread locals");
+ }
+ if(!th->local_storage){
+ th->local_storage = st_init_numtable();
+ }
+ if(NIL_P(val)){
+ st_delete(th->local_storage, (st_data_t*)&id, 0);
+ return Qnil;
+ }
+ st_insert(th->local_storage, id, val);
+ return val;
+}
+
+/*
+ * call-seq:
+ * thr[sym] = obj => obj
+ *
+ * Attribute Assignment---Sets or creates the value of a thread-local variable,
+ * using either a symbol or a string. See also <code>Thread#[]</code>.
+ */
+
+static VALUE
+rb_thread_aset(VALUE thread, ID id, VALUE val)
+{
+ return rb_thread_local_aset(thread, rb_to_id(id), val);
+}
+
+
+/*
+ * call-seq:
+ * thr.key?(sym) => true or false
+ *
+ * Returns <code>true</code> if the given string (or symbol) exists as a
+ * thread-local variable.
+ *
+ * me = Thread.current
+ * me[:oliver] = "a"
+ * me.key?(:oliver) #=> true
+ * me.key?(:stanley) #=> false
+ */
+
+static VALUE
+rb_thread_key_p(VALUE thread, ID id)
+{
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+
+ if(!th->local_storage){
+ return Qfalse;
+ }
+ if(st_lookup(th->local_storage, rb_to_id(id), 0)){
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static int
+thread_keys_i(ID key, VALUE value, VALUE ary)
+{
+ rb_ary_push(ary, ID2SYM(key));
+ return ST_CONTINUE;
+}
+
+
+/*
+ * call-seq:
+ * thr.keys => array
+ *
+ * Returns an an array of the names of the thread-local variables (as Symbols).
+ *
+ * thr = Thread.new do
+ * Thread.current[:cat] = 'meow'
+ * Thread.current["dog"] = 'woof'
+ * end
+ * thr.join #=> #<Thread:0x401b3f10 dead>
+ * thr.keys #=> [:dog, :cat]
+ */
+
+static VALUE
+rb_thread_keys(thread)
+ VALUE thread;
+{
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+ VALUE ary = rb_ary_new();
+
+ if(th->local_storage){
+ st_foreach(th->local_storage, thread_keys_i, ary);
+ }
+ return ary;
+}
+
+void
+yarv_thraed_schedule()
+{
+ if(GET_VM()->thread_critical == 0){
+ yarv_thread_t *th = GET_THREAD();
+ yarv_save_machine_context(th);
+ native_mutex_unlock(&GET_VM()->global_interpreter_lock);
+ native_mutex_lock(&GET_VM()->global_interpreter_lock);
+ yarv_set_current_running_thread(th);
+ }
+}
+
+static VALUE
+yarv_thread_s_pass(VALUE klass)
+{
+ yarv_thraed_schedule();
+ return Qnil;
+}
+
+void
+yarv_set_stack_end(VALUE **stack_end_p)
+{
+ VALUE stack_end;
+ *stack_end_p = &stack_end;
+}
+
+void
+yarv_save_machine_context(yarv_thread_t *th)
+{
+ yarv_set_stack_end(&th->machine_stack_end);
+ setjmp(th->machine_regs);
+}
+
+static pthread_t time_thread;
+
+static void*
+thread_timer(void *dummy)
+{
+ for (;;) {
+#ifdef HAVE_NANOSLEEP
+ struct timespec req, rem;
+
+ req.tv_sec = 0;
+ req.tv_nsec = 10000000;
+ nanosleep(&req, &rem);
+#else
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000;
+ select(0, NULL, NULL, NULL, &tv);
+#endif
+ theYarvVM->interrupt_flag = 1;
+ }
+}
+
+void
+Init_yarvthread(){
+ rb_define_singleton_method(cYarvThread, "new", yarv_thread_s_new, -2);
+ rb_define_singleton_method(cYarvThread, "start", yarv_thread_s_new, -2);
+ rb_define_singleton_method(cYarvThread, "fork", yarv_thread_s_new, -2);
+
+ rb_define_singleton_method(cYarvThread, "current", yarv_thread_s_current, 0);
+ rb_define_singleton_method(cYarvThread, "pass", yarv_thread_s_pass, 0);
+
+ rb_define_method(cYarvThread, "join", yarv_thread_join, -1);
+ rb_define_method(cYarvThread, "value", yarv_thread_value, 0);
+ rb_define_method(cYarvThread, "[]", rb_thread_aref, 1);
+ rb_define_method(cYarvThread, "[]=", rb_thread_aset, 2);
+ rb_define_method(cYarvThread, "key?", rb_thread_key_p, 1);
+ rb_define_method(cYarvThread, "keys", rb_thread_keys, 0);
+
+ if(time_thread == 0){
+ pthread_create(&time_thread, 0, thread_timer, 0);
+ }
+
+ {
+ /* main thread setting */
+ {
+ /* acquire global interpreter lock */
+ yarv_thread_lock_t *lp = &GET_VM()->global_interpreter_lock;
+ yarv_thread_lock_initialize(*lp);
+ native_mutex_lock(lp);
+ }
+ }
+}
+
Property changes on: trunk/thread.c
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/thread_pthread.h
===================================================================
--- trunk/thread_pthread.h 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/thread_pthread.h 2005-09-30 06:08:45 UTC (rev 267)
@@ -0,0 +1,19 @@
+
+#ifndef THREAD_PTHREAD_H_INCLUDED
+#define THREAD_PTHREAD_H_INCLUDED
+
+#include <pthread.h>
+typedef pthread_t yarv_thread_id_t;
+typedef pthread_mutex_t yarv_thread_lock_t;
+
+#define native_mutex_lock pthread_mutex_lock
+#define native_mutex_unlock pthread_mutex_unlock
+#define native_thread_join pthread_join
+
+#define yarv_thread_lock_initialize(lock) \
+ ((lock) = PTHREAD_MUTEX_INITIALIZER)
+
+#define native_cleanup_push pthread_cleanup_push
+#define native_cleanup_pop pthread_cleanup_pop
+
+#endif /* THREAD_PTHREAD_H_INCLUDED */
Property changes on: trunk/thread_pthread.h
___________________________________________________________________
Name: svn:executable
+ *
Modified: trunk/yarv.h
===================================================================
--- trunk/yarv.h 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/yarv.h 2005-09-30 06:08:45 UTC (rev 267)
@@ -21,13 +21,47 @@
#define SET_YARV_STOP()
#endif
-VALUE yarv_get_current_running_vm_value _(());
-VALUE yarv_get_current_running_thread_value _(());
-yarv_vm_t *yarv_get_current_running_vm _(());
-yarv_thread_t *yarv_get_current_running_thread _(());
+#if YARV_THREAD_MODEL == 2
+extern yarv_thread_t *yarvCurrentThread;
+extern yarv_vm_t *theYarvVM;
+static inline VALUE
+yarv_get_current_running_vm_value()
+{
+ return theYarvVM->self;
+}
+
+static inline VALUE
+yarv_get_current_running_thread_value()
+{
+ return yarvCurrentThread->self;
+}
+
+static inline yarv_vm_t *
+yarv_get_current_running_vm()
+{
+ return theYarvVM;
+}
+
+static inline yarv_thread_t *
+yarv_get_current_running_thread()
+{
+ return yarvCurrentThread;
+}
+
+static inline void
+yarv_set_current_running_thread(yarv_thread_t *th)
+{
+ yarvCurrentThread = th;
+}
+
+#else
+#error "unsupported thread model"
+#endif
+
#define GET_THREAD() yarv_get_current_running_thread()
+#define GET_VM() yarv_get_current_running_vm()
struct yarv_yield_data{
yarv_thread_t *th;
Modified: trunk/yarvcore.c
===================================================================
--- trunk/yarvcore.c 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/yarvcore.c 2005-09-30 06:08:45 UTC (rev 267)
@@ -59,7 +59,8 @@
#define va_init_list(a,b) va_start(a)
#endif
-#if 0
+#define MARK_FREE_DEBUG 0
+#if MARK_FREE_DEBUG
#define MARK_REPORT(msg) printf("mark: %s\n", msg)
#define FREE_REPORT(msg) printf("free: %s\n", msg)
#define GC_INFO printf
@@ -81,41 +82,11 @@
void yarv_setup(void *p1, void *p2, void *p3, void *p4,
void *p5, void *p6, void *p7, void *p8);
-static yarv_thread_t *yarvCurrentRunningThread = 0;
-static yarv_vm_t *theYarvVM = 0;
+yarv_thread_t *yarvCurrentThread = 0;
+yarv_vm_t *theYarvVM = 0;
static VALUE yarvVMArray = Qnil;
VALUE
-yarv_get_current_running_vm_value()
-{
- return theYarvVM->self;
-}
-
-VALUE
-yarv_get_current_running_thread_value()
-{
- return yarvCurrentRunningThread->self;
-}
-
-yarv_vm_t *
-yarv_get_current_running_vm()
-{
- return theYarvVM;
-}
-
-yarv_thread_t *
-yarv_get_current_running_thread()
-{
- return yarvCurrentRunningThread;
-}
-
-void
-yarv_set_current_running_thread(yarv_thread_t *th)
-{
- yarvCurrentRunningThread = th;
-}
-
-VALUE
th_invoke_yield(yarv_thread_t *th, int argc, VALUE *argv);
/* rb_yield_values */
@@ -207,7 +178,7 @@
argv[4] = ISEQ_TYPE_TOP;
iseq = rb_class_new_instance(5, argv, cYarvISeq);
- vm_eval(yarv_get_current_running_vm_value(), iseq);
+ vm_eval(GET_VM()->self, iseq);
return 0;
}
@@ -275,7 +246,7 @@
{
VALUE vm;
VALUE ret;
- vm = yarv_get_current_running_vm_value();
+ vm = GET_VM()->self;
ret = vm_eval(vm, iseq);
return ret;
}
@@ -533,7 +504,7 @@
MARK_REPORT("-> vm");
if(ptr){
vmobj = ptr;
- rb_gc_mark(vmobj->main_thread);
+ rb_gc_mark(vmobj->living_threads);
}
MARK_REPORT("<- vm");
}
@@ -576,11 +547,16 @@
th = ptr;
FREE_UNLESS_NULL(th->stack);
FREE_UNLESS_NULL(th->top_local_tbl);
+ if(th->local_storage){
+ st_free_table(th->local_storage);
+ }
ruby_xfree(ptr);
}
FREE_REPORT("<- thread");
}
+void yarv_machine_stack_mark(yarv_thread_t *th);
+
static void thread_mark(void *ptr){
yarv_thread_t *th;
MARK_REPORT("-> thread");
@@ -601,8 +577,16 @@
/* mark ruby objects */
MARK_UNLESS_NULL(th->vm_value);
- MARK_UNLESS_NULL(th->stat_insn_usage);
MARK_UNLESS_NULL(th->klass_nest_stack);
+ MARK_UNLESS_NULL(th->first_proc);
+ MARK_UNLESS_NULL(th->first_args);
+ MARK_UNLESS_NULL(th->stat_insn_usage);
+
+ if(GET_THREAD() != th &&
+ th->machine_stack_start &&
+ th->machine_stack_end){
+ yarv_machine_stack_mark(th);
+ }
}
MARK_REPORT("<- thread");
}
@@ -634,6 +618,8 @@
th->cfp->dfp = th->stack;
th->cfp->self = Qnil;
th->cfp->magic = 0;
+
+ th->status = THREAD_RUNNABLE;
}
static VALUE
@@ -641,8 +627,7 @@
{
yarv_thread_t *th;
yarv_vm_t *vm;
- VALUE vmval = yarv_get_current_running_vm_value();
-
+ VALUE vmval = GET_VM()->self;
GetThreadVal(self, th);
GetVMVal(vmval, vm);
@@ -785,6 +770,8 @@
// VALUE yarv_Hash_each();
VALUE insns_name_array();
+VALUE Init_yarvthread();
+
char yarv_version[0x20];
char *yarv_options = ""
#if OPT_DIRECT_THREADED_CODE
@@ -865,12 +852,11 @@
/* declare YARVCore::VM::Thread */
cYarvThread = rb_define_class_under(cYarvVM, "Thread", rb_cObject);
+ rb_define_global_const("Thread", cYarvThread);
rb_define_alloc_func(cYarvThread, thread_alloc);
rb_define_method(cYarvThread, "initialize", thread_init, 0);
rb_define_method(cYarvThread, "eval", thread_eval, 1);
- // rb_define_singleton_method(cYarvThread, "new", rb_thread_s_new, -2);
-
/* declare YARVCore::VM::Env */
cYarvEnv = rb_define_class_under(cYarvVM, "Env", rb_cObject);
rb_define_alloc_func(cYarvEnv, env_alloc);
@@ -954,10 +940,16 @@
thread_free(GET_THREAD());
yarv_set_current_running_thread(th);
+ extern VALUE *rb_gc_stack_start;
+ th->machine_stack_start = rb_gc_stack_start;
+ Init_yarvthread();
+
+ vm->living_threads = rb_hash_new();
+ rb_hash_aset(vm->living_threads, th->self, Qtrue);
+
/*
* set toplevel binding
*/
-
}
}
Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h 2005-09-29 14:01:52 UTC (rev 266)
+++ trunk/yarvcore.h 2005-09-30 06:08:45 UTC (rev 267)
@@ -6,17 +6,19 @@
#ifndef _YARVCORE_H_INCLUDED_
#define _YARVCORE_H_INCLUDED_
+#define YARV_THREAD_MODEL 2
+
+#include <setjmp.h>
+
#include "debug.h"
#include "vm_opts.h"
+#include "st.h"
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-typedef pthread_t yarv_thread_id_t;
-typedef pthread_mutex_t yarv_thread_lock_t;
+#if defined(HAVE_PTHREAD_H)
+#include "thread_pthread.h"
#else
-typedef int yarv_thread_id_t;
-typedef
-#endif /* _SAFE_THREAD */
+#error "unsupported thread type"
+#endif
/*****************/
/* configuration */
@@ -262,11 +264,13 @@
Data_Get_Struct(obj, yarv_vm_t, tobj)
typedef struct{
- VALUE main_thread;
VALUE self;
- /* this data structure should include all
- runtime information (e.g. method table, object management table, ...) */
+ yarv_thread_lock_t global_interpreter_lock;
+ int thread_critical;
+ VALUE main_thread;
+ VALUE living_threads;
+ int interrupt_flag;
} yarv_vm_t;
typedef struct{
@@ -293,6 +297,13 @@
#define GetThreadVal(obj, tobj) \
Data_Get_Struct(obj, yarv_thread_t, tobj)
+enum yarv_thread_status{
+ THREAD_TO_KILL,
+ THREAD_RUNNABLE,
+ THREAD_STOPPED,
+ THREAD_KILLED,
+};
+
typedef struct{
VALUE self;
VALUE vm_value;
@@ -312,9 +323,6 @@
/* klass/module nest information stack */
VALUE klass_nest_stack; /* Array */
- /* other information */
- VALUE stat_insn_usage;
-
/* passed via parse.y, eval.c (rb_scope_setup_local_tbl) */
ID *top_local_tbl;
@@ -322,13 +330,24 @@
ID *base_local_tbl;
int base_local_size;
yarv_block_t *base_block;
-
+
/* thread control */
- yarv_thread_id_t *thread_id;
+ yarv_thread_id_t thread_id;
VALUE value;
- int status;
- yarv_thread_lock_t global_interpreter_lock;
+ enum yarv_thread_status status;
+
+ VALUE first_proc;
+ VALUE first_args;
+
+ /* for GC */
+ VALUE *machine_stack_start;
+ VALUE *machine_stack_end;
+ jmp_buf machine_regs;
+ /* other information */
+ st_table *local_storage; /* thread local storage */
+ VALUE stat_insn_usage;
+
} yarv_thread_t;
/** node -> yarv instruction sequence object */
@@ -349,7 +368,7 @@
/* each thread has this size stack : 2MB */
-#define YARV_THREAD_STACK_SIZE 0x20000
+#define YARV_THREAD_STACK_SIZE (128 * 1024)
/* from ruby 1.9 variable.c */
@@ -434,6 +453,48 @@
#include "yarv.h"
+#define GIL_LOCK_BEGIN() do { \
+ native_mutex_lock(&GET_VM()->global_interpreter_lock)
+
+#define GIL_LOCK_END() \
+ native_mutex_unlock(&GET_VM()->global_interpreter_lock); \
+} while(0)
+
+#define GIL_UNLOCK_BEGIN() do { \
+ yarv_thread_t *_th_stored = GET_THREAD(); \
+ yarv_save_machine_context(_th_stored); \
+ native_mutex_unlock(&GET_VM()->global_interpreter_lock)
+
+#define GIL_UNLOCK_END() \
+ native_mutex_lock(&GET_VM()->global_interpreter_lock); \
+ yarv_set_current_running_thread(_th_stored); \
+} while(0)
+
+#define CSL_UNLOCK_BEGIN() do { \
+ int _thread_critical = GET_VM()->thread_critical; \
+ GET_VM()->thread_critical = 0
+
+#define CSL_UNLOCK_END() \
+ GET_VM()->thread_critical = _thread_critical; \
+} while(0)
+
+NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
+NOINLINE(void yarv_save_machine_context(yarv_thread_t *));
+
+extern int rb_thread_pending;
+
+void yarv_thraed_schedule();
+
+#define YARV_CHECK_INTS() do { \
+ if(theYarvVM->interrupt_flag){ \
+ theYarvVM->interrupt_flag = 0; \
+ /* TODO: trap something event */ \
+ yarv_thraed_schedule(); \
+ } \
+} while (0)
+
+
+
#endif // _YARVCORE_H_INCLUDED_
--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml