accomodate signal-handler calls from multiple threads

svn: r9225
This commit is contained in:
Matthew Flatt 2008-04-09 18:54:46 +00:00
parent 2a17f76cec
commit e4190d765f
12 changed files with 106 additions and 50 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
/*========================================================================*/

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);
}