diff --git a/include/gambit.h.in b/include/gambit.h.in index 70285781d..1ea392c43 100644 --- a/include/gambit.h.in +++ b/include/gambit.h.in @@ -8002,9 +8002,10 @@ typedef struct ___mask_interrupts_state_struct } ___mask_interrupts_state; -typedef ___mask_interrupts_state ___mask_os_interrupts_state; +typedef ___mask_interrupts_state ___mask_all_interrupts_state; typedef ___mask_interrupts_state ___mask_user_interrupts_state; typedef ___mask_interrupts_state ___mask_heartbeat_interrupts_state; +typedef ___mask_interrupts_state ___mask_child_interrupts_state; /*---------------------------------------------------------------------------*/ @@ -10034,11 +10035,11 @@ typedef struct ___global_state_struct void (*___enable_interrupts_pstate) ___P((___processor_state ___ps), ()); - void (*___mask_os_interrupts_begin) - ___P((___mask_os_interrupts_state *state), + void (*___mask_all_interrupts_begin) + ___P((___mask_all_interrupts_state *state), ()); - void (*___mask_os_interrupts_end) - ___P((___mask_os_interrupts_state *state), + void (*___mask_all_interrupts_end) + ___P((___mask_all_interrupts_state *state), ()); void (*___mask_user_interrupts_begin) ___P((___mask_user_interrupts_state *state), @@ -10052,6 +10053,12 @@ typedef struct ___global_state_struct void (*___mask_heartbeat_interrupts_end) ___P((___mask_heartbeat_interrupts_state *state), ()); + void (*___mask_child_interrupts_begin) + ___P((___mask_child_interrupts_state *state), + ()); + void (*___mask_child_interrupts_end) + ___P((___mask_child_interrupts_state *state), + ()); #ifndef ___DEBUG_ALLOC_MEM void *(*___alloc_mem) ___P((___SIZE_T bytes), @@ -11389,11 +11396,11 @@ ___IMP_FUNC(void,___enable_interrupts_pstate) #endif #ifndef ___INCLUDED_FROM_OS_SETUP -___IMP_FUNC(void,___mask_os_interrupts_begin) - ___P((___mask_os_interrupts_state *state), +___IMP_FUNC(void,___mask_all_interrupts_begin) + ___P((___mask_all_interrupts_state *state), ()); -___IMP_FUNC(void,___mask_os_interrupts_end) - ___P((___mask_os_interrupts_state *state), +___IMP_FUNC(void,___mask_all_interrupts_end) + ___P((___mask_all_interrupts_state *state), ()); #endif @@ -11415,6 +11422,15 @@ ___IMP_FUNC(void,___mask_heartbeat_interrupts_end) ()); #endif +#ifndef ___INCLUDED_FROM_OS_IO +___IMP_FUNC(void,___mask_child_interrupts_begin) + ___P((___mask_child_interrupts_state *state), + ()); +___IMP_FUNC(void,___mask_child_interrupts_end) + ___P((___mask_child_interrupts_state *state), + ()); +#endif + #ifndef ___INCLUDED_FROM_OS_BASE #ifndef ___DEBUG_ALLOC_MEM ___IMP_FUNC(void *,___alloc_mem) diff --git a/lib/os_io.c b/lib/os_io.c index c8ee7717a..bd5dc3d53 100644 --- a/lib/os_io.c +++ b/lib/os_io.c @@ -8127,6 +8127,125 @@ ___BOOL use_pty;) #endif +#ifdef USE_POSIX + +___HIDDEN void sigchld_signal_handler + ___P((int sig), + (sig) +int sig;) +{ + int save_errno = errno; +#ifdef USE_signal + ___set_signal_handler (SIGCHLD, sigchld_signal_handler); +#endif + + /* + * A SIGCHLD signal indicates that at least one child has changed + * status. There may be more than one because signals are not + * queued. For example during a period when the SIGCHLD signal is + * blocked several child processes can terminate and only one call + * to the SIGCHLD handler will occur when the SIGCHLD signal is + * unblocked. For this reason we must call waitpid in a loop, until + * the last call indicates that no other child process is available. + */ + + for (;;) + { + int status; + ___device *head; + pid_t pid = ___waitpid_no_EINTR (-1, &status, WNOHANG); + + if (pid <= 0) + break; + + /* + * Find the process device structure for the process which + * terminated, and save the exit status with the process device. + */ + + head = ___global_device_group ()->list; + + if (head != NULL) + { + ___device *d = head->prev; + + do + { + if (___device_kind (d) == ___PROCESS_DEVICE_KIND) + { + ___device_process *dev = ___CAST(___device_process*,d); + + if (dev->pid == pid) + { + if (WIFEXITED(status) || WIFSIGNALED(status)) + ___device_process_status_set (dev, status); /* ignore error */ + break; + } + } + d = d->prev; + } while (d != head); + } + } + errno = save_errno; +} + +#endif + + +___SCMOBJ ___setup_child_interrupt_handling ___PVOID +{ +#ifdef USE_POSIX + + ___set_signal_handler (SIGPIPE, SIG_IGN); + ___set_signal_handler (SIGCHLD, sigchld_signal_handler); + + ___thread_sigmask1 (SIG_UNBLOCK, SIGCHLD, NULL); + +#endif + + return ___FIX(___NO_ERR); +} + + +void ___cleanup_child_interrupt_handling ___PVOID +{ +#ifdef USE_POSIX + + ___set_signal_handler (SIGPIPE, SIG_DFL); + ___set_signal_handler (SIGCHLD, SIG_DFL); + + ___thread_sigmask1 (SIG_UNBLOCK, SIGCHLD, NULL); + +#endif +} + + +___EXP_FUNC(void,___mask_child_interrupts_begin) + ___P((___mask_child_interrupts_state *state), + (state) +___mask_child_interrupts_state *state;) +{ +#ifdef USE_POSIX + + ___thread_sigmask1 (SIG_BLOCK, SIGCHLD, ___CAST(___sigset_type*,state)+2); + +#endif +} + + +___EXP_FUNC(void,___mask_child_interrupts_end) + ___P((___mask_child_interrupts_state *state), + (state) +___mask_child_interrupts_state *state;) +{ +#ifdef USE_POSIX + + ___thread_sigmask (SIG_SETMASK, ___CAST(___sigset_type*,state)+2, NULL); + +#endif +} + + #ifdef USE_CreateProcess #define ___ESCAPE_PROCESS_ARGS @@ -8356,7 +8475,9 @@ int options;) * sigchld_signal_handler will find it in the device group. */ - ___sigset_type oldmask = ___block_signal (SIGCHLD); + ___mask_all_interrupts_state all_interrupts; + + ___mask_all_interrupts_begin (&all_interrupts); fdp.input.writing_fd = -1; fdp.output.reading_fd = -1; @@ -8370,10 +8491,6 @@ int options;) e = err_code_from_errno (); else { - ___mask_os_interrupts_state os_interrupts; - - ___mask_os_interrupts_begin (&os_interrupts); - if ((pid = fork ()) < 0) { e = err_code_from_errno (); @@ -8383,9 +8500,6 @@ int options;) ___close_half_duplex_pipe (&fdp.output, 2); } } - - if (pid > 0) - ___mask_os_interrupts_end (&os_interrupts); } if (e != ___FIX(___NO_ERR)) @@ -8398,9 +8512,7 @@ int options;) { /* child process */ - ___restore_sigmask (oldmask); - - ___cleanup_os_interrupt_handling (); + ___cleanup_all_interrupt_handling (); if (options & (STDIN_REDIR | STDOUT_REDIR | STDERR_REDIR)) { @@ -8528,7 +8640,7 @@ int options;) ___close_half_duplex_pipe (&hdp_errno, 0); } - ___restore_sigmask (oldmask); + ___mask_all_interrupts_end (&all_interrupts); return e; @@ -9748,71 +9860,6 @@ ___SCMOBJ options;) } -#ifdef USE_POSIX - -___HIDDEN void sigchld_signal_handler - ___P((int sig), - (sig) -int sig;) -{ - int save_errno = errno; -#ifdef USE_signal - ___set_signal_handler (SIGCHLD, sigchld_signal_handler); -#endif - - /* - * A SIGCHLD signal indicates that at least one child has changed - * status. There may be more than one because signals are not - * queued. For example during a period when the SIGCHLD signal is - * blocked several child processes can terminate and only one call - * to the SIGCHLD handler will occur when the SIGCHLD signal is - * unblocked. For this reason we must call waitpid in a loop, until - * the last call indicates that no other child process is available. - */ - - for (;;) - { - int status; - ___device *head; - pid_t pid = ___waitpid_no_EINTR (-1, &status, WNOHANG); - - if (pid <= 0) - break; - - /* - * Find the process device structure for the process which - * terminated, and save the exit status with the process device. - */ - - head = ___global_device_group ()->list; - - if (head != NULL) - { - ___device *d = head->prev; - - do - { - if (___device_kind (d) == ___PROCESS_DEVICE_KIND) - { - ___device_process *dev = ___CAST(___device_process*,d); - - if (dev->pid == pid) - { - if (WIFEXITED(status) || WIFSIGNALED(status)) - ___device_process_status_set (dev, status); /* ignore error */ - break; - } - } - d = d->prev; - } while (d != head); - } - } - errno = save_errno; -} - -#endif - - /* - - - - - - - - - - - - - - - - - - */ /* Opening a TCP client. */ @@ -10752,11 +10799,7 @@ ___HIDDEN ___SCMOBJ io_module_setup ___PVOID if ((e = ___device_group_setup (&___io_mod.dgroup)) == ___FIX(___NO_ERR)) { -#ifdef USE_POSIX - - ___set_signal_handler (SIGCHLD, sigchld_signal_handler); - -#endif + ___setup_child_interrupt_handling (); /* ignore error */ #ifdef USE_WIN32 @@ -10786,11 +10829,7 @@ ___HIDDEN ___SCMOBJ io_module_setup ___PVOID ___HIDDEN void io_module_cleanup ___PVOID { -#ifdef USE_POSIX - - ___set_signal_handler (SIGCHLD, SIG_DFL); - -#endif + ___cleanup_child_interrupt_handling (); #ifdef USE_WIN32 diff --git a/lib/os_io.h b/lib/os_io.h index cbc167dac..e3c69403d 100644 --- a/lib/os_io.h +++ b/lib/os_io.h @@ -743,6 +743,8 @@ extern ___SCMOBJ ___os_device_process_status ___P((___SCMOBJ dev), ()); +extern void ___cleanup_child_interrupt_handling ___PVOID; + /* - - - - - - - - - - - - - - - - - - */ /* Opening a TCP client. */ diff --git a/lib/os_setup.c b/lib/os_setup.c index 2b339c06d..a2e7e9262 100644 --- a/lib/os_setup.c +++ b/lib/os_setup.c @@ -58,53 +58,6 @@ #ifdef USE_POSIX -___sigset_type ___block_signal - ___P((int signum), - (signum) -int signum;) -{ - ___sigset_type oldmask; - -#ifdef USE_sigaction - - ___sigset_type toblock; - - sigemptyset (&toblock); - sigaddset (&toblock, signum); - - ___thread_sigmask (SIG_BLOCK, &toblock, &oldmask); - -#endif - -#ifdef USE_signal - - oldmask = sigblock (sigmask (signum)); - -#endif - - return oldmask; -} - - -void ___restore_sigmask - ___P((___sigset_type oldmask), - (oldmask) -___sigset_type oldmask;) -{ -#ifdef USE_sigaction - - ___thread_sigmask (SIG_SETMASK, &oldmask, 0); - -#endif - -#ifdef USE_signal - - sigsetmask (oldmask); - -#endif -} - - /* * Some system calls can be interrupted by a signal and fail with * errno == EINTR. The following functions are wrappers for system @@ -308,40 +261,31 @@ int end;) /*---------------------------------------------------------------------------*/ -___SCMOBJ ___setup_os_interrupt_handling ___PVOID -{ - ___SCMOBJ e; - - if ((e = ___setup_heartbeat_interrupt_handling ()) == ___FIX(___NO_ERR)) - { - if ((e = ___setup_user_interrupt_handling ()) != ___FIX(___NO_ERR)) - ___cleanup_heartbeat_interrupt_handling (); - } - - return e; -} - -void ___cleanup_os_interrupt_handling ___PVOID +void ___cleanup_all_interrupt_handling ___PVOID { ___cleanup_user_interrupt_handling (); ___cleanup_heartbeat_interrupt_handling (); + ___cleanup_child_interrupt_handling (); } -void ___mask_os_interrupts_begin - ___P((___mask_os_interrupts_state *state), + +___EXP_FUNC(void,___mask_all_interrupts_begin) + ___P((___mask_all_interrupts_state *state), (state) -___mask_os_interrupts_state *state;) +___mask_all_interrupts_state *state;) { ___mask_user_interrupts_begin (state); ___mask_heartbeat_interrupts_begin (state); + ___mask_child_interrupts_begin (state); } -void ___mask_os_interrupts_end - ___P((___mask_os_interrupts_state *state), +___EXP_FUNC(void,___mask_all_interrupts_end) + ___P((___mask_all_interrupts_state *state), (state) -___mask_os_interrupts_state *state;) +___mask_all_interrupts_state *state;) { + ___mask_child_interrupts_end (state); ___mask_heartbeat_interrupts_end (state); ___mask_user_interrupts_end (state); } @@ -2982,7 +2926,6 @@ ___SCMOBJ ___setup_os ___PVOID if ((e = ___setup_tty_module (user_intr, terminate_intr)) == ___FIX(___NO_ERR)) { if ((e = ___setup_io_module ()) == ___FIX(___NO_ERR)) { #ifdef USE_POSIX - ___set_signal_handler (SIGPIPE, SIG_IGN); /***** belongs elsewhere */ #ifdef USE_CRASH_SIGNAL_HANDLER ___set_signal_handler (SIGTERM, crash_signal_handler); ___set_signal_handler (SIGBUS, crash_signal_handler); diff --git a/lib/os_setup.h b/lib/os_setup.h index 4a6f7b8c6..7b324eccd 100644 --- a/lib/os_setup.h +++ b/lib/os_setup.h @@ -8,6 +8,7 @@ #include "os.h" #include "os_tty.h" #include "os_time.h" +#include "os_io.h" /*---------------------------------------------------------------------------*/ @@ -16,14 +17,6 @@ #ifdef USE_POSIX -extern ___sigset_type ___block_signal - ___P((int signum), - ()); - -extern void ___restore_sigmask - ___P((___sigset_type oldmask), - ()); - extern pid_t ___waitpid_no_EINTR ___P((pid_t pid, int *stat_loc, @@ -68,9 +61,7 @@ extern void ___close_half_duplex_pipe /* Interrupt handling. */ -extern ___SCMOBJ ___setup_os_interrupt_handling ___PVOID; - -extern void ___cleanup_os_interrupt_handling ___PVOID; +extern void ___cleanup_all_interrupt_handling ___PVOID; /* CPU information. */ diff --git a/lib/os_shell.c b/lib/os_shell.c index bc6c840c4..db597e182 100644 --- a/lib/os_shell.c +++ b/lib/os_shell.c @@ -826,9 +826,9 @@ ___SCMOBJ cmd;) == ___FIX(___NO_ERR)) { int code; - ___mask_os_interrupts_state os_interrupts; + ___mask_all_interrupts_state all_interrupts; - ___mask_os_interrupts_begin (&os_interrupts); + ___mask_all_interrupts_begin (&all_interrupts); code = system (ccmd); @@ -837,7 +837,7 @@ ___SCMOBJ cmd;) else e = ___FIX(code & ___MAX_FIX); - ___mask_os_interrupts_end (&os_interrupts); + ___mask_all_interrupts_end (&all_interrupts); ___release_string (ccmd); } @@ -901,9 +901,9 @@ ___SCMOBJ dir;) e = err_code_from_errno (); else { - ___mask_os_interrupts_state os_interrupts; + ___mask_all_interrupts_state all_interrupts; - ___mask_os_interrupts_begin (&os_interrupts); + ___mask_all_interrupts_begin (&all_interrupts); code = system (ccmd); @@ -912,7 +912,7 @@ ___SCMOBJ dir;) else e = ___FIX(code & ___MAX_FIX); - ___mask_os_interrupts_end (&os_interrupts); + ___mask_all_interrupts_end (&all_interrupts); chdir (old_dir); /* ignore error */ } diff --git a/lib/os_thread.c b/lib/os_thread.c index 851ea4f59..dffa98049 100644 --- a/lib/os_thread.c +++ b/lib/os_thread.c @@ -1,6 +1,6 @@ /* File: "os_thread.c" */ -/* Copyright (c) 2013-2016 by Marc Feeley, All Rights Reserved. */ +/* Copyright (c) 2013-2017 by Marc Feeley, All Rights Reserved. */ /* * This module implements thread-related services. @@ -457,6 +457,25 @@ ___sigset_type *oldset;) #endif } +int ___thread_sigmask1 + ___P((int how, + int sig, + ___sigset_type *oldset), + (how, + sig, + oldset) +int how; +int sig; +___sigset_type *oldset;) +{ + ___sigset_type sigs; + + sigemptyset (&sigs); + sigaddset (&sigs, sig); + + ___thread_sigmask (how, &sigs, oldset); +} + #endif diff --git a/lib/os_thread.h b/lib/os_thread.h index 5f586b2e9..13dc11fdb 100644 --- a/lib/os_thread.h +++ b/lib/os_thread.h @@ -1,6 +1,6 @@ /* File: "os_thread.h" */ -/* Copyright (c) 2013-2016 by Marc Feeley, All Rights Reserved. */ +/* Copyright (c) 2013-2017 by Marc Feeley, All Rights Reserved. */ #ifndef ___OS_THREAD_H #define ___OS_THREAD_H @@ -86,7 +86,12 @@ extern int ___thread_sigmask ___sigset_type *set, ___sigset_type *oldset), ()); -#else + +extern int ___thread_sigmask1 + ___P((int how, + int sig, + ___sigset_type *oldset), + ()); #endif diff --git a/lib/os_time.c b/lib/os_time.c index 84ded6d05..5aabc0c66 100644 --- a/lib/os_time.c +++ b/lib/os_time.c @@ -1045,12 +1045,7 @@ ___mask_heartbeat_interrupts_state *state;) { #ifdef USE_POSIX - ___sigset_type toblock; - - sigemptyset (&toblock); - sigaddset (&toblock, HEARTBEAT_SIG); - - ___thread_sigmask (SIG_BLOCK, &toblock, ___CAST(___sigset_type*,state)+0); + ___thread_sigmask1 (SIG_BLOCK, HEARTBEAT_SIG, ___CAST(___sigset_type*,state)+0); #endif } @@ -1072,7 +1067,11 @@ ___mask_heartbeat_interrupts_state *state;) ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID { #ifdef USE_POSIX + ___set_signal_handler (HEARTBEAT_SIG, heartbeat_interrupt_handler); + + ___thread_sigmask1 (SIG_UNBLOCK, HEARTBEAT_SIG, NULL); + #endif return ___FIX(___NO_ERR); @@ -1084,7 +1083,11 @@ void ___cleanup_heartbeat_interrupt_handling ___PVOID ___set_heartbeat_interval (-1.0); #ifdef USE_POSIX + ___set_signal_handler (HEARTBEAT_SIG, SIG_IGN); + + ___thread_sigmask1 (SIG_UNBLOCK, HEARTBEAT_SIG, NULL); + #endif } diff --git a/lib/os_tty.c b/lib/os_tty.c index dea030acd..e59bef7c1 100644 --- a/lib/os_tty.c +++ b/lib/os_tty.c @@ -8582,6 +8582,18 @@ ___SCMOBJ ___setup_user_interrupt_handling ___PVOID ___set_signal_handler (SIGWINCH, tty_signal_handler); ___set_signal_handler (SIGCONT, tty_signal_handler); + { + ___sigset_type sigs; + + sigemptyset (&sigs); + sigaddset (&sigs, SIGINT); + sigaddset (&sigs, SIGTERM); + sigaddset (&sigs, SIGWINCH); + sigaddset (&sigs, SIGCONT); + + ___thread_sigmask (SIG_UNBLOCK, &sigs, NULL); + } + #endif #ifdef USE_WIN32 @@ -8603,6 +8615,18 @@ void ___cleanup_user_interrupt_handling ___PVOID ___set_signal_handler (SIGWINCH, SIG_DFL); ___set_signal_handler (SIGCONT, SIG_DFL); + { + ___sigset_type sigs; + + sigemptyset (&sigs); + sigaddset (&sigs, SIGINT); + sigaddset (&sigs, SIGTERM); + sigaddset (&sigs, SIGWINCH); + sigaddset (&sigs, SIGCONT); + + ___thread_sigmask (SIG_UNBLOCK, &sigs, NULL); + } + #endif #ifdef USE_WIN32 @@ -8613,28 +8637,28 @@ void ___cleanup_user_interrupt_handling ___PVOID } -void ___mask_user_interrupts_begin +___EXP_FUNC(void,___mask_user_interrupts_begin) ___P((___mask_user_interrupts_state *state), (state) ___mask_user_interrupts_state *state;) { #ifdef USE_POSIX - ___sigset_type toblock; + ___sigset_type sigs; - sigemptyset (&toblock); - sigaddset (&toblock, SIGINT); - sigaddset (&toblock, SIGTERM); - sigaddset (&toblock, SIGWINCH); - sigaddset (&toblock, SIGCONT); + sigemptyset (&sigs); + sigaddset (&sigs, SIGINT); + sigaddset (&sigs, SIGTERM); + sigaddset (&sigs, SIGWINCH); + sigaddset (&sigs, SIGCONT); - ___thread_sigmask (SIG_BLOCK, &toblock, ___CAST(___sigset_type*,state)+1); + ___thread_sigmask (SIG_BLOCK, &sigs, ___CAST(___sigset_type*,state)+1); #endif } -void ___mask_user_interrupts_end +___EXP_FUNC(void,___mask_user_interrupts_end) ___P((___mask_user_interrupts_state *state), (state) ___mask_user_interrupts_state *state;) diff --git a/lib/setup.c b/lib/setup.c index 1bdcb66a7..b2e68ac93 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -3421,7 +3421,7 @@ ___EXP_FUNC(void,___cleanup) ___PVOID ___GSTATE->setup_state = 2; - ___cleanup_os_interrupt_handling (); + ___cleanup_all_interrupt_handling (); #ifndef ___SINGLE_THREADED_VMS @@ -4476,11 +4476,11 @@ ___HIDDEN void setup_dynamic_linking ___PVOID ___GSTATE->___enable_interrupts_pstate = ___enable_interrupts_pstate; - ___GSTATE->___mask_os_interrupts_begin - = ___mask_os_interrupts_begin; + ___GSTATE->___mask_all_interrupts_begin + = ___mask_all_interrupts_begin; - ___GSTATE->___mask_os_interrupts_end - = ___mask_os_interrupts_end; + ___GSTATE->___mask_all_interrupts_end + = ___mask_all_interrupts_end; ___GSTATE->___mask_user_interrupts_begin = ___mask_user_interrupts_begin; @@ -4494,6 +4494,12 @@ ___HIDDEN void setup_dynamic_linking ___PVOID ___GSTATE->___mask_heartbeat_interrupts_end = ___mask_heartbeat_interrupts_end; + ___GSTATE->___mask_child_interrupts_begin + = ___mask_child_interrupts_begin; + + ___GSTATE->___mask_child_interrupts_end + = ___mask_child_interrupts_end; + ___GSTATE->___alloc_mem = ___alloc_mem;