Having further investigated, I'm convinced that this is a bug. Attached are two minimal C programs. Both create threads that do nothing but sleep for 2 seconds and then exit. The parent tries to join with the child thread, with a timeout of 10 seconds.
The only difference is that test1 uses scm_spawn_thread, and test2 uses scm_call_with_new_thread. test1 always times out, and test2 works properly. Having looked at the code in threads.c, I'm surprised that either of them work. Both scm_spawn_thread and scm_call_with_new_thread arrange for pthread_detach to be called in the child (in spawn_thread and launch_thread, respectively). This is supposed to make the child un-joinable. I've attached not only test1.c and test2.c, but also the diff between them. I compiled them as follows: gcc -o test1 test1.c $(pkg-config --cflags --libs guile-2.0) gcc -o test2 test2.c $(pkg-config --cflags --libs guile-2.0) Any ideas? Thanks, Mark
#include <libguile.h> static SCM thread_main (void *data) { /* scm_sleep (scm_from_signed_integer (20)); /* This should cause a timeout */ /* scm_sleep (SCM_BOOL_T); /* This should throw an exception */ scm_sleep (scm_from_signed_integer (2)); /* This should finish */ return scm_from_latin1_string ("finished"); } static SCM thread_handler (void *data, SCM key, SCM args) { return scm_from_latin1_string ("exception thrown"); } static void * inner_main (void *data) { SCM thread = scm_spawn_thread (thread_main, 0, thread_handler, 0); SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10)); SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out")); scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result)); } int main (int argc, char **argv) { scm_with_guile (inner_main, 0); return 0; }
#include <libguile.h> static SCM thread_main (void) { /* scm_sleep (scm_from_signed_integer (20)); /* This should cause a timeout */ /* scm_sleep (SCM_BOOL_T); /* This should throw an exception */ scm_sleep (scm_from_signed_integer (2)); /* This should finish */ return scm_from_latin1_string ("finished"); } static SCM thread_handler (SCM handler, SCM key, SCM args) { return scm_from_latin1_string ("exception thrown"); } static void * inner_main (void *data) { SCM thread_main_proc = scm_c_make_gsubr ("thread-main", 0, 0, 0, thread_main); SCM thread_handler_proc = scm_c_make_gsubr ("thread-handler", 2, 0, 1, thread_handler); SCM thread = scm_call_with_new_thread (thread_main_proc, thread_handler_proc); SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10)); SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out")); scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result)); } int main (int argc, char **argv) { scm_with_guile (inner_main, 0); return 0; }
--- test1.c 2011-03-09 01:33:36.000000000 -0500 +++ test2.c 2011-03-09 01:34:18.000000000 -0500 @@ -1,7 +1,7 @@ #include <libguile.h> static SCM -thread_main (void *data) +thread_main (void) { /* scm_sleep (scm_from_signed_integer (20)); /* This should cause a timeout */ /* scm_sleep (SCM_BOOL_T); /* This should throw an exception */ @@ -10,7 +10,7 @@ } static SCM -thread_handler (void *data, SCM key, SCM args) +thread_handler (SCM handler, SCM key, SCM args) { return scm_from_latin1_string ("exception thrown"); } @@ -18,7 +18,9 @@ static void * inner_main (void *data) { + SCM thread_main_proc = scm_c_make_gsubr ("thread-main", 0, 0, 0, thread_main); + SCM thread_handler_proc = scm_c_make_gsubr ("thread-handler", 2, 0, 1, thread_handler); - SCM thread = scm_spawn_thread (thread_main, 0, thread_handler, 0); + SCM thread = scm_call_with_new_thread (thread_main_proc, thread_handler_proc); SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10)); SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out")); scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result));