From e4190d765fadf262f1bd0f8a6c7906cc7bd45850 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 9 Apr 2008 18:54:46 +0000 Subject: [PATCH] accomodate signal-handler calls from multiple threads svn: r9225 --- src/mred/mred.cxx | 7 +-- src/mzscheme/include/mzscheme.exp | 2 + src/mzscheme/include/mzscheme3m.exp | 2 + src/mzscheme/include/mzwin.def | 2 + src/mzscheme/include/mzwin3m.def | 2 + src/mzscheme/main.c | 2 +- src/mzscheme/src/port.c | 70 ++++++++++++++++------------- src/mzscheme/src/schemef.h | 2 + src/mzscheme/src/schemex.h | 2 + src/mzscheme/src/schemex.inc | 2 + src/mzscheme/src/schemexm.h | 2 + src/mzscheme/src/thread.c | 61 +++++++++++++++++++------ 12 files changed, 106 insertions(+), 50 deletions(-) diff --git a/src/mred/mred.cxx b/src/mred/mred.cxx index 62cc7673fd..628146db29 100644 --- a/src/mred/mred.cxx +++ b/src/mred/mred.cxx @@ -1655,6 +1655,7 @@ void wxDoEvents() c->main_cells, c->main_break_cell, NULL, 0); + scheme_set_break_main_target(user_main_thread); cp = scheme_intern_symbol("mred"); user_main_thread->name = cp; } @@ -1778,7 +1779,7 @@ static void MrEdSleep(float secs, void *fds) #ifdef mred_BREAK_HANDLER static void user_break_hit(int ignore) { - scheme_break_thread(user_main_thread); + scheme_break_main_thread(); scheme_signal_received(); # ifdef SIGSET_NEEDS_REINSTALL @@ -2369,7 +2370,7 @@ void IOFrame::OnMenuCommand(long id) else if (id == 81) media->Paste(); else if (id == 83) - scheme_break_thread(user_main_thread); + scheme_break_main_thread(); else if (id == 77) if (OnClose()) Show(FALSE); @@ -2448,7 +2449,7 @@ static Bool RecordInput(void *m, wxEvent *event, void *data) static Bool SendBreak(void *m, wxEvent *event, void *data) { - scheme_break_thread(user_main_thread); + scheme_break_main_thread(); return TRUE; } diff --git a/src/mzscheme/include/mzscheme.exp b/src/mzscheme/include/mzscheme.exp index 573d2a3df8..ac4619a0f9 100644 --- a/src/mzscheme/include/mzscheme.exp +++ b/src/mzscheme/include/mzscheme.exp @@ -26,6 +26,8 @@ scheme_thread scheme_thread_w_details scheme_kill_thread scheme_break_thread +scheme_break_main_thread +scheme_set_break_main_target scheme_thread_block scheme_thread_block_enable_break scheme_swap_thread diff --git a/src/mzscheme/include/mzscheme3m.exp b/src/mzscheme/include/mzscheme3m.exp index 3c9e7726b8..4356c177b7 100644 --- a/src/mzscheme/include/mzscheme3m.exp +++ b/src/mzscheme/include/mzscheme3m.exp @@ -26,6 +26,8 @@ scheme_thread scheme_thread_w_details scheme_kill_thread scheme_break_thread +scheme_break_main_thread +scheme_set_break_main_target scheme_thread_block scheme_thread_block_enable_break scheme_swap_thread diff --git a/src/mzscheme/include/mzwin.def b/src/mzscheme/include/mzwin.def index 18f8c4a9cb..38e4997f66 100644 --- a/src/mzscheme/include/mzwin.def +++ b/src/mzscheme/include/mzwin.def @@ -28,6 +28,8 @@ EXPORTS scheme_thread_w_details scheme_kill_thread scheme_break_thread + scheme_break_main_thread + scheme_set_break_main_target scheme_thread_block scheme_thread_block_enable_break scheme_swap_thread diff --git a/src/mzscheme/include/mzwin3m.def b/src/mzscheme/include/mzwin3m.def index bad3ebd97c..d0c45119dd 100644 --- a/src/mzscheme/include/mzwin3m.def +++ b/src/mzscheme/include/mzwin3m.def @@ -28,6 +28,8 @@ EXPORTS scheme_thread_w_details scheme_kill_thread scheme_break_thread + scheme_break_main_thread + scheme_set_break_main_target scheme_thread_block scheme_thread_block_enable_break scheme_swap_thread diff --git a/src/mzscheme/main.c b/src/mzscheme/main.c index dad5ba3c2f..d0806c52d3 100644 --- a/src/mzscheme/main.c +++ b/src/mzscheme/main.c @@ -169,7 +169,7 @@ extern Scheme_Object *scheme_initialize(Scheme_Env *env); static void user_break_hit(int ignore) { - scheme_break_thread(NULL); + scheme_break_main_thread(); scheme_signal_received(); # ifdef SIGSET_NEEDS_REINSTALL diff --git a/src/mzscheme/src/port.c b/src/mzscheme/src/port.c index 912a2dab61..d7c018f235 100644 --- a/src/mzscheme/src/port.c +++ b/src/mzscheme/src/port.c @@ -6458,38 +6458,7 @@ void scheme_block_child_signals(int block) static void child_done(int ingored) { - pid_t result; - int status; - System_Child *sc, *prev; - - do { - do { - result = WAITANY(&status); - } while ((result == -1) && (errno == EINTR)); - - if (result > 0) { - if (WIFEXITED(status)) - status = WEXITSTATUS(status); - else - status = MZ_FAILURE_STATUS; - - prev = NULL; - for (sc = scheme_system_children; sc; prev = sc, sc = sc->next) { - if (sc->id == result) { - sc->done = 1; - sc->status = status; - - if (prev) { - prev->next = sc->next; - } else - scheme_system_children = sc->next; - - scheme_signal_received(); - break; - } - } - } - } while (result > 0); + scheme_signal_received(); # ifdef SIGSET_NEEDS_REINSTALL MZ_SIGSET(SIGCHLD, child_done); @@ -6514,6 +6483,43 @@ static void init_sigchld(void) } } +void scheme_check_child_done() +{ + pid_t result; + int status; + System_Child *sc, *prev; + + if (scheme_system_children) { + do { + do { + result = WAITANY(&status); + } while ((result == -1) && (errno == EINTR)); + + if (result > 0) { + if (WIFEXITED(status)) + status = WEXITSTATUS(status); + else + status = MZ_FAILURE_STATUS; + + prev = NULL; + for (sc = scheme_system_children; sc; prev = sc, sc = sc->next) { + if (sc->id == result) { + sc->done = 1; + sc->status = status; + + if (prev) { + prev->next = sc->next; + } else + scheme_system_children = sc->next; + + break; + } + } + } + } while (result > 0); + } +} + #endif /*========================================================================*/ diff --git a/src/mzscheme/src/schemef.h b/src/mzscheme/src/schemef.h index 6cb1547f68..9c205eac42 100644 --- a/src/mzscheme/src/schemef.h +++ b/src/mzscheme/src/schemef.h @@ -92,6 +92,8 @@ MZ_EXTERN Scheme_Object *scheme_thread_w_details(Scheme_Object *thunk, int suspend_to_kill); MZ_EXTERN void scheme_kill_thread(Scheme_Thread *p); MZ_EXTERN void scheme_break_thread(Scheme_Thread *p); +MZ_EXTERN void scheme_break_main_thread(); +MZ_EXTERN void scheme_set_break_main_target(Scheme_Thread *p); MZ_EXTERN void scheme_thread_block(float sleep_time); MZ_EXTERN void scheme_thread_block_enable_break(float sleep_time, int enable); diff --git a/src/mzscheme/src/schemex.h b/src/mzscheme/src/schemex.h index 8bc63f83ab..a0a3def468 100644 --- a/src/mzscheme/src/schemex.h +++ b/src/mzscheme/src/schemex.h @@ -74,6 +74,8 @@ Scheme_Object *(*scheme_thread_w_details)(Scheme_Object *thunk, int suspend_to_kill); void (*scheme_kill_thread)(Scheme_Thread *p); void (*scheme_break_thread)(Scheme_Thread *p); +void (*scheme_break_main_thread)(); +void (*scheme_set_break_main_target)(Scheme_Thread *p); void (*scheme_thread_block)(float sleep_time); void (*scheme_thread_block_enable_break)(float sleep_time, int enable); void (*scheme_swap_thread)(Scheme_Thread *process); diff --git a/src/mzscheme/src/schemex.inc b/src/mzscheme/src/schemex.inc index 72d26b5db2..042421041b 100644 --- a/src/mzscheme/src/schemex.inc +++ b/src/mzscheme/src/schemex.inc @@ -34,6 +34,8 @@ scheme_extension_table->scheme_thread_w_details = scheme_thread_w_details; scheme_extension_table->scheme_kill_thread = scheme_kill_thread; scheme_extension_table->scheme_break_thread = scheme_break_thread; + scheme_extension_table->scheme_break_main_thread = scheme_break_main_thread; + scheme_extension_table->scheme_set_break_main_target = scheme_set_break_main_target; scheme_extension_table->scheme_thread_block = scheme_thread_block; scheme_extension_table->scheme_thread_block_enable_break = scheme_thread_block_enable_break; scheme_extension_table->scheme_swap_thread = scheme_swap_thread; diff --git a/src/mzscheme/src/schemexm.h b/src/mzscheme/src/schemexm.h index a4c7f66821..24be57000d 100644 --- a/src/mzscheme/src/schemexm.h +++ b/src/mzscheme/src/schemexm.h @@ -34,6 +34,8 @@ #define scheme_thread_w_details (scheme_extension_table->scheme_thread_w_details) #define scheme_kill_thread (scheme_extension_table->scheme_kill_thread) #define scheme_break_thread (scheme_extension_table->scheme_break_thread) +#define scheme_break_main_thread (scheme_extension_table->scheme_break_main_thread) +#define scheme_set_break_main_target (scheme_extension_table->scheme_set_break_main_target) #define scheme_thread_block (scheme_extension_table->scheme_thread_block) #define scheme_thread_block_enable_break (scheme_extension_table->scheme_thread_block_enable_break) #define scheme_swap_thread (scheme_extension_table->scheme_swap_thread) diff --git a/src/mzscheme/src/thread.c b/src/mzscheme/src/thread.c index 292e883b3c..048ed5e580 100644 --- a/src/mzscheme/src/thread.c +++ b/src/mzscheme/src/thread.c @@ -95,6 +95,10 @@ extern HANDLE scheme_break_semaphore; #include "schfd.h" +#if defined(UNIX_PROCESSES) +extern void scheme_check_child_done(); +#endif + #define DEFAULT_INIT_STACK_SIZE 1000 #define MAX_INIT_STACK_SIZE 100000 @@ -119,6 +123,8 @@ extern void scheme_gmp_tls_unload(long *s); extern void scheme_gmp_tls_snapshot(long *s, long *save); extern void scheme_gmp_tls_restore_snapshot(long *s, long *save, int do_free); +static void check_ready_break(); + extern int scheme_num_read_syntax_objects; extern int scheme_hash_request_count; extern int scheme_hash_iteration_count; @@ -210,7 +216,8 @@ extern MZ_DLLIMPORT void (*GC_collect_end_callback)(void); static void get_ready_for_GC(void); static void done_with_GC(void); -static short delay_breaks = 0, delayed_break_ready = 0; +static volatile short delayed_break_ready = 0; +static Scheme_Thread *main_break_target_thread; void (*scheme_sleep)(float seconds, void *fds); void (*scheme_notify_multithread)(int on); @@ -3216,6 +3223,8 @@ Scheme_Object *scheme_call_as_nested_thread(int argc, Scheme_Object *argv[], voi GC cleaning for this thread: */ prepare_this_thread_for_GC(p); + check_ready_break(); + np->nester = p; p->nestee = np; np->external_break = p->external_break; @@ -3579,6 +3588,8 @@ void scheme_check_break_now(void) { Scheme_Thread *p = scheme_current_thread; + check_ready_break(); + if (p->external_break && scheme_can_break(p)) { scheme_thread_block_w_thread(0.0, p); p->ran_some = 1; @@ -3726,14 +3737,36 @@ static void exit_or_escape(Scheme_Thread *p) select_thread(); } -void scheme_break_thread(Scheme_Thread *p) - /* This function can be called from an interrupt handler. */ +void scheme_break_main_thread() +/* This function can be called from an interrupt handler. + On some platforms, it will even be called from multiple + OS threads. In the case of multiple threads, there's a + tiny chance that a single Ctl-C will trigger multiple + break exceptions. */ { - if (delay_breaks) { - delayed_break_ready = 1; - return; - } + delayed_break_ready = 1; +} +void scheme_set_break_main_target(Scheme_Thread *p) +{ + if (!main_break_target_thread) { + REGISTER_SO(main_break_target_thread); + } + main_break_target_thread = p; +} + +static void check_ready_break() +{ + if (delayed_break_ready) { + if (scheme_main_thread) { + delayed_break_ready = 0; + scheme_break_thread(main_break_target_thread); + } + } +} + +void scheme_break_thread(Scheme_Thread *p) +{ if (!p) { p = scheme_main_thread; if (!p) @@ -3801,6 +3834,8 @@ void scheme_thread_block(float sleep_time) start_sleep_check: + check_ready_break(); + if (!p->external_break && !p->next && scheme_check_for_break && scheme_check_for_break()) p->external_break = 1; @@ -3818,6 +3853,10 @@ void scheme_thread_block(float sleep_time) /* Check scheduled_kills early and often. */ check_scheduled_kills(); +#if defined(UNIX_PROCESSES) + scheme_check_child_done(); +#endif + if (!do_atomic && (sleep_end >= 0.0)) { double msecs = 0.0; @@ -4029,6 +4068,7 @@ void scheme_thread_block(float sleep_time) } /* Check for external break again after swap or sleep */ + check_ready_break(); if (p->external_break && !p->suspend_break && scheme_can_break(p)) { raise_break(p); } @@ -7108,9 +7148,6 @@ static void get_ready_for_GC() #endif did_gc_count++; - - delayed_break_ready = 0; - delay_breaks = 1; } extern int GC_words_allocd; @@ -7132,10 +7169,6 @@ static void done_with_GC() scheme_block_child_signals(0); #endif - delay_breaks = 0; - if (delayed_break_ready) - scheme_break_thread(NULL); - scheme_total_gc_time += (scheme_get_process_milliseconds() - start_this_gc_time); }