yarv-diff:114
From: ko1 atdot.net
Date: 1 Oct 2005 14:09:59 -0000
Subject: [yarv-diff:114] r270 - in trunk: . win32
Author: ko1
Date: 2005-10-01 23:09:59 +0900 (Sat, 01 Oct 2005)
New Revision: 270
Added:
trunk/thread_win32.h
Modified:
trunk/ChangeLog
trunk/common.mk
trunk/eval_thread.c
trunk/gc.c
trunk/test.rb
trunk/thread.c
trunk/thread_pthread.h
trunk/win32/Makefile.sub
trunk/yarvcore.c
trunk/yarvcore.h
Log:
* thread_win32.h, common.mk : add thread_win32.h
* thread.c : support _WIN32 thread
* thread.c, thread_pthread.h : fix some interface
* eval_thread.c : remove debug print
* gc.c : fix stack region
* win32/Makefile.sub : add -MD flag to LDFLAGS
* yarvcore.c : fix mark and sweep debug print
* yarvcore.h : fix VM#living_threads data type to st_table
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/ChangeLog 2005-10-01 14:09:59 UTC (rev 270)
@@ -4,6 +4,25 @@
# from Mon, 03 May 2004 01:24:19 +0900
#
+2005-10-01(Sat) 23:06:21 +0900 Koichi Sasada <ko1 atdot.net>
+
+ * thread_win32.h, common.mk : add thread_win32.h
+
+ * thread.c : support _WIN32 thread
+
+ * thread.c, thread_pthread.h : fix some interface
+
+ * eval_thread.c : remove debug print
+
+ * gc.c : fix stack region
+
+ * win32/Makefile.sub : add -MD flag to LDFLAGS
+
+ * yarvcore.c : fix mark and sweep debug print
+
+ * yarvcore.h : fix VM#living_threads data type to st_table
+
+
2005-10-01(Sat) 00:25:28 +0900 Koichi Sasada <ko1 atdot.net>
* thread.c, yarvcore.h : rename GIL (Global Interpreter Lock) to
Modified: trunk/common.mk
===================================================================
--- trunk/common.mk 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/common.mk 2005-10-01 14:09:59 UTC (rev 270)
@@ -275,7 +275,7 @@
{$(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)}thread_win32.h {$(VPATH)}thread_pthread.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
@@ -454,7 +454,7 @@
$(RUBY) -I$(srcdir) -I. $(srcdir)/rb/aotcompile.rb $(INSNS2VMOPT)
# for GCC
-vm.asm:
+vmasm:
$(CC) $(CFLAGS) $(CPPFLAGS) -S $(srcdir)/vm.c
run.gdb:
Modified: trunk/eval_thread.c
===================================================================
--- trunk/eval_thread.c 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/eval_thread.c 2005-10-01 14:09:59 UTC (rev 270)
@@ -736,7 +736,7 @@
void
rb_thread_schedule()
{
- printf("rb_thread_schedule()\n");
+ // printf("rb_thread_schedule()\n");
// TODO: fix me
// ignore
/* UNSUPPORTED(rb_thread_schedule); */
@@ -2430,12 +2430,15 @@
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
VALUE list, sym;
- sym = ID2SYM(rb_frame_this_func());
+ sym = ID2SYM(rb_frame_this_func());
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
- VALUE symname = rb_inspect(sym);
- VALUE thrname = rb_inspect(rb_thread_current());
- rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
- StringValuePtr(symname), StringValuePtr(thrname));
+ VALUE symname;
+ VALUE thrname;
+ symname = rb_inspect(sym);
+ thrname = rb_inspect(rb_thread_current());
+
+ rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
+ StringValuePtr(symname), StringValuePtr(thrname));
}
list = rb_hash_aref(hash, sym);
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
Modified: trunk/gc.c
===================================================================
--- trunk/gc.c 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/gc.c 2005-10-01 14:09:59 UTC (rev 270)
@@ -1291,9 +1291,9 @@
#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);
+ rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end + 1);
#else
- if ((VALUE*)STACK_END < rb_gc_stack_start)
+ if (th->machine_stack_end < th->machin_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);
@@ -1353,8 +1353,8 @@
gc_mark_rest();
}
}
+
gc_sweep();
-
return Qtrue;
}
Modified: trunk/test.rb
===================================================================
--- trunk/test.rb 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/test.rb 2005-10-01 14:09:59 UTC (rev 270)
@@ -1,22 +1,117 @@
Thread.new{
- sleep
-}.join(10)
+ 100.times{|i|
+ sleep 1
+ p [i]
+ }
+}
-p :finish
-exit
+40.times{|i|
+ p i
+ sleep 0.1
+}
+#p gets while true
+
+
__END__
-10.times{|e|
+10000.times{|e|
+ begin
+ p e
+ Thread.new{
+ sleep
+ }
+ rescue Exception => ex
+ p ex
+ p e
+ break
+ end
+}
+
+__END__
+
+max = 100000000
+def m
+end
+t1 = Thread.new{
+ max.times{
+ m
+ p 1
+ }
+}
+t2 = Thread.new{
+ max.times{
+ m
+ p '------------------------------------------------------------------'
+ }
+}
+t1.join
+t2.join
+
+__END__
+
+Thread.new{
+ sleep 1
+}.join
+p :fin
+
+__END__
+
+(1..10).map{|e|
Thread.new(e){|le|
+ p "Start #{le}"
10000.times{|i|
p [le, i]
}
+ p "Finish #{le}"
}
+}.each{|t|
+ t.join
}
-sleep 10
+p :finish
+
__END__
+def test100
+ ths = (0..100).map{|e|
+ Thread.new(e){|le|
+ p le
+ }
+ }
+ ths.each{|e| e.join}
+end
+test100
+t1 = Thread.new{
+ p 1
+}
+t2 = Thread.new{
+ p 2
+}
+t1.join
+t2.join
+
+__END__
+def jointest
+ Thread.new{
+ sleep
+ }.join(10)
+
+ p :finish
+end
+
+10.times{|e|
+ Thread.new(e){|le|
+ p "Start #{le}"
+ 10000.times{|i|
+ [le, i]
+ }
+ p "Finish #{le}"
+ }
+}
+sleep 20
+p :finish
+__END__
+
require 'test_req'
# test_req.rb
Modified: trunk/thread.c
===================================================================
--- trunk/thread.c 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/thread.c 2005-10-01 14:09:59 UTC (rev 270)
@@ -5,18 +5,18 @@
/*
YARV Thread Desgin
- mode 1: Userlevel Thread
+ model 1: Userlevel Thread
Same as traditional ruby thread.
- mode 2: Native Thread with Giant VM lock
+ model 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
+ model 3: Native Thread with fine grain lock
Using pthread and Ruby threads run concurrent or parallel.
------------------------------------------------------------------------
- mode 2:
+ model 2:
A thread has mutex (GVL: Global VM Lock) can run. When thread
scheduling, running thread release GVL. If running thread
try blocking operation, this thread must release GVL and another
@@ -29,23 +29,23 @@
------------------------------------------------------------------------
- mode 3:
+ model 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) */
+/* for model 2 */
#include "eval_intern.h"
#define THREAD_DEBUG 0
#if THREAD_DEBUG
-#define thead_debug printf
+#define thread_debug printf
#else
-#define thead_debug if(0)printf
+#define thread_debug if(0)printf
#endif
static void sleep_for_polling();
@@ -53,22 +53,33 @@
static double timeofday();
struct timeval rb_time_interval(VALUE);
+inline static void
+st_delete_wrap(st_table *table, VALUE key){
+ st_delete(table, (st_data_t *)&key, 0);
+}
+
/********************************************************************************/
+#define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
+#if HAVE_PTHREAD_H
+#include "thread_pthread.h"
+#elif _WIN32
+#include "thread_win32.h"
+#else
+#error "unsupported thread"
+#endif
+
+VALUE th_eval_body(yarv_thread_t *th);
+
void
static thread_cleanup_func(void *th_ptr)
{
yarv_thread_t *th = th_ptr;
- rb_hash_delete(GET_VM()->living_threads, th->self);
+ st_delete_wrap(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)
{
@@ -78,59 +89,20 @@
th->machine_stack_start = stack_start;
- thead_debug("start: %p\n", th);
+ thread_debug("start: %p\n", th);
GVL_LOCK_BEGIN();
yarv_set_current_running_thread(th);
- thead_debug("get_lock, start: %p\n", th);
+ thread_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);
+ thread_debug("end: %p\n", th);
+ st_delete_wrap(GET_VM()->living_threads, th->self);
GVL_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)
{
@@ -140,7 +112,7 @@
/* create thread object */
thval= rb_class_new_instance(0, 0, cYarvThread);
GetThreadVal(thval, th);
- rb_hash_aset(GET_VM()->living_threads, thval, Qtrue);
+ st_insert(GET_VM()->living_threads, thval, (st_data_t)th->thread_id);
/* setup thread environment */
th->first_args = args;
@@ -163,6 +135,7 @@
}
if(argc == 0){
+ thread_debug("yarv_thread_join(0)\n");
GVL_UNLOCK_BEGIN();
err = native_thread_join(th->thread_id, 0);
GVL_UNLOCK_END();
@@ -195,9 +168,9 @@
}
}
else{
-
+ rb_raise(rb_eArgError, "wrong number of arguments");
}
- return self;
+ return Qnil;
}
static VALUE
@@ -220,6 +193,7 @@
void
rb_thread_sleep_forever()
{
+ thread_debug("rb_thread_sleep_forever\n");
GVL_UNLOCK_BEGIN();
pause();
GVL_UNLOCK_END();
@@ -236,10 +210,18 @@
static void
sleep_timeval(struct timeval time)
{
+#ifdef _WIN32
+ DWORD limit = time.tv_sec * 1000 + time.tv_usec / 1000;
+ thread_debug("sleep_timeval - sleep start\n");
+ Sleep(limit);
+ thread_debug("sleep_timeval - sleep end\n");
+ return;
+#else
#ifndef linux
double d, limit;
limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6;
#endif
+ thread_debug("sleep_timeval\n");
for (;;) {
int n = select(0, 0, 0, 0, &time);
if (n == 0) return;
@@ -266,6 +248,7 @@
if (time.tv_sec < 0) return;
#endif
}
+#endif
}
static void
@@ -280,7 +263,7 @@
rb_thread_wait_for(struct timeval time)
{
double date;
-
+ thread_debug("rb_thread_wait_for\n");
CSL_UNLOCK_BEGIN();
GVL_UNLOCK_BEGIN();
sleep_timeval(time);
@@ -291,8 +274,11 @@
void
yarv_thraed_schedule()
{
+ thread_debug("yarv_thraed_schedule\n");
if(GET_VM()->thread_critical == 0){
yarv_thread_t *th = GET_THREAD();
+
+ thread_debug("yarv_thraed_schedule/switch\n");
yarv_save_machine_context(th);
native_mutex_unlock(&GET_VM()->global_interpreter_lock);
native_mutex_lock(&GET_VM()->global_interpreter_lock);
@@ -300,40 +286,6 @@
}
}
-#if HAVE_PTHREAD_H
-static pthread_t time_thread;
-
-static void*
-thread_timer(void *dummy)
-{
- while(1){
-#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
- GET_VM()->interrupt_flag = 1;
- }
-}
-
-void make_timer_thread()
-{
- if(!time_thread){
- pthread_create(&time_thread, 0, thread_timer, 0);
- }
-}
-
-#else
-#error "unsupported"
-#endif /* HAVE_PTHREAD_H */
-
/********************************************************************/
static VALUE
@@ -483,8 +435,8 @@
rb_thread_keys(VALUE self)
{
yarv_thread_t *th;
- GetThreadVal(self, th);
VALUE ary = rb_ary_new();
+ GetThreadVal(self, th);
if(th->local_storage){
st_foreach(th->local_storage, thread_keys_i, ary);
@@ -530,6 +482,7 @@
rb_define_method(cYarvThread, "key?", rb_thread_key_p, 1);
rb_define_method(cYarvThread, "keys", rb_thread_keys, 0);
+ Init_native_thread();
make_timer_thread();
{
@@ -537,7 +490,7 @@
{
/* acquire global interpreter lock */
yarv_thread_lock_t *lp = &GET_VM()->global_interpreter_lock;
- yarv_thread_lock_initialize(*lp);
+ native_mutex_initialize(lp);
native_mutex_lock(lp);
}
}
Modified: trunk/thread_pthread.h
===================================================================
--- trunk/thread_pthread.h 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/thread_pthread.h 2005-10-01 14:09:59 UTC (rev 270)
@@ -8,15 +8,100 @@
#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) do { \
+#endif /* THREAD_PTHREAD_H_INCLUDED */
+
+
+/**********************************************************************/
+
+#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
+
+#define native_mutex_initialize(lock) do { \
pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER; \
- ((lock) = _lock); \
+ ((*lock) = _lock); \
} while (0)
-
#define native_cleanup_push pthread_cleanup_push
#define native_cleanup_pop pthread_cleanup_pop
+#define native_thread_join pthread_join
-#endif /* THREAD_PTHREAD_H_INCLUDED */
+static void
+Init_native_thread(){
+ /* */
+}
+
+void
+native_thread_cleanup(yarv_vm_t *vm){
+ system_working = 0;
+}
+
+NOINLINE(static int thread_start_func_2(yarv_thread_t *th, VALUE *stack_start));
+void static thread_cleanup_func(void *th_ptr);
+
+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;
+}
+
+static int
+native_thread_crteate(yarv_thread_t *th)
+{
+ pthread_attr_t attr;
+ size_t stack_size = 16 * 1024;
+ int err;
+
+ thread_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;
+}
+
+static pthread_t time_thread;
+
+static void*
+thread_timer(void *dummy)
+{
+ while(system_working){
+#ifdef HAVE_NANOSLEEP
+ struct timespec req, rem;
+
+ req.tv_sec = 0;
+ req.tv_nsec = 10 * 1000; /* 10 ms */
+ nanosleep(&req, &rem);
+#else
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000;
+ select(0, NULL, NULL, NULL, &tv);
+#endif
+ GET_VM()->interrupt_flag = 1;
+ }
+}
+
+static void
+make_timer_thread()
+{
+ if(!time_thread){
+ pthread_create(&time_thread, 0, thread_timer, 0);
+ }
+}
+
+#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
+
Added: trunk/thread_win32.h
===================================================================
--- trunk/thread_win32.h 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/thread_win32.h 2005-10-01 14:09:59 UTC (rev 270)
@@ -0,0 +1,218 @@
+
+/* interface */
+#ifndef THREAD_WIN32_H_INCLUDED
+#define THREAD_WIN32_H_INCLUDED
+
+#include <windows.h>
+
+typedef HANDLE yarv_thread_id_t;
+typedef HANDLE yarv_thread_lock_t;
+
+int native_mutex_lock(yarv_thread_lock_t *);
+int native_mutex_unlock(yarv_thread_lock_t *);
+void native_mutex_initialize(yarv_thread_lock_t *);
+
+#endif /* THREAD_WIN32_H_INCLUDED */
+
+
+
+
+
+
+/**********************************************************************/
+
+#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
+
+#include <process.h>
+
+#define WIN32_WAIT_TIMEOUT 10 /* 10 ms */
+#undef Sleep
+
+static HANDLE interrupted_event;
+
+static void
+Init_native_thread(){
+ interrupted_event
+ = CreateEvent(NULL, FALSE, FALSE, NULL);
+ GET_THREAD()->thread_id = GetCurrentThread();
+}
+
+static int system_working = 1;
+
+static int
+kill_func(st_data_t key, st_data_t val, void *dummy){
+ HANDLE thid = (HANDLE)val;
+ if(GetCurrentThread() != thid){
+ TerminateThread(thid, 0);
+ }
+ return ST_CONTINUE;
+}
+
+void
+native_thread_cleanup(yarv_vm_t *vm){
+ system_working = 0;
+ st_foreach(vm->living_threads, kill_func, 0);
+}
+
+static void
+w32_show_error_message()
+{
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL);
+
+ MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
+ exit(1);
+}
+
+static int
+w32_wait_event(HANDLE event, DWORD timeout)
+{
+ HANDLE events[2];
+ int count = 0;
+ DWORD ret;
+
+ if(event){
+ events[count++] = event;
+ }
+ events[count++] = interrupted_event;
+
+ ret = WaitForMultipleObjectsEx(count, events, FALSE, timeout, TRUE);
+ if(ret == -1){
+ w32_show_error_message();
+ }
+ if (ret == WAIT_OBJECT_0 + count - 1) {
+ errno = EINTR;
+ }
+ return ret;
+}
+
+int
+native_mutex_lock(yarv_thread_lock_t *lock){
+ DWORD result;
+
+ while(1){
+ result = w32_wait_event(*lock, INFINITE);
+ switch(result){
+ case WAIT_OBJECT_0:
+ /* get mutex object */
+ thread_debug("%p acquire mutex: %p\n", GetCurrentThreadId(), *lock);
+ return 0;
+ case WAIT_TIMEOUT:
+ /* TODO: check interrupt */
+ thread_debug("%p timeout mutex: %p\n", GetCurrentThreadId(), *lock);
+ break;
+ case WAIT_ABANDONED:
+ rb_bug("win32_mutex_lock: WAIT_ABANDONED");
+ break;
+ default:
+ rb_bug("win32_mutex_lock: unknown result (%d)", result);
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+native_mutex_unlock(yarv_thread_lock_t *lock){
+ thread_debug("%p release mutex: %p\n", GetCurrentThreadId(), *lock);
+ return ReleaseMutex(*lock);
+}
+
+void
+native_mutex_initialize(yarv_thread_lock_t *lock){
+ *lock = CreateMutex(NULL, FALSE, NULL);
+ thread_debug("%p initialize mutex: %p\n", GetCurrentThreadId(), *lock);
+}
+
+static int
+native_thread_join(yarv_thread_id_t thid, void *ptr){
+ DWORD result;
+
+ while(1){
+ result = w32_wait_event(thid, INFINITE);
+ switch(result){
+ case WAIT_OBJECT_0:
+ /* join */
+ if(ptr){
+ GetExitCodeThread(thid, ptr);
+ }
+ thread_debug("%p join to %p\n", GetCurrentThreadId(), thid);
+ return 0;
+ case WAIT_TIMEOUT:
+ /* TODO: check interrupt */
+ thread_debug("%p join timeout (to %p)\n", GetCurrentThreadId(), thid);
+ break;
+ default:
+ rb_bug("native_thread_join: unknown result (%d)", result);
+ break;
+ }
+ }
+ return 1;
+}
+
+
+NOINLINE(static int thread_start_func_2(yarv_thread_t *th, VALUE *stack_start));
+void static thread_cleanup_func(void *th_ptr);
+
+static int _stdcall
+thread_start_func_1(void *th_ptr)
+{
+ yarv_thread_t *th = th_ptr;
+ VALUE stack_start;
+ /* run */
+ thread_debug("%p (th: %p) thread created\n", GetCurrentThreadId(), th);
+ thread_start_func_2(th, &stack_start);
+ thread_cleanup_func(th);
+ thread_debug("%p (th: %p) thread deleted\n", GetCurrentThreadId(), th);
+ return 0;
+}
+
+static int
+native_thread_crteate(yarv_thread_t *th)
+{
+ size_t stack_size = 16 * 1024;
+ if((th->thread_id = (HANDLE)_beginthreadex(0, /* security */
+ stack_size,
+ thread_start_func_1,
+ th,
+ 0, /* init flag */
+ 0 /* handle */)) == 0){
+ rb_raise(rb_eThreadError, "can't create Thread (%d)", errno);
+ }
+ thread_debug("%p create: %p (th: %p), stack size: %d\n", GetCurrentThreadId(), th->thread_id, th, stack_size);
+ return 0;
+}
+
+static HANDLE timer_thread_handle = 0;
+
+static int _stdcall
+timer_thread_func(void *dummy){
+ thread_debug("timer_thread: %p\n", GetCurrentThreadId());
+ while(system_working){
+ Sleep(WIN32_WAIT_TIMEOUT);
+ GET_VM()->interrupt_flag = 1;
+ }
+ return 0;
+}
+
+static void
+make_timer_thread(){
+ if(timer_thread_handle == 0){
+ timer_thread_handle =
+ (HANDLE)_beginthreadex(0,
+ 1024,
+ timer_thread_func,
+ 0, 0, 0);
+ }
+}
+
+#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
Modified: trunk/win32/Makefile.sub
===================================================================
--- trunk/win32/Makefile.sub 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/win32/Makefile.sub 2005-10-01 14:09:59 UTC (rev 270)
@@ -120,7 +120,7 @@
CXXFLAGS = $(CFLAGS)
!endif
!if !defined(LDFLAGS)
-LDFLAGS = -link -incremental:no -debug -opt:ref -opt:icf
+LDFLAGS = -MD -link -incremental:no -debug -opt:ref -opt:icf
!endif
!if !defined(XLDFLAGS)
XLDFLAGS = -stack:$(STACK)
Modified: trunk/yarvcore.c
===================================================================
--- trunk/yarvcore.c 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/yarvcore.c 2005-10-01 14:09:59 UTC (rev 270)
@@ -61,11 +61,28 @@
#define MARK_FREE_DEBUG 0
#if MARK_FREE_DEBUG
-#define MARK_REPORT(msg) printf("mark: %s\n", msg)
+static int g_indent = 0;
+static void gc_debug_indent(){
+ int i;
+ for(i=0; i<g_indent; i++){
+ printf(" ");
+ }
+}
+void MARK_REPORT(char *msg, int st){
+ if(st == 0){
+ g_indent--;
+ }
+ gc_debug_indent();
+ printf("mark: %s\n", msg);
+ if(st){
+ g_indent++;
+ }
+}
+#define GC_INFO gc_debug_indent(); printf
#define FREE_REPORT(msg) printf("free: %s\n", msg)
-#define GC_INFO printf
+
#else
-#define MARK_REPORT(msg)
+#define MARK_REPORT(msg, st)
#define FREE_REPORT(msg)
#define GC_INFO if(0)printf
#endif
@@ -349,7 +366,7 @@
iseq_mark(void *ptr)
{
yarv_iseq_t *iseq;
- MARK_REPORT("-> iseq");
+ MARK_REPORT("-> iseq", 1);
if(ptr){
iseq = ptr;
GC_INFO("%s\n", RSTRING(iseq->name)->ptr);
@@ -365,7 +382,7 @@
MARK_UNLESS_NULL(iseq->compile_data->err_info);
}
}
- MARK_REPORT("<- iseq");
+ MARK_REPORT("<- iseq", 0);
}
static VALUE
@@ -491,22 +508,28 @@
/* VM */
/******/
+void native_thread_cleanup(void *);
+
static void vm_free(void *ptr){
FREE_REPORT("-> vm");
if(ptr){
+ yarv_vm_t *vmobj = ptr;
+
+ native_thread_cleanup(ptr);
+
+ st_free_table(vmobj->living_threads);
ruby_xfree(ptr);
}
FREE_REPORT("<- vm");
}
static void vm_mark(void *ptr){
- yarv_vm_t *vmobj;
- MARK_REPORT("-> vm");
+ MARK_REPORT("-> vm", 1);
if(ptr){
- vmobj = ptr;
- rb_gc_mark(vmobj->living_threads);
+ yarv_vm_t *vmobj = ptr;
+ /* */
}
- MARK_REPORT("<- vm");
+ MARK_REPORT("<- vm", 0);
}
static VALUE vm_alloc(VALUE klass){
@@ -542,6 +565,7 @@
static void thread_free(void *ptr){
yarv_thread_t *th;
+
FREE_REPORT("-> thread");
if(ptr){
th = ptr;
@@ -559,7 +583,7 @@
static void thread_mark(void *ptr){
yarv_thread_t *th;
- MARK_REPORT("-> thread");
+ MARK_REPORT("-> thread", 1);
if(ptr){
th = ptr;
if(th->stack){
@@ -581,14 +605,16 @@
MARK_UNLESS_NULL(th->first_proc);
MARK_UNLESS_NULL(th->first_args);
MARK_UNLESS_NULL(th->stat_insn_usage);
-
+
+ rb_mark_tbl(th->local_storage);
+
if(GET_THREAD() != th &&
th->machine_stack_start &&
th->machine_stack_end){
yarv_machine_stack_mark(th);
}
}
- MARK_REPORT("<- thread");
+ MARK_REPORT("<- thread", 0);
}
static VALUE thread_alloc(VALUE klass){
@@ -620,6 +646,8 @@
th->cfp->magic = 0;
th->status = THREAD_RUNNABLE;
+ th->local_storage = 0;
+ th->top_local_tbl = 0;
}
static VALUE
@@ -682,7 +710,7 @@
env_mark(void *ptr)
{
yarv_env_t *env;
- MARK_REPORT("-> env");
+ MARK_REPORT("-> env", 1);
if(ptr){
env = ptr;
if(env->env){
@@ -692,7 +720,7 @@
MARK_UNLESS_NULL(env->prev_envval);
MARK_UNLESS_NULL(env->block.iseq->self);
}
- MARK_REPORT("<- env");
+ MARK_REPORT("<- env", 0);
}
static VALUE
@@ -724,13 +752,13 @@
proc_mark(void *ptr)
{
yarv_proc_t *proc;
- MARK_REPORT("-> proc");
+ MARK_REPORT("-> proc", 1);
if(ptr){
proc = ptr;
MARK_UNLESS_NULL(proc->envval);
MARK_UNLESS_NULL(proc->blockprocval);
}
- MARK_REPORT("<- proc");
+ MARK_REPORT("<- proc", 0);
}
static VALUE
@@ -769,8 +797,8 @@
VALUE yarv_Integer_times();
// VALUE yarv_Hash_each();
VALUE insns_name_array();
-
VALUE Init_yarvthread();
+extern VALUE *rb_gc_stack_start;
char yarv_version[0x20];
char *yarv_options = ""
@@ -867,8 +895,8 @@
rb_define_method(cYarvProc, "call", proc_call, -1);
/* misc */
-
+
/* YARV test functions */
rb_define_global_function("once", yarv_once, 0);
@@ -936,17 +964,15 @@
/* create main thread */
vm->main_thread = rb_class_new_instance(0, 0, cYarvThread);
GetThreadVal(vm->main_thread, th);
-
+
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);
+ vm->living_threads = st_init_numtable();
+ st_insert(vm->living_threads, th->self, (st_data_t)th->thread_id);
/*
* set toplevel binding
*/
Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h 2005-09-30 15:26:58 UTC (rev 269)
+++ trunk/yarvcore.h 2005-10-01 14:09:59 UTC (rev 270)
@@ -14,8 +14,10 @@
#include "vm_opts.h"
#include "st.h"
-#if defined(HAVE_PTHREAD_H)
+#if defined(HAVE_PTHREAD_H)
#include "thread_pthread.h"
+#elif defined(_WIN32)
+#include "thread_win32.h"
#else
#error "unsupported thread type"
#endif
@@ -269,7 +271,7 @@
yarv_thread_lock_t global_interpreter_lock;
int thread_critical;
VALUE main_thread;
- VALUE living_threads;
+ st_table *living_threads;
int interrupt_flag;
} yarv_vm_t;
--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml