From: Joe Damato <ice799@...>
Date: 2008-09-03T07:10:24+09:00
Subject: [ruby-core:18444] [PATCH] remove timer signal after last ruby thread has died

This is a multi-part message in MIME format.
--------------060304070208010802040906
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi -

While playing around with ruby's green threads in ruby 1.8.7 (with 
pthreads disabled) I noticed that after all green threads spawned for a 
ruby process have died, the timer setup to pre-empt the threads is not 
turned off. There is a function for doing this, rb_thread_stop_timer() 
in eval.c, but it is never called after the last ruby green thread has 
died. As a result, even after all threads have joined, the timer 
interrupts continue to fire. The included patch fixes this, and I've 
included some examples to help clarify the behavior I am seeing:

with ruby 1.8.7:

[joe@mawu:/home/joe]% strace -ttT ruby -e 't1 = Thread.new { sleep(10) 
}; t1.join; 10000.times { "aaaaaaaa" * 1000 };'  2>&1 | egrep 
'(sigret|setitimer|timer|exit_group)'
14:29:27.785959 setitimer(ITIMER_VIRTUAL, {it_interval={0, 10000}, 
it_value={0, 10000}}, NULL) = 0 <0.000006>
14:29:37.832131 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:37.832217 rt_sigreturn(0x1a)      = 10127344 <0.000008>
14:29:37.878799 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:37.878867 rt_sigreturn(0x1a)      = 14271352 <0.000009>
14:29:37.945461 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:37.945508 rt_sigreturn(0x1a)      = 7158032 <0.000006>
14:29:37.988797 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:37.988859 rt_sigreturn(0x1a)      = 9634280 <0.000007>
14:29:38.028799 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:38.028855 rt_sigreturn(0x1a)      = 9986760 <0.000006>
14:29:38.075464 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:38.075523 rt_sigreturn(0x1a)      = 11 <0.000005>
14:29:38.148798 --- SIGVTALRM (Virtual timer expired) @ 0 (0) ---
14:29:38.148856 rt_sigreturn(0x1a)      = 11364504 <0.000007>
14:29:38.180574 exit_group(0)           = ?

with the patch applied:

[joe@mawu:/home/joe]% strace -ttT ruby -e 't1 = Thread.new { sleep(10) 
}; t1.join; 10000.times { "aaaaaaaa" * 1000 };'  2>&1 | egrep 
'(sigret|setitimer|timer|exit_group)'
14:29:17.536727 setitimer(ITIMER_VIRTUAL, {it_interval={0, 10000}, 
it_value={0, 10000}}, NULL) = 0 <0.000006>
14:29:27.544435 setitimer(ITIMER_VIRTUAL, {it_interval={0, 0}, 
it_value={0, 0}}, NULL) = 0 <0.000006>
14:29:27.948804 exit_group(0)           = ?


Comments, suggestions, and questions are welcome.

Thanks,
Joe Damato
Aman Gupta

--------------060304070208010802040906
Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0";
 name="thread_timer.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="thread_timer.patch"

--- eval.c.orig	2008-08-03 20:24:26.000000000 -0700
+++ eval.c	2008-09-02 14:03:15.000000000 -0700
@@ -10761,6 +10761,8 @@
 #endif
 }
 
+static int thread_init;
+
 static void
 rb_thread_restore_context(th, exit)
     rb_thread_t th;
@@ -10801,6 +10803,12 @@
     rb_thread_die(th);
     th->prev->next = th->next;
     th->next->prev = th->prev;
+
+    /* if this is the last ruby thread, stop timer signals */
+    if (th->next == th->prev && th->next == main_thread) {
+      rb_thread_stop_timer();
+      thread_init = 0;
+    }
 }
 
 static int
@@ -12090,8 +12098,6 @@
     return th;
 }
 
-static int thread_init;
-
 #if defined(_THREAD_SAFE)
 static void
 catch_timer(sig)

--------------060304070208010802040906--