1=== ruby.h
2==================================================================
3--- ruby.h	(/trunk)	(revision 16)
4+++ ruby.h	(/branches/thread-hooks)	(revision 16)
5@@ -724,6 +724,19 @@
6 void ruby_native_thread_kill _((int));
7 #endif
8 
9+
10+typedef unsigned int rb_threadswitch_event_t;
11+
12+#define RUBY_THREADSWITCH_INIT 0x01
13+#define RUBY_THREADSWITCH_FREE 0x02
14+#define RUBY_THREADSWITCH_SAVE 0x04
15+#define RUBY_THREADSWITCH_RESTORE 0x08
16+
17+typedef void (*rb_threadswitch_hook_func_t) _((rb_threadswitch_event_t,VALUE));
18+
19+void *rb_add_threadswitch_hook _((rb_threadswitch_hook_func_t func));
20+void rb_remove_threadswitch_hook _((void *handle));
21+
22 #if defined(__cplusplus)
23 #if 0
24 { /* satisfy cc-mode */
25=== eval.c
26==================================================================
27--- eval.c	(/trunk)	(revision 16)
28+++ eval.c	(/branches/thread-hooks)	(revision 16)
29@@ -227,6 +227,25 @@
30 
31 #include <sys/stat.h>
32 
33+
34+typedef struct threadswitch_hook {
35+    rb_threadswitch_hook_func_t func;
36+    struct threadswitch_hook *next;
37+} rb_threadswitch_hook_t;
38+
39+static rb_threadswitch_hook_t *threadswitch_hooks;
40+
41+#define EXEC_THREADSWITCH_HOOK(event, thread) \
42+    do { \
43+	rb_threadswitch_hook_t *hook = threadswitch_hooks; \
44+	\
45+	while (hook) { \
46+	    (*hook->func)(event, thread); \
47+            hook = hook->next; \
48+	} \
49+    } while (0)
50+
51+
52 VALUE rb_cProc;
53 VALUE rb_cBinding;
54 static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE));
55@@ -10131,6 +10150,8 @@
56 thread_free(th)
57     rb_thread_t th;
58 {
59+    EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_FREE,th->thread);
60+
61     if (th->stk_ptr) free(th->stk_ptr);
62     th->stk_ptr = 0;
63 #ifdef __ia64__
64@@ -10181,6 +10202,8 @@
65     VALUE *pos;
66     int len;
67     static VALUE tval;
68+    
69+    EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_SAVE,th->thread);
70 
71     len = ruby_stack_length(&pos);
72     th->stk_len = 0;
73@@ -10313,6 +10336,8 @@
74 
75     if (!th->stk_ptr) rb_bug("unsaved context");
76 
77+    EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_RESTORE,th->thread);
78+
79 #if STACK_GROW_DIRECTION < 0
80     if (&v > th->stk_pos) stack_extend(th, exit);
81 #elif STACK_GROW_DIRECTION > 0
82@@ -10452,6 +10477,41 @@
83     rb_thread_main_jump(e, RESTORE_RAISE);
84 }
85 
86+void *
87+rb_add_threadswitch_hook(func)
88+    rb_threadswitch_hook_func_t func;
89+{
90+    rb_threadswitch_hook_t *hook;
91+    rb_thread_t th;
92+
93+    hook = ALLOC(rb_threadswitch_hook_t);
94+    hook->func = func;
95+    hook->next = threadswitch_hooks;
96+    threadswitch_hooks = hook;
97+
98+    FOREACH_THREAD(th) {
99+    	(*func)(RUBY_THREADSWITCH_INIT, th->thread);
100+    } END_FOREACH(th);
101+
102+    return hook;
103+}
104+
105+void
106+rb_remove_threadswitch_hook(handle)
107+    void *handle;
108+{
109+    rb_threadswitch_hook_t **hook_p, *hook;
110+	
111+    for (hook_p = &threadswitch_hooks; *hook_p; hook_p = &hook->next) {
112+	hook = *hook_p;
113+	if (hook == (rb_threadswitch_hook_t*)handle) {
114+	    *hook_p = hook->next;
115+	    xfree(hook);
116+	    return;
117+	}
118+    }
119+}
120+
121 static void
122 copy_fds(dst, src, max)
123     fd_set *dst, *src;
124@@ -11631,6 +11691,8 @@
125     THREAD_ALLOC(th);
126     th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th);
127 
128+    EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_INIT,th->thread);
129+
130     for (vars = th->dyna_vars; vars; vars = vars->next) {
131 	if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
132 	FL_SET(vars, DVAR_DONT_RECYCLE);
133