[前][次][番号順一覧][スレッド一覧][生データ]

yarv-diff:204

From: ko1 atdot.net
Date: 3 Feb 2006 23:33:41 -0000
Subject: [yarv-diff:204] r362 - in trunk: . test/ruby yarvtest

Author: ko1
Date: 2006-02-04 08:33:40 +0900 (Sat, 04 Feb 2006)
New Revision: 362

Added:
   trunk/yarvtest/test_thread.rb
Modified:
   trunk/ChangeLog
   trunk/common.mk
   trunk/compile.c
   trunk/eval.c
   trunk/eval_thread.c
   trunk/insns.def
   trunk/test.rb
   trunk/test/ruby/test_gc.rb
   trunk/test/ruby/test_readpartial.rb
   trunk/test/ruby/test_signal.rb
   trunk/thread.c
   trunk/thread_pthread.h
   trunk/thread_win32.h
   trunk/vm.c
   trunk/yarvcore.c
   trunk/yarvcore.h
   trunk/yarvtest/test_class.rb
Log:
	* common.mk : add dependency to yarvcore.h on signal.o

	* compile.c (iseq_compile_each) : fix [yarv-dev:795] problem
	(prohibit "break", "next" jump from eval)

	* eval.c : fix indent

	* eval_thread.c, thread.c : remove some functions and move to thread.c

	* insns.def, vm.c : fix [yarv-dev:799] and [yarv-dev:800]

	* yarvtest/test_class.rb : add a test for above

	* test/ruby/test_gc.rb : remove GC.debug_flag control

	* test/ruby/test_readpartial.rb : disable

	* test/ruby/test_signal.rb : disable

	* thread.c : fix thread_debug() and many bugs

	* thread.c (yarv_thread_s_new) : move living_threads setting

	* thread.c (yarv_thread_join) : fix

	* thread_pthread.h : add type native_thread_data_t (dummy)
	and support interrupt blocking thread

	* thread_pthread.h (native_thread_apply_priority) : added

	* thread_win32.h : add type native_thread_data_t (dummy)
	and support interrupt blocking thread

	* yarvcore.h : use win32 thread system on cygwin and fix
	some struct members

	* yarvtest/test_thread.rb : added



Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/ChangeLog	2006-02-03 23:33:40 UTC (rev 362)
@@ -4,6 +4,47 @@
 #  from Mon, 03 May 2004 01:24:19 +0900
 #
 
+2006-02-04(Sat) 08:19:50 +0900  Koichi Sasada  <ko1 atdot.net>
+
+	* common.mk : add dependency to yarvcore.h on signal.o
+
+	* compile.c (iseq_compile_each) : fix [yarv-dev:795] problem
+	(prohibit "break", "next" jump from eval)
+
+	* eval.c : fix indent
+
+	* eval_thread.c, thread.c : remove some functions and move to thread.c
+
+	* insns.def, vm.c : fix [yarv-dev:799] and [yarv-dev:800]
+
+	* yarvtest/test_class.rb : add a test for above
+
+	* test/ruby/test_gc.rb : remove GC.debug_flag control
+
+	* test/ruby/test_readpartial.rb : disable
+
+	* test/ruby/test_signal.rb : disable
+
+	* thread.c : fix thread_debug() and many bugs
+
+	* thread.c (yarv_thread_s_new) : move living_threads setting
+
+	* thread.c (yarv_thread_join) : fix
+
+	* thread_pthread.h : add type native_thread_data_t (dummy)
+	and support interrupt blocking thread
+
+	* thread_pthread.h (native_thread_apply_priority) : added
+
+	* thread_win32.h : add type native_thread_data_t (dummy)
+	and support interrupt blocking thread
+
+	* yarvcore.h : use win32 thread system on cygwin and fix
+	some struct members
+
+	* yarvtest/test_thread.rb : added
+
+
 2006-02-03(Fri) 00:08:09 +0900  Minero Aoki  <aamine loveruby.net>
 
 	* test/ruby/test_string.rb: import many tests from rubicon.

Modified: trunk/common.mk
===================================================================
--- trunk/common.mk	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/common.mk	2006-02-03 23:33:40 UTC (rev 362)
@@ -346,7 +346,7 @@
   {$(VPATH)}dln.h {$(VPATH)}node.h {$(VPATH)}util.h
 signal.$(OBJEXT): {$(VPATH)}signal.c {$(VPATH)}ruby.h config.h \
   {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
-  {$(VPATH)}rubysig.h
+  {$(VPATH)}rubysig.h {$(VPATH)}yarvcore.h
 sjis.$(OBJEXT): {$(VPATH)}sjis.c {$(VPATH)}regenc.h \
   {$(VPATH)}oniguruma.h config.h
 sprintf.$(OBJEXT): {$(VPATH)}sprintf.c {$(VPATH)}ruby.h config.h \

Modified: trunk/compile.c
===================================================================
--- trunk/compile.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/compile.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -2753,7 +2753,7 @@
     if(iseq->compile_data->redo_label != 0){
       /* while/until */
       add_ensure_iseq(ret, iseq);
-      COMPILE_(ret, "break val(while/until)", node->nd_stts,
+      COMPILE_(ret, "break val (while/until)", node->nd_stts,
                iseq->compile_data->loopval_popped);
       ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
     }
@@ -2763,6 +2763,9 @@
       COMPILE(ret, "break val (block)", node->nd_stts);
       ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x02) /* TAG_BREAK */);
     }
+    else if(iseq->type == ISEQ_TYPE_EVAL){
+      COMPILE_ERROR(("Can't escape from eval with break"));
+    }
     else{
       yarv_iseq_t *ip = iseq->parent_iseq;
       while(ip){
@@ -2797,6 +2800,9 @@
       add_ensure_iseq(ret, iseq);
       ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
     }
+    else if(iseq->type == ISEQ_TYPE_EVAL){
+      COMPILE_ERROR(("Can't escape from eval with next"));
+    }
     else{
       yarv_iseq_t *ip = iseq->parent_iseq;
       while(ip){
@@ -2842,8 +2848,7 @@
         ip = ip->parent_iseq;
       }
       if(ip != 0){
-        add_ensure_iseq(ret, iseq
-                        );
+        add_ensure_iseq(ret, iseq);
         ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x05) /* TAG_REDO */);
       }
       else{
@@ -2935,7 +2940,6 @@
     LABEL * lstart = NEW_LABEL(nd_line(node));
     LABEL * lend   = NEW_LABEL(nd_line(node));
     LABEL * lcont  = NEW_LABEL(nd_line(node));
-    VALUE prev_in_ensure = iseq->compile_data->in_ensure;
     struct ensure_range er = {lstart, lend, 0};
     struct iseq_compile_data_ensure_node_stack enl = {
       node->nd_ensr,
@@ -2944,10 +2948,8 @@
     };
     struct ensure_range *erange;
 
-    iseq->compile_data->in_ensure = Qtrue;
     COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
 
-    iseq->compile_data->in_ensure = prev_in_ensure;
     iseq->compile_data->ensure_node_stack = &enl;
     
     ADD_LABEL(ret, lstart);

Modified: trunk/eval.c
===================================================================
--- trunk/eval.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/eval.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -985,7 +985,7 @@
 void
 rb_interrupt()
 {
-    rb_raise(rb_eInterrupt, "");
+  rb_raise(rb_eInterrupt, "");
 }
 
 /*

Modified: trunk/eval_thread.c
===================================================================
--- trunk/eval_thread.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/eval_thread.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -370,23 +370,6 @@
   return 0;
 }
 
-static const char *
-thread_status_name(status)
-    enum yarv_thread_status status;
-{
-  switch (status) {
-  case THREAD_RUNNABLE:
-    return "run";
-  case THREAD_STOPPED:
-    return "sleep";
-  case THREAD_TO_KILL:
-    return "aborting";
-  case THREAD_KILLED:
-    return "dead";
-  default:
-    return "unknown";
-  }
-}
 
 /* Return the current time as a floating-point number */
 static double
@@ -415,8 +398,6 @@
   return &dummy;
 }
 
-static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));
-
 static VALUE th_raise_exception;
 static NODE *th_raise_node;
 static VALUE th_cmd;
@@ -622,13 +603,6 @@
     th->next->prev = th->prev;
 }
 
-static int
-rb_thread_dead(th)
-    rb_thread_t th;
-{
-    return th->status == THREAD_KILLED;
-}
-
 void
 rb_thread_fd_close(fd)
     int fd;
@@ -743,28 +717,7 @@
   /* UNSUPPORTED(rb_thread_schedule); */
 }
 
-void
-rb_thread_wait_fd(int fd)
-{
-  
-  return;
-}
-
 int
-rb_thread_fd_writable(int fd)
-{
-  // TODO: fix me
-  return Qfalse;
-}
-
-int
-rb_thread_alone()
-{
-  // TODO: fix me
-  return 1;
-}
-
-int
 rb_thread_select(max, read, write, except, timeout)
     int max;
     fd_set *read, *write, *except;
@@ -856,315 +809,6 @@
 
 /*
  *  call-seq:
- *     Thread.main   => thread
- *  
- *  Returns the main thread for the process.
- *     
- *     Thread.main   #=> #<Thread:0x401bdf4c run>
- */
-
-VALUE
-rb_thread_main()
-{
-    return main_thread->thread;
-}
-
-
-/*
- *  call-seq:
- *     Thread.list   => array
- *  
- *  Returns an array of <code>Thread</code> objects for all threads that are
- *  either runnable or stopped.
- *     
- *     Thread.new { sleep(200) }
- *     Thread.new { 1000000.times {|i| i*i } }
- *     Thread.new { Thread.stop }
- *     Thread.list.each {|t| p t}
- *     
- *  <em>produces:</em>
- *     
- *     #<Thread:0x401b3e84 sleep>
- *     #<Thread:0x401b3f38 run>
- *     #<Thread:0x401b3fb0 sleep>
- *     #<Thread:0x401bdf4c run>
- */
-
-VALUE
-rb_thread_list()
-{
-    rb_thread_t th;
-    VALUE ary = rb_ary_new();
-
-    FOREACH_THREAD(th) {
-	switch (th->status) {
-	  case THREAD_RUNNABLE:
-	  case THREAD_STOPPED:
-	  case THREAD_TO_KILL:
-	    rb_ary_push(ary, th->thread);
-	  default:
-	    break;
-	}
-    }
-    END_FOREACH(th);
-
-    return ary;
-}
-
-
-/*
- *  call-seq:
- *     thr.wakeup   => thr
- *  
- *  Marks <i>thr</i> as eligible for scheduling (it may still remain blocked on
- *  I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>).
- *     
- *     c = Thread.new { Thread.stop; puts "hey!" }
- *     c.wakeup
- *     
- *  <em>produces:</em>
- *     
- *     hey!
- */
-
-VALUE
-rb_thread_wakeup(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (th->status == THREAD_KILLED)
-	rb_raise(rb_eThreadError, "killed thread");
-    rb_thread_ready(th);
-
-    return thread;
-}
-
-
-/*
- *  call-seq:
- *     thr.run   => thr
- *  
- *  Wakes up <i>thr</i>, making it eligible for scheduling. If not in a critical
- *  section, then invokes the scheduler.
- *     
- *     a = Thread.new { puts "a"; Thread.stop; puts "c" }
- *     Thread.pass
- *     puts "Got here"
- *     a.run
- *     a.join
- *     
- *  <em>produces:</em>
- *     
- *     a
- *     Got here
- *     c
- */
-
-VALUE
-rb_thread_run(thread)
-    VALUE thread;
-{
-    rb_thread_wakeup(thread);
-    if (!rb_thread_critical) rb_thread_schedule();
-
-    return thread;
-}
-
-
-/*
- *  call-seq:
- *     thr.exit        => thr or nil
- *     thr.kill        => thr or nil
- *     thr.terminate   => thr or nil
- *  
- *  Terminates <i>thr</i> and schedules another thread to be run. If this thread
- *  is already marked to be killed, <code>exit</code> returns the
- *  <code>Thread</code>. If this is the main thread, or the last thread, exits
- *  the process.
- */
-
-VALUE
-rb_thread_kill(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (th != curr_thread && th->safe < 4) {
-	rb_secure(4);
-    }
-    if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
-	return thread;
-    if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS);
-
-    rb_thread_ready(th);
-    th->status = THREAD_TO_KILL;
-    if (!rb_thread_critical) rb_thread_schedule();
-    return thread;
-}
-
-
-/*
- *  call-seq:
- *     Thread.kill(thread)   => thread
- *  
- *  Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>).
- *     
- *     count = 0
- *     a = Thread.new { loop { count += 1 } }
- *     sleep(0.1)       #=> 0
- *     Thread.kill(a)   #=> #<Thread:0x401b3d30 dead>
- *     count            #=> 93947
- *     a.alive?         #=> false
- */
-
-static VALUE
-rb_thread_s_kill(obj, th)
-    VALUE obj, th;
-{
-    return rb_thread_kill(th);
-}
-
-
-/*
- *  call-seq:
- *     Thread.exit   => thread
- *  
- *  Terminates the currently running thread and schedules another thread to be
- *  run. If this thread is already marked to be killed, <code>exit</code>
- *  returns the <code>Thread</code>. If this is the main thread, or the last
- *  thread, exit the process.
- */
-
-static VALUE
-rb_thread_exit()
-{
-    return rb_thread_kill(curr_thread->thread);
-}
-
-
-/*
- *  call-seq:
- *     Thread.stop   => nil
- *  
- *  Stops execution of the current thread, putting it into a ``sleep'' state,
- *  and schedules execution of another thread. Resets the ``critical'' condition
- *  to <code>false</code>.
- *     
- *     a = Thread.new { print "a"; Thread.stop; print "c" }
- *     Thread.pass
- *     print "b"
- *     a.run
- *     a.join
- *     
- *  <em>produces:</em>
- *     
- *     abc
- */
-
-VALUE
-rb_thread_stop()
-{
-    enum yarv_thread_status last_status = THREAD_RUNNABLE;
-
-    rb_thread_critical = 0;
-    if (curr_thread == curr_thread->next) {
-	rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever");
-    }
-    if (curr_thread->status == THREAD_TO_KILL)
-	last_status = THREAD_TO_KILL;
-    curr_thread->status = THREAD_STOPPED;
-    rb_thread_schedule();
-    curr_thread->status = last_status;
-
-    return Qnil;
-}
-
-struct timeval rb_time_timeval();
-
-void
-rb_thread_polling()
-{
-    if (curr_thread != curr_thread->next) {
-	curr_thread->status = THREAD_STOPPED;
-	curr_thread->delay = timeofday() + (double)0.06;
-	curr_thread->wait_for = WAIT_TIME;
-	rb_thread_schedule();
-    }
-}
-
-void
-rb_thread_sleep(sec)
-    int sec;
-{
-    if (curr_thread == curr_thread->next) {
-	TRAP_BEG;
-	sleep(sec);
-	TRAP_END;
-	return;
-    }
-    rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
-}
-
-
-/*
- *  call-seq:
- *     thr.priority   => integer
- *  
- *  Returns the priority of <i>thr</i>. Default is zero; higher-priority threads
- *  will run before lower-priority threads.
- *     
- *     Thread.current.priority   #=> 0
- */
-
-static VALUE
-rb_thread_priority(thread)
-    VALUE thread;
-{
-    return INT2NUM(rb_thread_check(thread)->priority);
-}
-
-
-/*
- *  call-seq:
- *     thr.priority= integer   => thr
- *  
- *  Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
- *  will run before lower-priority threads.
- *     
- *     count1 = count2 = 0
- *     a = Thread.new do
- *           loop { count1 += 1 }
- *         end
- *     a.priority = -1
- *     
- *     b = Thread.new do
- *           loop { count2 += 1 }
- *         end
- *     b.priority = -2
- *     sleep 1   #=> 1
- *     Thread.critical = 1
- *     count1    #=> 622504
- *     count2    #=> 5832
- */
-
-static VALUE
-rb_thread_priority_set(thread, prio)
-    VALUE thread, prio;
-{
-    rb_thread_t th;
-
-    rb_secure(4);
-    th = rb_thread_check(thread);
-
-    th->priority = NUM2INT(prio);
-    rb_thread_schedule();
-    return prio;
-}
-
-
-/*
- *  call-seq:
  *     thr.safe_level   => integer
  *  
  *  Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
@@ -1617,114 +1261,6 @@
 }
 
 
-/*
- *  call-seq:
- *     thr.value   => obj
- *  
- *  Waits for <i>thr</i> to complete (via <code>Thread#join</code>) and returns
- *  its value.
- *     
- *     a = Thread.new { 2 + 2 }
- *     a.value   #=> 4
- */
-
-static VALUE
-rb_thread_value(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    while (!rb_thread_join(th, DELAY_INFTY));
-
-    return th->result;
-}
-
-
-/*
- *  call-seq:
- *     thr.status   => string, false or nil
- *  
- *  Returns the status of <i>thr</i>: ``<code>sleep</code>'' if <i>thr</i> is
- *  sleeping or waiting on I/O, ``<code>run</code>'' if <i>thr</i> is executing,
- *  ``<code>aborting</code>'' if <i>thr</i> is aborting, <code>false</code> if
- *  <i>thr</i> terminated normally, and <code>nil</code> if <i>thr</i>
- *  terminated with an exception.
- *     
- *     a = Thread.new { raise("die now") }
- *     b = Thread.new { Thread.stop }
- *     c = Thread.new { Thread.exit }
- *     d = Thread.new { sleep }
- *     Thread.critical = true
- *     d.kill                  #=> #<Thread:0x401b3678 aborting>
- *     a.status                #=> nil
- *     b.status                #=> "sleep"
- *     c.status                #=> false
- *     d.status                #=> "aborting"
- *     Thread.current.status   #=> "run"
- */
-
-static VALUE
-rb_thread_status(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (rb_thread_dead(th)) {
-	if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED))
-	    return Qnil;
-	return Qfalse;
-    }
-
-    return rb_str_new2(thread_status_name(th->status));
-}
-
-
-/*
- *  call-seq:
- *     thr.alive?   => true or false
- *  
- *  Returns <code>true</code> if <i>thr</i> is running or sleeping.
- *     
- *     thr = Thread.new { }
- *     thr.join                #=> #<Thread:0x401b3fb0 dead>
- *     Thread.current.alive?   #=> true
- *     thr.alive?              #=> false
- */
-
-static VALUE
-rb_thread_alive_p(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (rb_thread_dead(th)) return Qfalse;
-    return Qtrue;
-}
-
-
-/*
- *  call-seq:
- *     thr.stop?   => true or false
- *  
- *  Returns <code>true</code> if <i>thr</i> is dead or sleeping.
- *     
- *     a = Thread.new { Thread.stop }
- *     b = Thread.current
- *     a.stop?   #=> true
- *     b.stop?   #=> false
- */
-
-static VALUE
-rb_thread_stop_p(thread)
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (rb_thread_dead(th)) return Qtrue;
-    if (th->status == THREAD_STOPPED) return Qtrue;
-    return Qfalse;
-}
-
 void
 rb_thread_wait_other_threads()
 {
@@ -1781,179 +1317,9 @@
 rb_thread_interrupt()
 {
   rb_interrupt();
-  // TODO: fix me
-  
-  /*
-    rb_thread_critical = 0;
-    rb_thread_ready(main_thread);
-    if (curr_thread == main_thread) {
-	rb_interrupt();
-    }
-    if (!rb_thread_dead(curr_thread)) {
-	if (THREAD_SAVE_CONTEXT(curr_thread)) {
-	    return;
-	}
-    }
-    curr_thread = main_thread;
-    rb_thread_restore_context(curr_thread, RESTORE_INTERRUPT);
-   */
 }
 
 void
-rb_thread_signal_raise(const char *sig)
-{
-    if (sig == 0) return;	/* should not happen */
-    rb_thread_critical = 0;
-    if (curr_thread == main_thread) {
-	rb_thread_ready(curr_thread);
-	rb_raise(rb_eSignal, "SIG%s", sig);
-    }
-    rb_thread_ready(main_thread);
-    if (!rb_thread_dead(curr_thread)) {
-	if (THREAD_SAVE_CONTEXT(curr_thread)) {
-	    return;
-	}
-    }
-    th_signm = (char *)sig;
-    curr_thread = main_thread;
-    rb_thread_restore_context(curr_thread, RESTORE_SIGNAL);
-}
-
-void
-rb_thread_trap_eval(cmd, sig, safe)
-    VALUE cmd;
-    int sig, safe;
-{
-    rb_thread_critical = 0;
-    if (curr_thread == main_thread) {
-	rb_trap_eval(cmd, sig, safe);
-	return;
-    }
-    if (!rb_thread_dead(curr_thread)) {
-	if (THREAD_SAVE_CONTEXT(curr_thread)) {
-	    return;
-	}
-    }
-    th_cmd = cmd;
-    th_sig = sig;
-    th_safe = safe;
-    curr_thread = main_thread;
-    rb_thread_restore_context(curr_thread, RESTORE_TRAP);
-}
-
-void
-rb_thread_signal_exit()
-{
-    VALUE args[2];
-
-    rb_thread_critical = 0;
-    if (curr_thread == main_thread) {
-	rb_thread_ready(curr_thread);
-	rb_exit(EXIT_SUCCESS);
-    }
-    args[0] = INT2NUM(EXIT_SUCCESS);
-    args[1] = rb_str_new2("exit");
-    rb_thread_ready(main_thread);
-    if (!rb_thread_dead(curr_thread)) {
-	if (THREAD_SAVE_CONTEXT(curr_thread)) {
-	    return;
-	}
-    }
-    rb_thread_main_jump(rb_class_new_instance(2, args, rb_eSystemExit), 
-			RESTORE_EXIT);
-}
-
-static VALUE
-rb_thread_raise(argc, argv, th)
-    int argc;
-    VALUE *argv;
-    rb_thread_t th;
-{
-    volatile rb_thread_t th_save = th;
-    VALUE exc;
-
-    if (!th->next) {
-	rb_raise(rb_eArgError, "unstarted thread");
-    }
-    if (rb_thread_dead(th)) return Qnil;
-    exc = rb_make_exception(argc, argv);
-    if (curr_thread == th) {
-	rb_raise_jump(exc);
-    }
-
-    if (!rb_thread_dead(curr_thread)) {
-	if (THREAD_SAVE_CONTEXT(curr_thread)) {
-	    return th_save->thread;
-	}
-    }
-
-    rb_thread_ready(th);
-    curr_thread = th;
-
-    th_raise_exception = exc;
-    th_raise_node = ruby_current_node;
-    rb_thread_restore_context(curr_thread, RESTORE_RAISE);
-    return Qnil;		/* not reached */
-}
-
-
-/*
- *  call-seq:
- *     thr.raise(exception)
- *  
- *  Raises an exception (see <code>Kernel::raise</code>) from <i>thr</i>. The
- *  caller does not have to be <i>thr</i>.
- *     
- *     Thread.abort_on_exception = true
- *     a = Thread.new { sleep(200) }
- *     a.raise("Gotcha")
- *     
- *  <em>produces:</em>
- *     
- *     prog.rb:3: Gotcha (RuntimeError)
- *     	from prog.rb:2:in `initialize'
- *     	from prog.rb:2:in `new'
- *     	from prog.rb:2
- */
-
-static VALUE
-rb_thread_raise_m(argc, argv, thread)
-    int argc;
-    VALUE *argv;
-    VALUE thread;
-{
-    rb_thread_t th = rb_thread_check(thread);
-
-    if (ruby_safe_level > th->safe) {
-	rb_secure(4);
-    }
-    rb_thread_raise(argc, argv, th);
-    return Qnil;		/* not reached */
-}
-
-/*
- * call-seq:
- *   thr.inspect   => string
- *
- * Dump the name, id, and status of _thr_ to a string.
- */
-
-static VALUE
-rb_thread_inspect(thread)
-    VALUE thread;
-{
-    char *cname = rb_obj_classname(thread);
-    rb_thread_t th = rb_thread_check(thread);
-    const char *status = thread_status_name(th->status);
-    VALUE str;
-
-    str = rb_sprintf("#<%s:%p %s>", cname, (void*)thread, status);
-    OBJ_INFECT(str, thread);
-
-    return str;
-}
-
-void
 rb_thread_atfork()
 {
     rb_thread_t th;
@@ -2271,46 +1637,17 @@
     rb_cThread = rb_define_class("Thread", rb_cObject);
     rb_undef_alloc_func(rb_cThread);
 
-    rb_define_singleton_method(rb_cThread, "new", rb_thread_s_new, -1);
-    rb_define_method(rb_cThread, "initialize", rb_thread_initialize, -2);
-    rb_define_singleton_method(rb_cThread, "start", rb_thread_start, -2);
-    rb_define_singleton_method(rb_cThread, "fork", rb_thread_start, -2);
-
-    rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
-    rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
-    rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
-    rb_define_singleton_method(rb_cThread, "pass", rb_thread_pass, 0);
-    rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0);
-    rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0);
-    rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
-
     rb_define_singleton_method(rb_cThread, "critical", rb_thread_critical_get, 0);
     rb_define_singleton_method(rb_cThread, "critical=", rb_thread_critical_set, 1);
 
     rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
     rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
 
-    rb_define_method(rb_cThread, "run", rb_thread_run, 0);
-    rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
-    rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "value", rb_thread_value, 0);
-    rb_define_method(rb_cThread, "status", rb_thread_status, 0);
-    rb_define_method(rb_cThread, "join", rb_thread_join_m, -1);
-    rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
-    rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
-    rb_define_method(rb_cThread, "raise", rb_thread_raise_m, -1);
-
     rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
     rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
-
-    rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
-    rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
     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, "inspect", rb_thread_inspect, 0);
 
     rb_cCont = rb_define_class("Continuation", rb_cObject);
     rb_undef_alloc_func(rb_cCont);

Modified: trunk/insns.def
===================================================================
--- trunk/insns.def	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/insns.def	2006-02-03 23:33:40 UTC (rev 362)
@@ -1092,13 +1092,14 @@
 
   /* find klass */
   if(rb_const_defined_at(cbase, id)){
+    /* already exist */
     klass = rb_const_get_at(cbase, id);
     if (TYPE(klass) != T_CLASS) {
       rb_raise(rb_eTypeError, "%s is not a class",
                rb_id2name(id));
     }
+    
     if(super != rb_cObject){
-      /* type check */
       VALUE tmp;
       tmp = rb_class_real(RCLASS(klass)->super);
 
@@ -1188,12 +1189,13 @@
   if(rb_const_defined_at(mbase, id)){
     module = rb_const_get_at(mbase, id);
     /* already exist */
-    
-    /* type check */
-    
+    if (TYPE(module) != T_MODULE) {
+      rb_raise(rb_eTypeError, "%s is not a module",
+               rb_id2name(id));
+    }
   }
   else{
-    /* new class declaration */
+    /* new module declaration */
     module = rb_define_module_id(id);
     rb_set_class_path(module, mbase, rb_id2name(id));
     rb_const_set(mbase, id, module);
@@ -1590,7 +1592,7 @@
       th->state = GET_THROWOBJ_STATE(err);
     }
     else{
-      th->state = rb_ivar_get(err, idThrowState);
+      th->state = FIX2INT(rb_ivar_get(err, idThrowState));
     }
     return err;
   }

Modified: trunk/test/ruby/test_gc.rb
===================================================================
--- trunk/test/ruby/test_gc.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/test/ruby/test_gc.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -8,7 +8,7 @@
   end
 
   def test_gc
-    GC.debug_flag = false
+    # GC.debug_flag = false
     
     assert_nothing_raised do
       1.upto(10000) {
@@ -29,6 +29,6 @@
     GC.start
     assert true   # reach here or dumps core
 
-    GC.debug_flag = true
+    # GC.debug_flag = true
   end
 end

Modified: trunk/test/ruby/test_readpartial.rb
===================================================================
--- trunk/test/ruby/test_readpartial.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/test/ruby/test_readpartial.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -2,7 +2,7 @@
 require 'timeout'
 #require 'fcntl'
 
-class TestReadPartial < Test::Unit::TestCase
+class TestReadPartial # < Test::Unit::TestCase
   def make_pipe
     r, w = IO.pipe
     begin

Modified: trunk/test/ruby/test_signal.rb
===================================================================
--- trunk/test/ruby/test_signal.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/test/ruby/test_signal.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -1,7 +1,7 @@
 require 'test/unit'
 require 'timeout'
 
-class TestSignal < Test::Unit::TestCase
+class TestSignal # < Test::Unit::TestCase
   def have_fork?
     begin
       fork{}

Modified: trunk/test.rb
===================================================================
--- trunk/test.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/test.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -1,25 +1,318 @@
+t = Thread.new{
+  Thread.stop
+}
+sleep 0.1
+
+p Thread.list
+t.run
+__END__
+
+t = Thread.new{
+  sleep
+}
+Thread.pass
+#sleep 0.1
+t.join
+
+__END__
+
+begin
+  t.join
+  :ng
+rescue
+  :ok
+end
+
+__END__
+
+t = Thread.new{
+        sleep
+      }z
+      sleep 1
+      p st = t.status
+      t.kill
+__END__
+
+t = Thread.new{
+      }
+      t.raise("foo")
+      t.raise("bar")
+p      begin
+        p t
+        t.join
+        :ng
+      rescue => e
+        e.message
+      end
+__END__
+
+t = Thread.new{
+  sleep
+}
+t.raise "Foo"
+
+p begin
+    t.join
+    :ng
+  rescue
+    :ok
+  end
+
+__END__
+Thread.new{
+  sleep 
+}
+Thread.pass
+
+__END__
+require 'timeout'
+
+timeout(1){
+  sleep
+}
+
+__END__
+
+t = Thread.new{
+  sleep 1
+}
+#sleep 1
+t.join
+p :ok
+__END__
+
+
+t = Thread.new{
+  p 1
+}
+sleep 0.1
+t.join
+p 2
+__END__
+p 2
+sleep 1
+p 3
+__END__
+
+Thread.new{
+  sleep 0.1
+}.join
+p 1
+sleep 1
+__END__
+require 'timeout'
+timeout(1){
+  p :ok
+  #sleep
+}
+p :ok
+sleep 2
+#sleep 2
+__END__
+
+t = Thread.new{
+  begin
+    sleep
+  ensure
+    p :ok
+  end
+}
+sleep 1
+t.kill
+t.join
+__END__
+
+require 'timeout'
+
+timeout(1){
+}
+
+
+
+begin
+  r, w = IO.pipe
+  r0, w0 = IO.pipe
+  pid = fork {
+    trap(:USR1, "EXIT")
+    w0.close
+    w.syswrite("a")
+    p r0.sysread(20)
+  }
+  p r.sysread(1)
+  sleep 0.1
+  
+  1.times{
+    Process.kill(:USR1, pid)
+    begin
+      Timeout.timeout(1) {
+        Process.waitpid pid
+      }
+    rescue Timeout::Error
+      Process.kill(:TERM, pid)
+      raise
+    end
+  }
+ensure
+  r.close
+  w.close
+  r0.close
+  w0.close
+end
+
+__END__
+require 'timeout'
+
+begin
+  timeout(1){
+    sleep
+  }
+rescue Timeout::Error => e
+  p e
+end
+
+
+__END__
+
+begin
+        B = 1
+        module B
+          p B
+        end
+      rescue TypeError => e
+        p e.message
+      end
+
+__END__
+p 1
+
+__END__
+
+t = Thread.new{
+  begin
+    sleep 3
+  rescue Exception => e
+    p :ok, e
+  end
+  p :exit
+}
+
+Thread.pass
+sleep 1
+#t.raise
+t.join
+
+__END__
+
+t = Thread.new{
+  Thread.pass
+  Thread.main.raise
+  p :exit
+}
+
+begin
+  sleep
+rescue Exception => e
+  p :ok, e
+end
+
+__END__
+
+$v = true
+$n1 = 0
+$n2 = 0
+
+t1 = Thread.new{
+  while $v
+    $n1 += 1
+  end
+}
+t2 = Thread.new{
+  while $v
+    $n2 += 1
+  end
+}
+
+
+t1.priority = -10
+
+sleep 3
+$v = false
+t1.join; t2.join
+p [$n1, $n2]
+
+
+__END__
+while true
+  p 1
+end
+
+
+__END__
+1.times{
+  eval("break")
+  p :ng
+}
+
+__END__
+
 class A
+  Const = 1
   class B
-    def a_method
-      def nested_method
-        p "nested_method"
-      end
-      nested_method
+    class C
+      p Const
     end
   end
+end
+__END__
 
-  def test_method
-    instance_eval("B.new.a_method")
-#    eval("B.new.a_method")
-#    B.new.a_method
+module M
+  class C
   end
 end
 
-A.new.test_method
+module Foo
+class C
+  include M
+  p C
+end
+end
 
 __END__
 
+module M
+  class A
+    def hoge
+      p "hoge"
+    end
+  end
+end
+
 class A
+  include M
+  def initialize
+    A.new.hoge
+    instance_eval("A.new.hoge")
+  end
+end
+
+
+__END__
+
+
+class A
+  def m
+    def m2
+      p :m2
+    end
+    m2()
+  end
+end
+
+instance_eval('A.new.m')
+
+__END__
+
+class A
   class B
     def a_method
       def nested_method

Modified: trunk/thread.c
===================================================================
--- trunk/thread.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/thread.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -42,17 +42,15 @@
 
 #define THREAD_DEBUG 0
 
-#if THREAD_DEBUG
-#define thread_debug printf
-#else
-#define thread_debug if(0)printf
-#endif
-
 static void sleep_for_polling();
-static void sleep_timeval(struct timeval time);
+static void sleep_timeval(yarv_thread_t *th, struct timeval time);
 static double timeofday();
 struct timeval rb_time_interval(VALUE);
+static int rb_thread_dead(yarv_thread_t *th);
 
+static void yarv_add_signal_thread_list(yarv_thread_t *th);
+static void yarv_remove_signal_thread_list(yarv_thread_t *th);
+
 inline static void
 st_delete_wrap(st_table *table, VALUE key){
   st_delete(table, (st_data_t *)&key, 0);
@@ -61,19 +59,76 @@
 /********************************************************************************/
 
 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
-#if HAVE_PTHREAD_H
+
+#if THREAD_DEBUG
+void thread_debug(const char*fmt, ...);
+#else
+#define thread_debug if(0)printf
+#endif
+
+#if   defined(_WIN32) || defined(__CYGWIN__)
+#include "thread_win32.h"
+
+#define DEBUG_OUT() \
+  WaitForSingleObject(debug_mutex, INFINITE); \
+  printf("%8p - %s", GetCurrentThreadId(), buf); \
+  ReleaseMutex(debug_mutex);
+
+#elif defined(HAVE_PTHREAD_H)
 #include "thread_pthread.h"
-#elif _WIN32
-#include "thread_win32.h"
+
+#define DEBUG_OUT() \
+  pthread_mutex_lock(&debug_mutex); \
+  printf("%8p - %s", pthread_self(), buf); \
+  pthread_mutex_unlock(&debug_mutex);
+
 #else
-#error "unsupported thread"
+#error "unsupported thread type"
 #endif
 
-VALUE th_eval_body(yarv_thread_t *th);
+#if THREAD_DEBUG
+static int debug_mutex_initialized = 1;
+static yarv_thread_lock_t debug_mutex;
 
 void
-static thread_cleanup_func(void *th_ptr)
+thread_debug(const char*fmt, ...)
 {
+  va_list args;
+  char buf[BUFSIZ];
+
+  if(debug_mutex_initialized == 1){
+    debug_mutex_initialized = 0;
+    native_mutex_initialize(&debug_mutex);
+  }
+  
+  va_start(args,fmt);
+  vsnprintf(buf, BUFSIZ, fmt, args);
+  va_end(args);
+
+  DEBUG_OUT();
+}
+#endif
+
+
+#define GVL_UNLOCK_RANGE(exec) do { \
+  yarv_thread_t *__th = GET_THREAD(); \
+  int __prev_status = __th->status; \
+  __th->status = THREAD_STOPPED; \
+  YARV_CHECK_INTS(); \
+  GVL_UNLOCK_BEGIN(); {\
+  exec; \
+  } \
+  GVL_UNLOCK_END(); \
+  yarv_remove_signal_thread_list(__th); \
+  __th->status = __prev_status; \
+  YARV_CHECK_INTS(); \
+} while(0)
+
+VALUE th_eval_body(yarv_thread_t *th);
+
+static void
+thread_cleanup_func(void *th_ptr)
+{
   yarv_thread_t *th = th_ptr;
   st_delete_wrap(GET_VM()->living_threads, th->self);
   th->status = THREAD_KILLED;
@@ -90,7 +145,7 @@
 
   th->machine_stack_start = stack_start;
   
-  thread_debug("start: %p\n", th);
+  thread_debug("thread start: %p\n", th);
   
   GVL_LOCK_BEGIN();
   {
@@ -107,7 +162,7 @@
     }
     TH_POP_TAG();
     th->status = THREAD_KILLED;
-    thread_debug("end: %p\n", th);
+    thread_debug("thread end: %p\n", th);
     st_delete_wrap(GET_VM()->living_threads, th->self);
   }
   GVL_LOCK_END();
@@ -124,7 +179,6 @@
   /* create thread object */
   thval= rb_class_new_instance(0, 0, cYarvThread);
   GetThreadVal(thval, th);
-  st_insert(GET_VM()->living_threads, thval, (st_data_t)th->thread_id);
   
   /* setup thread environment */
   th->first_args = args;
@@ -132,6 +186,7 @@
 
   /* kick thread */
   native_thread_create(th);
+  st_insert(GET_VM()->living_threads, thval, (st_data_t)th->thread_id);
   return thval;
 }
 
@@ -140,29 +195,39 @@
 {
   yarv_thread_t *cur_th = GET_THREAD();
   yarv_thread_t *th;
-  int err;
+  int err, lerrno;
 
   GetThreadVal(self, th);
   cur_th->wait_thread_value = self;
 
 again:
   if(argc == 0){
-    thread_debug("yarv_thread_join(0)\n");
+    thread_debug("yarv_thread_join (thid: %p)\n", th->thread_id);
 
-    GVL_UNLOCK_BEGIN();
-    {
-      err = native_thread_join(th->thread_id, 0);
-    }
-    GVL_UNLOCK_END();
+    GVL_UNLOCK_RANGE(
+      err = native_thread_join(cur_th, th->thread_id, 0);
+      lerrno = errno;
+      );
 
-    if(errno == EINTR){
+    switch(lerrno){
+    case EINTR:
+      thread_debug("yarv_thread_join: interrupted (thid: %p)\n",
+                   th->thread_id);
       goto again;
-    }
-
-    switch(err){
     case EDEADLK:
       cur_th->wait_thread_value = Qnil;
       rb_raise(rb_eThreadError, "can't join current thread (cause dead lock)");
+      break;
+    case EINVAL:
+      /* already terminated */
+      if(th->status == THREAD_KILLED){
+        thread_debug("yarv_thread_join: already terminated (thid: %p)\n",
+                      th->thread_id);
+        break;
+      }
+      else{
+        rb_bug("yarv_thread_join: EINVAL");
+      }
     }
   }
   else if(argc == 1){
@@ -174,12 +239,8 @@
     limit += interval.tv_usec * 1e-6;
 
     while(1){
-      GVL_UNLOCK_BEGIN();
-      {
-        sleep_for_polling();
-      }
-      GVL_UNLOCK_END();
-
+      GVL_UNLOCK_RANGE(sleep_for_polling());
+      
       if(th->status == THREAD_KILLED){
         break;
       }
@@ -202,6 +263,17 @@
   return self;
 }
 
+/*
+ *  call-seq:
+ *     thr.value   => obj
+ *  
+ *  Waits for <i>thr</i> to complete (via <code>Thread#join</code>) and returns
+ *  its value.
+ *     
+ *     a = Thread.new { 2 + 2 }
+ *     a.value   #=> 4
+ */
+
 static VALUE
 yarv_thread_value(VALUE self)
 {
@@ -216,23 +288,22 @@
  * Thread Scheduling
  */
 
-#if !defined HAVE_PAUSE
-# if defined _WIN32 && !defined __CYGWIN__
-#  define pause() Sleep(INFINITE)
+#if !defined(HAVE_PAUSE) || defined(__CYGWIN__)
+# if defined(_WIN32) || defined(__CYGWIN__)
+#  define pause(th) w32_sleep(th, INFINITE)
 # else
-#  define pause() sleep(0x7fffffff)
+#  define pause(th) sleep(0x7fffffff)
 # endif
+#else
+#define pause(th) pause()
 #endif
 
 void
 rb_thread_sleep_forever()
 {
+  yarv_thread_t *th = GET_THREAD();
   thread_debug("rb_thread_sleep_forever\n");
-  GVL_UNLOCK_BEGIN();
-  {
-    pause();
-  }
-  GVL_UNLOCK_END();
+  GVL_UNLOCK_RANGE(pause(th));
 }
 
 static double
@@ -244,12 +315,12 @@
 }
 
 static void
-sleep_timeval(struct timeval time)
+sleep_timeval(yarv_thread_t *th, struct timeval time)
 {
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
   DWORD limit = time.tv_sec * 1000 + time.tv_usec / 1000;
   thread_debug("sleep_timeval - sleep start\n");
-  Sleep(limit);
+  w32_sleep(th, limit);
   thread_debug("sleep_timeval - sleep end\n");
   return;
 #else
@@ -288,37 +359,46 @@
 }
 
 static void
-sleep_for_polling(){
+sleep_for_polling(yarv_thread_t *th){
   struct timeval time;
   time.tv_sec  = 0;
   time.tv_usec = 100000; /* 0.1 sec */
-  sleep_timeval(time);
+  sleep_timeval(th, time);
 }
 
 void
 rb_thread_wait_for(struct timeval time)
 {
-  double date;
+  yarv_thread_t *th = GET_THREAD();
   thread_debug("rb_thread_wait_for\n");
-  CSL_UNLOCK_BEGIN();
-  {
-    GVL_UNLOCK_BEGIN();
-    {
-      sleep_timeval(time);
-    }
-    GVL_UNLOCK_END();
+  GVL_UNLOCK_RANGE(sleep_timeval(th, time));
+}
+
+void
+rb_thread_polling(void)
+{
+  if(!rb_thread_alone()){
+    yarv_thread_t *th = GET_THREAD();
+    GVL_UNLOCK_RANGE(sleep_for_polling(th));
   }
-  CSL_UNLOCK_END();
 }
 
+struct timeval rb_time_timeval();
+
 void
+rb_thread_sleep(int sec)
+{
+  rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
+}
+
+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");
+    thread_debug("yarv_thraed_schedule/switch start\n");
     yarv_save_machine_context(th);
     native_mutex_unlock(&GET_VM()->global_interpreter_lock);
     {
@@ -327,9 +407,12 @@
     }
     native_mutex_lock(&GET_VM()->global_interpreter_lock);
     yarv_set_current_running_thread(th);
+    thread_debug("yarv_thraed_schedule/switch done (thid: %p)\n",
+                 th->thread_id);
   }
 }
 
+
 /*
  *  call-seq:
  *     Thread.pass   => nil
@@ -364,27 +447,50 @@
 
 void rb_signal_exec(yarv_thread_t *th, int sig);
 
+static VALUE eKillSignal = 1;
+
 void
 yarv_thread_execute_interrupts(yarv_thread_t *th)
 {
-  th->interrupt_flag = 0;
   
-  /* signal handling */
-  while(th->signal_queue.head != th->signal_queue.tail){
-    int sig = th->signal_queue.buff[th->signal_queue.tail];
-    th->signal_queue.tail = (th->signal_queue.tail + 1) % RUBY_SIGNAL_QUEUE_MAX;
-    rb_signal_exec(th, sig);
+  while(th->interrupt_flag){
+    int status = th->status;
+    th->status = THREAD_RUNNABLE;
+    th->interrupt_flag = 0;
+    
+    /* signal handling */
+    while(th->signal_queue.head != th->signal_queue.tail){
+      int sig = th->signal_queue.buff[th->signal_queue.tail];
+      // TODO: signal mask
+      th->signal_queue.tail = (th->signal_queue.tail + 1) % RUBY_SIGNAL_QUEUE_MAX;
+      rb_signal_exec(th, sig);
+    }
+
+    /* exception from another thread */
+    if(th->throwed_errinfo){
+      VALUE err = th->throwed_errinfo;
+      th->throwed_errinfo = 0;
+      if(err == eKillSignal){
+        th->status == THREAD_TO_KILL;
+        TH_JUMP_TAG(th, TAG_FATAL);
+      }
+      else{
+        rb_exc_raise(err);
+      }
+    }
+
+    th->status = status;
+    /* thread pass */
+    yarv_thraed_schedule();
   }
-  
-  /* exception from another thread */
-  if(th->throwed_errinfo){
-    VALUE err = th->throwed_errinfo;
-    th->throwed_errinfo = 0;
-    rb_exc_raise(err);
+}
+
+static void
+rb_thread_ready(yarv_thread_t *th)
+{
+  if(th->status == THREAD_STOPPED){
+    native_thread_interrupt(th);
   }
-  
-  /* thread pass */
-  yarv_thraed_schedule();
 }
 
 static VALUE
@@ -392,12 +498,46 @@
 {
   VALUE exc;
 
+  if (rb_thread_dead(th)) {
+    return Qnil;
+  }
+
   exc = rb_make_exception(argc, argv);
+  // TODO: need synchronization if run threads in parallel
   th->throwed_errinfo = exc;
   th->interrupt_flag = 1;
+
+  rb_thread_ready(th);
+  
   return Qnil;
 }
 
+void
+rb_thread_signal_raise(const char *sig)
+{
+  VALUE argv[1];
+  char buf[BUFSIZ];
+  if (sig == 0) {
+    return;	/* should not happen */
+  }
+  snprintf(buf, BUFSIZ, "SIG%s", sig);
+  argv[0] = rb_exc_new3(rb_eSignal, rb_str_new2(buf));
+  yarv_thread_raise(1, argv, GET_VM()->main_thread);
+}
+
+void
+rb_thread_signal_exit()
+{
+  VALUE argv[1];
+  VALUE args[2];
+  
+  args[0] = INT2NUM(EXIT_SUCCESS);
+  args[1] = rb_str_new2("exit");
+  argv[0] = rb_class_new_instance(2, args, rb_eSystemExit);
+  yarv_thread_raise(1, argv, GET_VM()->main_thread);
+}
+
+
 /*
  *  call-seq:
  *     thr.raise(exception)
@@ -427,8 +567,222 @@
 }
 
 
+/*
+ *  call-seq:
+ *     thr.exit        => thr or nil
+ *     thr.kill        => thr or nil
+ *     thr.terminate   => thr or nil
+ *  
+ *  Terminates <i>thr</i> and schedules another thread to be run. If this thread
+ *  is already marked to be killed, <code>exit</code> returns the
+ *  <code>Thread</code>. If this is the main thread, or the last thread, exits
+ *  the process.
+ */
+
+VALUE
+rb_thread_kill(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  if (th != GET_THREAD() && th->safe_level < 4) {
+    rb_secure(4);
+  }
+  if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED){
+    return thread;
+  }
+  if (th == GET_VM()->main_thread) {
+    rb_exit(EXIT_SUCCESS);
+  }
+
+  th->throwed_errinfo = eKillSignal;
+  th->status = THREAD_TO_KILL;
+  if(th->status == THREAD_STOPPED){
+    native_thread_interrupt(th);
+  }
+  return thread;
+}
+
+
+/*
+ *  call-seq:
+ *     Thread.kill(thread)   => thread
+ *  
+ *  Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>).
+ *     
+ *     count = 0
+ *     a = Thread.new { loop { count += 1 } }
+ *     sleep(0.1)       #=> 0
+ *     Thread.kill(a)   #=> #<Thread:0x401b3d30 dead>
+ *     count            #=> 93947
+ *     a.alive?         #=> false
+ */
+
+static VALUE
+rb_thread_s_kill(VALUE obj, VALUE th)
+{
+  return rb_thread_kill(th);
+}
+
+
+/*
+ *  call-seq:
+ *     Thread.exit   => thread
+ *  
+ *  Terminates the currently running thread and schedules another thread to be
+ *  run. If this thread is already marked to be killed, <code>exit</code>
+ *  returns the <code>Thread</code>. If this is the main thread, or the last
+ *  thread, exit the process.
+ */
+
+static VALUE
+rb_thread_exit()
+{
+  return rb_thread_kill(GET_THREAD()->self);
+}
+
+
+/*
+ *  call-seq:
+ *     thr.wakeup   => thr
+ *  
+ *  Marks <i>thr</i> as eligible for scheduling (it may still remain blocked on
+ *  I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>).
+ *     
+ *     c = Thread.new { Thread.stop; puts "hey!" }
+ *     c.wakeup
+ *     
+ *  <em>produces:</em>
+ *     
+ *     hey!
+ */
+
+VALUE
+rb_thread_wakeup(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  if (th->status == THREAD_KILLED) {
+    rb_raise(rb_eThreadError, "killed thread");
+  }
+
+  rb_thread_ready(th);
+  return thread;
+}
+
+
+/*
+ *  call-seq:
+ *     thr.run   => thr
+ *  
+ *  Wakes up <i>thr</i>, making it eligible for scheduling. If not in a critical
+ *  section, then invokes the scheduler.
+ *     
+ *     a = Thread.new { puts "a"; Thread.stop; puts "c" }
+ *     Thread.pass
+ *     puts "Got here"
+ *     a.run
+ *     a.join
+ *     
+ *  <em>produces:</em>
+ *     
+ *     a
+ *     Got here
+ *     c
+ */
+
+VALUE
+rb_thread_run(thread)
+    VALUE thread;
+{
+  rb_thread_wakeup(thread);
+  rb_thread_schedule();
+  return thread;
+}
+
+
+/*
+ *  call-seq:
+ *     Thread.stop   => nil
+ *  
+ *  Stops execution of the current thread, putting it into a ``sleep'' state,
+ *  and schedules execution of another thread. Resets the ``critical'' condition
+ *  to <code>false</code>.
+ *     
+ *     a = Thread.new { print "a"; Thread.stop; print "c" }
+ *     Thread.pass
+ *     print "b"
+ *     a.run
+ *     a.join
+ *     
+ *  <em>produces:</em>
+ *     
+ *     abc
+ */
+
+VALUE
+rb_thread_stop(void)
+{
+  yarv_thread_t *th = GET_THREAD();
+  
+  if (rb_thread_alone()) {
+    rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever");
+  }
+  rb_thread_sleep_forever();
+
+  return Qnil;
+}
+
+
+static int
+thread_list_i(st_data_t key, st_data_t val, void *data)
+{
+  VALUE ary = (VALUE)data;
+  yarv_thread_t *th;
+  GetThreadVal((VALUE)key, th);
+  
+  switch (th->status) {
+  case THREAD_RUNNABLE:
+  case THREAD_STOPPED:
+  case THREAD_TO_KILL:
+    rb_ary_push(ary, th->self);
+  default:
+    break;
+  }
+  return ST_CONTINUE;
+}
+
 /********************************************************************/
 
+/*
+ *  call-seq:
+ *     Thread.list   => array
+ *  
+ *  Returns an array of <code>Thread</code> objects for all threads that are
+ *  either runnable or stopped.
+ *     
+ *     Thread.new { sleep(200) }
+ *     Thread.new { 1000000.times {|i| i*i } }
+ *     Thread.new { Thread.stop }
+ *     Thread.list.each {|t| p t}
+ *     
+ *  <em>produces:</em>
+ *     
+ *     #<Thread:0x401b3e84 sleep>
+ *     #<Thread:0x401b3f38 run>
+ *     #<Thread:0x401b3fb0 sleep>
+ *     #<Thread:0x401bdf4c run>
+ */
+
+VALUE
+rb_thread_list(void)
+{
+  VALUE ary = rb_ary_new();
+  st_foreach(GET_VM()->living_threads, thread_list_i, ary);
+  return ary;
+}
+
 static VALUE
 yarv_thread_s_current(VALUE klass){
   return GET_THREAD()->self;
@@ -439,6 +793,137 @@
   return GET_VM()->main_thread_val;
 }
 
+static const char *
+thread_status_name(enum yarv_thread_status status)
+{
+  switch (status) {
+  case THREAD_RUNNABLE:
+    return "run";
+  case THREAD_STOPPED:
+    return "sleep";
+  case THREAD_TO_KILL:
+    return "aborting";
+  case THREAD_KILLED:
+    return "dead";
+  default:
+    return "unknown";
+  }
+}
+
+static int
+rb_thread_dead(yarv_thread_t *th)
+{
+  return th->status == THREAD_KILLED;
+}
+
+
+/*
+ *  call-seq:
+ *     thr.status   => string, false or nil
+ *  
+ *  Returns the status of <i>thr</i>: ``<code>sleep</code>'' if <i>thr</i> is
+ *  sleeping or waiting on I/O, ``<code>run</code>'' if <i>thr</i> is executing,
+ *  ``<code>aborting</code>'' if <i>thr</i> is aborting, <code>false</code> if
+ *  <i>thr</i> terminated normally, and <code>nil</code> if <i>thr</i>
+ *  terminated with an exception.
+ *     
+ *     a = Thread.new { raise("die now") }
+ *     b = Thread.new { Thread.stop }
+ *     c = Thread.new { Thread.exit }
+ *     d = Thread.new { sleep }
+ *     Thread.critical = true
+ *     d.kill                  #=> #<Thread:0x401b3678 aborting>
+ *     a.status                #=> nil
+ *     b.status                #=> "sleep"
+ *     c.status                #=> false
+ *     d.status                #=> "aborting"
+ *     Thread.current.status   #=> "run"
+ */
+
+static VALUE
+rb_thread_status(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  if (rb_thread_dead(th)) {
+    if (!NIL_P(th->errinfo) /* TODO */) {
+      return Qnil;
+    }
+    return Qfalse;
+  }
+  return rb_str_new2(thread_status_name(th->status));
+}
+
+
+/*
+ *  call-seq:
+ *     thr.alive?   => true or false
+ *  
+ *  Returns <code>true</code> if <i>thr</i> is running or sleeping.
+ *     
+ *     thr = Thread.new { }
+ *     thr.join                #=> #<Thread:0x401b3fb0 dead>
+ *     Thread.current.alive?   #=> true
+ *     thr.alive?              #=> false
+ */
+
+static VALUE
+rb_thread_alive_p(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  if (rb_thread_dead(th)) return Qfalse;
+  return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     thr.stop?   => true or false
+ *  
+ *  Returns <code>true</code> if <i>thr</i> is dead or sleeping.
+ *     
+ *     a = Thread.new { Thread.stop }
+ *     b = Thread.current
+ *     a.stop?   #=> true
+ *     b.stop?   #=> false
+ */
+
+static VALUE
+rb_thread_stop_p(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  if (rb_thread_dead(th)) return Qtrue;
+  if (th->status == THREAD_STOPPED) return Qtrue;
+  return Qfalse;
+}
+
+/*
+ * call-seq:
+ *   thr.inspect   => string
+ *
+ * Dump the name, id, and status of _thr_ to a string.
+ */
+
+static VALUE
+rb_thread_inspect(VALUE thread)
+{
+  char *cname = rb_obj_classname(thread);
+  yarv_thread_t *th;
+  const char *status;
+  VALUE str;
+
+  GetThreadVal(thread, th);
+  status = thread_status_name(th->status);
+  str = rb_sprintf("#<%s:%p %s>", cname, (void*)thread, status);
+  OBJ_INFECT(str, thread);
+
+  return str;
+}
+
 VALUE
 rb_thread_local_aref(VALUE thread, ID id)
 {
@@ -557,6 +1042,11 @@
   return ST_CONTINUE;
 }
 
+int
+rb_thread_alone()
+{
+  return GET_VM()->living_threads->num_entries == 1;
+}
 
 /*
  *  call-seq:
@@ -585,8 +1075,93 @@
   return ary;
 }
 
+/*
+ *  call-seq:
+ *     thr.priority   => integer
+ *  
+ *  Returns the priority of <i>thr</i>. Default is zero; higher-priority threads
+ *  will run before lower-priority threads.
+ *     
+ *     Thread.current.priority   #=> 0
+ */
 
+static VALUE
+rb_thread_priority(VALUE thread)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+  return INT2NUM(th->priority);
+}
+
+
 /*
+ *  call-seq:
+ *     thr.priority= integer   => thr
+ *  
+ *  Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
+ *  will run before lower-priority threads.
+ *     
+ *     count1 = count2 = 0
+ *     a = Thread.new do
+ *           loop { count1 += 1 }
+ *         end
+ *     a.priority = -1
+ *     
+ *     b = Thread.new do
+ *           loop { count2 += 1 }
+ *         end
+ *     b.priority = -2
+ *     sleep 1   #=> 1
+ *     Thread.critical = 1
+ *     count1    #=> 622504
+ *     count2    #=> 5832
+ */
+
+static VALUE
+rb_thread_priority_set(VALUE thread, VALUE prio)
+{
+  yarv_thread_t *th;
+  GetThreadVal(thread, th);
+
+  rb_secure(4);
+
+  th->priority = NUM2INT(prio);
+  native_thread_apply_priority(th);
+  return prio;
+}
+
+/* for IO */
+
+void
+rb_thread_wait_fd(int fd)
+{
+  fd_set set;
+  int result = 0;
+
+  FD_ZERO(&set);
+  FD_SET (fd, &set);
+  
+  while(result <= 0){
+    GVL_UNLOCK_RANGE(result = select(fd+1, &set, 0, 0, 0));
+  }
+}
+
+int
+rb_thread_fd_writable(int fd)
+{
+  fd_set set;
+  int result = 0;
+
+  FD_ZERO(&set);
+  FD_SET (fd, &set);
+  
+  while(result <= 0){
+    GVL_UNLOCK_RANGE(result = select(fd+1, 0, &set, 0, 0));
+  }
+  return Qtrue;
+}
+
+/*
  * for GC
  */
 
@@ -605,6 +1180,79 @@
 }
 
 /*
+ *
+ */
+
+struct yarv_signal_thread_list {
+  yarv_thread_t *th;
+  int need_signal;
+  struct yarv_signal_thread_list *prev;
+  struct yarv_signal_thread_list *next;
+};
+
+static struct yarv_signal_thread_list signal_thread_list_anchor = {
+  0, 0, 0, 0,
+};
+
+static void
+yarv_add_signal_thread_list(yarv_thread_t *th)
+{
+  // LOCK
+  if(!th->signal_thread_list){
+    struct yarv_signal_thread_list *list =
+      xmalloc(sizeof(struct yarv_signal_thread_list));
+    list->th = th;
+    
+    list->prev = &signal_thread_list_anchor;
+    list->next =  signal_thread_list_anchor.next;
+    if(list->next){
+      list->next->prev = list;
+    }
+    signal_thread_list_anchor.next = list;
+    th->signal_thread_list = list;
+  }
+  // UNLOCK
+}
+
+static void
+yarv_remove_signal_thread_list(yarv_thread_t *th)
+{
+  // LOCK
+  if(th->signal_thread_list){
+    struct yarv_signal_thread_list *list =
+      (struct yarv_signal_thread_list*) th->signal_thread_list;
+    
+    list->prev->next = list->next;
+    if(list->next){
+      list->next->prev = list->prev;
+    }
+    th->signal_thread_list = 0;
+    xfree(list);
+  }
+  else{
+    /* */
+  }
+  // UNLOCK
+}
+
+static void
+timer_function(void)
+{
+  struct yarv_signal_thread_list *list;
+  
+  // TODO: GET_VM() should not be used
+  GET_VM()->running_thread->interrupt_flag = 1;
+
+#ifndef _WIN32
+  list = signal_thread_list_anchor.next;
+  while(list){
+    native_thread_send_interrupt_signal(list->th);
+    list = list->next;
+  }
+#endif
+}
+
+/*
  * for tests
  */
 
@@ -622,21 +1270,38 @@
 void
 Init_yarvthread(){
   rb_define_global_function("raw_gets", raw_gets, 0);
+
   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, "main", yarv_thread_s_main, 0);
   rb_define_singleton_method(cYarvThread, "current", yarv_thread_s_current, 0);
+  rb_define_singleton_method(cYarvThread, "stop", rb_thread_stop, 0);
+  rb_define_singleton_method(cYarvThread, "kill", rb_thread_s_kill, 1);
+  rb_define_singleton_method(cYarvThread, "exit", rb_thread_exit, 0);
+  rb_define_singleton_method(cYarvThread, "current", yarv_thread_s_current, 0);
   rb_define_singleton_method(cYarvThread, "pass", yarv_thread_s_pass, 0);
+  rb_define_singleton_method(cYarvThread, "list", rb_thread_list, 0);
 
   rb_define_method(cYarvThread, "raise", yarv_thread_raise_m, -1);
   rb_define_method(cYarvThread, "join", yarv_thread_join, -1);
   rb_define_method(cYarvThread, "value", yarv_thread_value, 0);
+  rb_define_method(cYarvThread, "kill", rb_thread_kill, 0);
+  rb_define_method(cYarvThread, "terminate", rb_thread_kill, 0);
+  rb_define_method(cYarvThread, "exit", rb_thread_kill, 0);
+  rb_define_method(cYarvThread, "run", rb_thread_run, 0);
+  rb_define_method(cYarvThread, "wakeup", rb_thread_wakeup, 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);
-
+  rb_define_method(cYarvThread, "priority", rb_thread_priority, 0);
+  rb_define_method(cYarvThread, "priority=", rb_thread_priority_set, 1);
+  rb_define_method(cYarvThread, "status", rb_thread_status, 0);
+  rb_define_method(cYarvThread, "alive?", rb_thread_alive_p, 0);
+  rb_define_method(cYarvThread, "stop?", rb_thread_stop_p, 0);
+  rb_define_method(cYarvThread, "inspect", rb_thread_inspect, 0);
+  
   Init_native_thread();
   {
     /* main thread setting */

Modified: trunk/thread_pthread.h
===================================================================
--- trunk/thread_pthread.h	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/thread_pthread.h	2006-02-03 23:33:40 UTC (rev 362)
@@ -9,6 +9,10 @@
 #define native_mutex_lock   pthread_mutex_lock
 #define native_mutex_unlock pthread_mutex_unlock
 
+typedef struct native_thread_data_struct {
+  int dummy;
+} native_thread_data_t;
+
 #endif /* THREAD_PTHREAD_H_INCLUDED */
 
 
@@ -23,11 +27,17 @@
 
 #define native_cleanup_push pthread_cleanup_push
 #define native_cleanup_pop  pthread_cleanup_pop
-#define native_thread_join  pthread_join
+#define native_thread_join(a, b, c)  pthread_join(b, c)
 
 static void
+null_func()
+{
+}
+
+static void
 Init_native_thread(){
-  /* */
+  GET_THREAD()->thread_id = pthread_self();
+  posix_signal(SIGVTALRM, null_func);
 }
 
 static int system_working = 1;
@@ -82,8 +92,46 @@
   return err;
 }
 
+static void
+native_thread_apply_priority(yarv_thread_t *th)
+{
+  struct sched_param sp;
+  int policy;
+  int priority = 0 - th->priority;
+  int max, min;
+  pthread_getschedparam(th->thread_id, &policy, &sp);
+  max = sched_get_priority_max(policy);
+  min = sched_get_priority_min(policy);
+
+  if(min < priority){
+    priority = max;
+  }
+  else if(max > priority){
+    priority = min;
+  }
+
+  sp.sched_priority = priority;
+  pthread_setschedparam(th->thread_id, policy, &sp);
+}
+
+static void
+native_thread_send_interrupt_signal(yarv_thread_t *th)
+{
+  thread_debug("native_thread_send_interrupt_signal (%p)\n",
+               th->thread_id);
+  pthread_kill(th->thread_id, SIGVTALRM);
+}
+
+static void
+native_thread_interrupt(yarv_thread_t *th)
+{
+  yarv_add_signal_thread_list(th);
+}
+
 static pthread_t time_thread;
 
+static void timer_function(void);
+
 static void*
 thread_timer(void *dummy)
 {
@@ -100,8 +148,7 @@
     tv.tv_usec = 10000;
     select(0, NULL, NULL, NULL, &tv);
 #endif
-    // TODO: GET_VM() should not be used
-    GET_VM()->running_thread->interrupt_flag = 1;
+    timer_function();
   }
   return NULL;
 }

Modified: trunk/thread_win32.h
===================================================================
--- trunk/thread_win32.h	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/thread_win32.h	2006-02-03 23:33:40 UTC (rev 362)
@@ -12,13 +12,14 @@
 int native_mutex_unlock(yarv_thread_lock_t *);
 void native_mutex_initialize(yarv_thread_lock_t *);
 
+typedef struct native_thread_data_struct {
+  HANDLE interrupt_event;
+} native_thread_data_t;
+
 #endif /* THREAD_WIN32_H_INCLUDED */
 
 
 
-
-
-
 /**********************************************************************/
 
 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
@@ -28,28 +29,47 @@
 #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();
+  yarv_thread_t *th = GET_THREAD();
+  DuplicateHandle(GetCurrentProcess(),
+                  GetCurrentThread(),
+                  GetCurrentProcess(),
+                  &th->thread_id,
+                  0,
+                  FALSE,
+                  DUPLICATE_SAME_ACCESS);
+  
+  th->native_thread_data.interrupt_event =
+    CreateEvent(0, TRUE, FALSE, 0);
+
+  thread_debug("initial thread (th: %p, thid: %p, event: %p)\n",
+               th, GET_THREAD()->thread_id,
+               th->native_thread_data.interrupt_event);
 }
 
 static int system_working = 1;
 
 static int
-kill_func(st_data_t key, st_data_t val, void *dummy){
+kill_func(st_data_t key, st_data_t val, void *dummy)
+{
   HANDLE thid = (HANDLE)val;
-  if(GetCurrentThread() != thid){
-    TerminateThread(thid, 0);
+  yarv_thread_t *th = (void *)key;
+  
+  thread_debug("kill_func\n");
+  if(th == th->vm->main_thread){
+    thread_debug("kill_func: main thread - skip (%p)\n", thid);
   }
+  else{
+    thread_debug("kill_func: work thread - kill (%p)\n", thid);
+    // TerminateThread(thid, 0);
+  }
   return ST_CONTINUE;
 }
 
 void
-native_thread_cleanup(yarv_vm_t *vm){
+native_thread_cleanup(yarv_vm_t *vm)
+{
   system_working = 0;
   st_foreach(vm->living_threads, kill_func, 0);
 }
@@ -68,47 +88,80 @@
     (LPTSTR) &lpMsgBuf,
     0,
     NULL);
-  
+  // {int *a=0; *a=0;}
   MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
-  exit(1);
+  //  exit(1);
 }
 
 static int
-w32_wait_event(HANDLE event, DWORD timeout)
+w32_wait_event(HANDLE event, DWORD timeout, yarv_thread_t *th)
 {
   HANDLE events[2];
   int count = 0;
   DWORD ret;
-
+  
   if(event){
     events[count++] = event;
+    thread_debug("  * handle: %p (count: %d)\n", event, count);
   }
-  events[count++] = interrupted_event;
 
+  if(th){
+    HANDLE intr = th->native_thread_data.interrupt_event;
+    ResetEvent(intr);
+    if(th->interrupt_flag){
+      SetEvent(intr);
+    }
+    events[count++] = intr;
+    thread_debug("  * handle: %p (count: %d, intr)\n", intr, count);
+  }
+
+  thread_debug("  WaitForMultipleObjectsEx start (count: %d)\n", count);
   ret = WaitForMultipleObjectsEx(count, events, FALSE, timeout, TRUE);
-  if(ret == -1){
-    w32_show_error_message();
-  }
-  if (ret == WAIT_OBJECT_0 + count - 1) {
+  thread_debug("  WaitForMultipleObjectsEx end (ret: %d)\n", ret);
+  
+  if (ret == WAIT_OBJECT_0 + count - 1 && th) {
     errno = EINTR;
   }
+  if (ret == -1 && THREAD_DEBUG) {
+    int i;
+    DWORD dmy;
+    for(i=0; i<count; i++){
+      thread_debug("  * error handle %d - %s\n", i,
+                   GetHandleInformation(events[i], &dmy) ? "OK" : "NG");
+    }
+  }
   return ret;
 }
 
+static void
+w32_sleep(yarv_thread_t *th, DWORD msec)
+{
+  DWORD ret;
+  thread_debug("w32_sleep start\n");
+  ret = w32_wait_event(0, msec, th);
+  thread_debug("w32_sleep done (%d)\n", ret);
+}
+
 int
-native_mutex_lock(yarv_thread_lock_t *lock){
+native_mutex_lock(yarv_thread_lock_t *lock)
+{
   DWORD result;
   
   while(1){
-    result = w32_wait_event(*lock, INFINITE);
+    thread_debug("native_mutex_lock: %p\n", *lock);
+    result = w32_wait_event(*lock, INFINITE, 0);
     switch(result){
     case WAIT_OBJECT_0:
       /* get mutex object */
-      thread_debug("%p acquire mutex: %p\n", GetCurrentThreadId(), *lock);
+      thread_debug("acquire mutex: %p\n", *lock);
       return 0;
+    case WAIT_OBJECT_0 + 1:
+      /* interrupt */
+      errno = EINTR;
+      thread_debug("acquire mutex interrupted: %p\n", *lock);
+      return 0;
     case WAIT_TIMEOUT:
-      /* TODO: check interrupt */
-      thread_debug("%p timeout mutex: %p\n", GetCurrentThreadId(), *lock);
+      thread_debug("timeout mutex: %p\n", *lock);
       break;
     case WAIT_ABANDONED:
       rb_bug("win32_mutex_lock: WAIT_ABANDONED");
@@ -122,38 +175,42 @@
 }
 
 int
-native_mutex_unlock(yarv_thread_lock_t *lock){
-  thread_debug("%p release mutex: %p\n",  GetCurrentThreadId(), *lock);
+native_mutex_unlock(yarv_thread_lock_t *lock)
+{
+  thread_debug("release mutex: %p\n", *lock);
   return ReleaseMutex(*lock);
 }
 
 void
-native_mutex_initialize(yarv_thread_lock_t *lock){
+native_mutex_initialize(yarv_thread_lock_t *lock)
+{
   *lock = CreateMutex(NULL, FALSE, NULL);
-  thread_debug("%p initialize mutex: %p\n",  GetCurrentThreadId(), *lock);
+  // thread_debug("initialize mutex: %p\n", *lock);
 }
 
 static int
-native_thread_join(yarv_thread_id_t thid, void *ptr){
+native_thread_join(yarv_thread_t *th, yarv_thread_id_t thid, void *ptr)
+{
   DWORD result;
 
   while(1){
-    result = w32_wait_event(thid, INFINITE);
+    result = w32_wait_event(thid, INFINITE, th);
     switch(result){
     case WAIT_OBJECT_0:
       /* join */
       if(ptr){
         GetExitCodeThread(thid, ptr);
       }
-      thread_debug("%p join to %p\n", GetCurrentThreadId(), thid);
+      thread_debug("join to %p\n", thid);
       return 0;
     case WAIT_TIMEOUT:
       /* TODO: check interrupt */
-      thread_debug("%p join timeout (to %p)\n", GetCurrentThreadId(), thid);
+      errno = EINTR;
+      thread_debug("join timeout (to %p)\n", thid);
       break;
-    default:
-      rb_bug("native_thread_join: unknown result (%d)", result);
-      break;
+    case -1:
+      errno = EINVAL;
+      return 1;
     }
   }
   return 1;
@@ -169,15 +226,40 @@
   yarv_thread_t *th = th_ptr;
   VALUE stack_start;
   /* run */
-  thread_debug("%p (th: %p) thread created\n", GetCurrentThreadId(), th);
+  th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
+  
+  thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th,
+               th->thread_id, th->native_thread_data.interrupt_event);
   thread_start_func_2(th, &stack_start);
   thread_cleanup_func(th);
-  thread_debug("%p (th: %p) thread deleted\n", GetCurrentThreadId(), th);
+
+  // native_mutex_unlock(&GET_VM()->global_interpreter_lock);
+
+  thread_debug("close handle - intr: %p, thid: %p\n",
+               th->native_thread_data.interrupt_event,
+               th->thread_id);
+  CloseHandle(th->native_thread_data.interrupt_event);
+  CloseHandle(th->thread_id);
+  thread_debug("thread deleted (th: %p)\n", th);
   return 0;
 }
 
 static void make_timer_thread();
 
+static HANDLE
+w32_create_thread(DWORD stack_size, void *func, void *val)
+{
+  HANDLE handle;
+#ifdef __CYGWIN__
+  DWORD dmy;
+  handle = CreateThread(0, stack_size, func, val, 0, &dmy);
+#else
+  handle = (HANDLE)_beginthreadex(
+    0, stack_size, func, val, 0, 0);
+#endif
+  return handle;
+}
+
 static int
 native_thread_create(yarv_thread_t *th)
 {
@@ -187,28 +269,55 @@
   if(!init){
     make_timer_thread();
   }
-  
-  if((th->thread_id = (HANDLE)_beginthreadex(0, /* security */
-                                             stack_size,
-                                             thread_start_func_1,
-                                             th,
-                                             0, /* init flag */
-                                             0  /* handle */)) == 0){
+
+  if((th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th))
+     == 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);
+  if(THREAD_DEBUG){
+    Sleep(0);
+    thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %d\n",
+                 th, th->thread_id, th->native_thread_data.interrupt_event,
+                 stack_size);
+  }
   return 0;
 }
 
+static void
+native_thread_apply_priority(yarv_thread_t *th)
+{
+  int priority = th->priority;
+  if(th->priority > 0){
+    priority = THREAD_PRIORITY_ABOVE_NORMAL;
+  }
+  else if(th->priority < 0){
+    priority = THREAD_PRIORITY_BELOW_NORMAL;
+  }
+  else{
+    priority = THREAD_PRIORITY_NORMAL;
+  }
+  
+  SetThreadPriority(th->thread_id, priority);
+}
+
+static void
+native_thread_interrupt(yarv_thread_t *th)
+{
+  SetEvent(th->native_thread_data.interrupt_event);
+}
+
+static void timer_function(void);
+
 static HANDLE timer_thread_handle = 0;
 
 static unsigned int _stdcall
 timer_thread_func(void *dummy){
-  thread_debug("timer_thread: %p\n", GetCurrentThreadId());
+  thread_debug("timer_thread\n");
   while(system_working){
     Sleep(WIN32_WAIT_TIMEOUT);
-    GET_VM()->running_thread->interrupt_flag = 1;
+    timer_function();
   }
+  thread_debug("timer killed\n");
   return 0;
 }
 
@@ -216,10 +325,7 @@
 make_timer_thread(){
   if(timer_thread_handle == 0){
     timer_thread_handle =
-      (HANDLE)_beginthreadex(0,
-                             1024,
-                             timer_thread_func,
-                             0, 0, 0);
+      w32_create_thread(1024, timer_thread_func, 0);
   }
 }
 

Modified: trunk/vm.c
===================================================================
--- trunk/vm.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/vm.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -1288,8 +1288,9 @@
     VALUE type;
     
     err = th->errinfo;
+    
     if(state == TAG_RAISE){
-      rb_ivar_set(err, idThrowState, state);
+      rb_ivar_set(err, idThrowState, INT2FIX(state));
     }
     
   exception_handler:

Modified: trunk/yarvcore.c
===================================================================
--- trunk/yarvcore.c	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/yarvcore.c	2006-02-03 23:33:40 UTC (rev 362)
@@ -1211,3 +1211,4 @@
   th_init2(th);
   yarv_set_current_running_thread_raw(th);
 }
+

Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/yarvcore.h	2006-02-03 23:33:40 UTC (rev 362)
@@ -20,10 +20,10 @@
 #include "debug.h"
 #include "vm_opts.h"
 
-#if   defined(HAVE_PTHREAD_H)
+#if   defined(_WIN32) || defined(__CYGWIN__)
+#include "thread_win32.h"
+#elif defined(HAVE_PTHREAD_H)
 #include "thread_pthread.h"
-#elif defined(_WIN32)
-#include "thread_win32.h"
 #else
 #error "unsupported thread type"
 #endif
@@ -180,7 +180,6 @@
   struct iseq_label_data* redo_label;
   VALUE current_block;
   VALUE loopval_popped;  /* used by NODE_BREAK */
-  VALUE in_ensure;       /* used by NODE_RETURN */
   VALUE ensure_node;
   VALUE for_iseq;
   struct iseq_compile_data_ensure_node_stack *ensure_node_stack;
@@ -354,10 +353,11 @@
   VALUE *stack;                   /* must free, must mark*/
   unsigned long stack_size;
   yarv_control_frame_t *cfp;
-
+  
   /* passing state */
   int state;
-  
+  int safe_level;
+
   /* for rb_iterate */
   yarv_block_t *passed_block;
 
@@ -375,7 +375,10 @@
   /* thread control */
   yarv_thread_id_t thread_id;
   enum yarv_thread_status status;
+  int priority;
   
+  native_thread_data_t native_thread_data;
+  
   VALUE value;
   VALUE wait_thread_value;
 
@@ -390,6 +393,8 @@
     int tail;
   } signal_queue;
 
+  void *signal_thread_list;
+  
   VALUE first_proc;
   VALUE first_args;
 
@@ -578,7 +583,6 @@
 
 #define YARV_CHECK_INTS_TH(th) do { \
   if(th->interrupt_flag){ \
-    th->interrupt_flag = 0; \
     /* TODO: trap something event */ \
     yarv_thread_execute_interrupts(th); \
   } \

Modified: trunk/yarvtest/test_class.rb
===================================================================
--- trunk/yarvtest/test_class.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/yarvtest/test_class.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -509,7 +509,7 @@
   end
 
   def test_reopen_not_class
-    ae %q{
+    ae %q{ # [yarv-dev:782]
       begin
         B = 1
         class B
@@ -519,6 +519,16 @@
         e.message
       end
     }
+    ae %q{ # [yarv-dev:800]
+      begin
+        B = 1
+        module B
+          p B
+        end
+      rescue TypeError => e
+        e.message
+      end
+    }
   end
 end
 

Added: trunk/yarvtest/test_thread.rb
===================================================================
--- trunk/yarvtest/test_thread.rb	2006-02-02 15:08:50 UTC (rev 361)
+++ trunk/yarvtest/test_thread.rb	2006-02-03 23:33:40 UTC (rev 362)
@@ -0,0 +1,123 @@
+
+require 'yarvtest/yarvtest'
+
+class TestThread < YarvTestBase
+  def test_create
+    ae %q{
+      Thread.new{
+      }.join
+      :ok
+    }
+    ae %q{
+      Thread.new{
+        :ok
+      }.value
+    }
+  end
+
+  def test_create_many_threads
+    ae %q{
+      v = 0
+      (1..200).map{|i|
+        Thread.new{
+          i
+        }
+      }.each{|t|
+        v += t.value
+      }
+      v
+    }
+    ae %q{
+      10000.times{|e|
+        (1..2).map{
+          Thread.new{
+          }
+        }.each{|e|
+          e.join
+        }
+      }
+    }
+  end
+
+  def test_raise
+    ae %q{
+      t = Thread.new{
+        sleep
+      }
+      sleep 0.1
+      t.raise
+      begin
+        t.join
+        :ng
+      rescue
+        :ok
+      end
+    }
+    ae %q{
+      t = Thread.new{
+        loop{}
+      }
+      Thread.pass
+      t.raise
+      begin
+        t.join
+        :ng
+      rescue
+        :ok
+      end
+    }
+    ae %q{
+      t = Thread.new{
+      }
+      Thread.pass
+      t.join
+      t.raise # raise to exited thread
+      begin
+        t.join
+        :ok
+      rescue
+        :ng
+      end
+    }
+  end
+
+  def test_status
+    ae %q{
+      t = Thread.new{
+        loop{}
+      }
+      st = t.status
+      t.kill
+      st
+    }
+    ae %q{
+      t = Thread.new{
+        sleep
+      }
+      sleep 0.1
+      st = t.status
+      t.kill
+      st
+    }
+    ae %q{
+      t = Thread.new{
+      }
+      t.kill
+      sleep 0.1
+      t.status
+    }
+  end
+
+  def test_tlv
+    ae %q{
+      Thread.current[:a] = 1
+      Thread.new{
+        Thread.current[:a] = 10
+        Thread.pass
+        Thread.current[:a]
+      }.value + Thread.current[:a]
+    }
+  end
+  
+end
+


-- 
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧][生データ]