From: Joshua Haberman Date: 2006-03-20T06:41:52+09:00 Subject: [PATCH] async thread wakeup --Apple-Mail-4--858943661 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed I emailed ruby-core about this a while back, but got no response, so here is a patch to make my question more concrete. This patch adds a hook into the thread scheduler that extensions can use to wake up a thread asynchronously. It is a function you can safely call from any thread. It will mark the thread runnable, so that the thread scheduler will consider running it the next time around. It is similar in concept to the catch_timer() callback that sets rb_thread_pending: set a flag asynchronously that is then checked from the Ruby thread. The function returns false (and does nothing) if the thread passed to it is not valid. I refactored rb_thread_check slightly to support this. Please let me know if this is suitable for inclusion in the main Ruby distribution. Thanks, Josh --Apple-Mail-4--858943661 Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="async_thread_wakeup.patch" Content-Disposition: attachment; filename=async_thread_wakeup.patch ? .eval.c.swp ? .intern.h.swp ? .ruby.h.swp ? async_thread_wakeup.patch ? ext/ripper/mkmf.log Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.890 diff -d -u -r1.890 eval.c --- eval.c 23 Feb 2006 04:24:39 -0000 1.890 +++ eval.c 19 Mar 2006 21:25:53 -0000 @@ -10112,15 +10112,25 @@ } static rb_thread_t -rb_thread_check(VALUE data) +rb_thread_get(VALUE data) { if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)thread_mark) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", - rb_obj_classname(data)); + return NULL; } return (rb_thread_t)RDATA(data)->data; } +static rb_thread_t +rb_thread_check(VALUE data) +{ + rb_thread_t th = rb_thread_get(data); + + if (th) return th; + + rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", + rb_obj_classname(data)); +} + static VALUE rb_thread_raise(int, VALUE*, rb_thread_t); static VALUE th_raise_exception; @@ -10769,6 +10779,18 @@ rb_thread_restore_context(next, RESTORE_NORMAL); } +/* + * Can be called asynchronously (in a different thread from the + * Ruby interpreter). + */ +int +rb_thread_async_wakeup(VALUE thread) +{ + rb_thread_t th = rb_thread_get(thread); + if (th) th->status = THREAD_RUNNABLE; + return th != NULL; +} + void rb_thread_wait_fd(int fd) { Index: intern.h =================================================================== RCS file: /src/ruby/intern.h,v retrieving revision 1.193 diff -d -u -r1.193 intern.h --- intern.h 17 Feb 2006 08:40:51 -0000 1.193 +++ intern.h 19 Mar 2006 21:25:53 -0000 @@ -275,6 +275,7 @@ void rb_thread_signal_exit(void); int rb_thread_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); void rb_thread_wait_for(struct timeval); +int rb_thread_async_wakeup(VALUE thread); VALUE rb_thread_current(void); VALUE rb_thread_main(void); VALUE rb_thread_local_aref(VALUE, ID); --Apple-Mail-4--858943661--