diff --git a/common/os_calls.c b/common/os_calls.c index 1afeb5703e..6739a647c4 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -2987,10 +2987,28 @@ g_set_alarm(void (*func)(int), unsigned int secs) #if defined(_WIN32) return 0; #else + struct sigaction action; + /* Cancel any previous alarm to prevent a race */ unsigned int rv = alarm(0); - signal(SIGALRM, func); - (void)alarm(secs); + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGALRM, &action, NULL); + if (func != NULL && secs > 0) + { + (void)alarm(secs); + } return rv; #endif } @@ -3002,7 +3020,22 @@ g_signal_child_stop(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGCHLD, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + // Don't need to know when children are stopped or started + action.sa_flags = (SA_RESTART | SA_NOCLDSTOP); + } + sigemptyset (&action.sa_mask); + + sigaction(SIGCHLD, &action, NULL); #endif } @@ -3013,7 +3046,21 @@ g_signal_segfault(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGSEGV, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESETHAND; // This is a one-shot + } + sigemptyset (&action.sa_mask); + + sigaction(SIGSEGV, &action, NULL); #endif } @@ -3024,7 +3071,21 @@ g_signal_hang_up(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGHUP, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGHUP, &action, NULL); #endif } @@ -3035,7 +3096,21 @@ g_signal_user_interrupt(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGINT, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGINT, &action, NULL); #endif } @@ -3046,7 +3121,21 @@ g_signal_terminate(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGTERM, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGTERM, &action, NULL); #endif } @@ -3057,7 +3146,21 @@ g_signal_pipe(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGPIPE, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGPIPE, &action, NULL); #endif } @@ -3068,7 +3171,21 @@ g_signal_usr1(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGUSR1, func); + struct sigaction action; + + if (func == NULL) + { + action.sa_handler = SIG_DFL; + action.sa_flags = 0; + } + else + { + action.sa_handler = func; + action.sa_flags = SA_RESTART; + } + sigemptyset (&action.sa_mask); + + sigaction(SIGUSR1, &action, NULL); #endif } diff --git a/common/os_calls.h b/common/os_calls.h index 2d5c18e679..6579d1163a 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -176,6 +176,14 @@ g_sck_get_peer_ip_address(int sck, const char * g_sck_get_peer_description(int sck, char *desc, unsigned int bytes); +/** + * Sleep for the specified number of milli-seconds + * @param msecs Milli-seconds + * + * If a signal is processed, it is possible that this call will + * sleep for less than the specified number of milli-seconds. This + * is platform-specific + */ void g_sleep(int msecs); int g_pipe(int fd[2]); @@ -275,13 +283,56 @@ int g_execvp(const char *p1, char *args[]); */ int g_execvp_list(const char *file, struct list *argv); int g_execlp3(const char *a1, const char *a2, const char *a3); +/** + * Set an alarm using SIGALRM + * @param func Signal handler, or NULL to cancel an alarm + * @param secs Number of seconds until an alarm is raised + * @return Number of seconds remaining before a previously requested + * alarm is raised + */ unsigned int g_set_alarm(void (*func)(int), unsigned int secs); +/** + * Set a handler up for SIGCHLD + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_child_stop(void (*func)(int)); +/** + * Set a handler up for SIGSEGV + * @param func signal handler, or NULL to restore the default handler + * The handler can only be called once, at which point the + * default handler is restored. This is to avoid infinite loops + */ void g_signal_segfault(void (*func)(int)); +/** + * Set a handler up for SIGHUP + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_hang_up(void (*func)(int)); +/** + * Set a handler up for SIGINT + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_user_interrupt(void (*func)(int)); +/** + * Set a handler up for SIGTERM + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_terminate(void (*func)(int)); +/** + * Set a handler up for SIGPIPE + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_pipe(void (*func)(int)); +/** + * Set a handler up for SIGUSR1 + * @param func signal handler, or NULL to restore the default handler + * The handler remains in place until explicitly replaced. + */ void g_signal_usr1(void (*func)(int)); int g_fork(void); int g_setgid(int pid); diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am index de4b0a3c7c..8294afcbd0 100644 --- a/tests/common/Makefile.am +++ b/tests/common/Makefile.am @@ -18,6 +18,7 @@ test_common_SOURCES = \ test_list_calls.c \ test_string_calls.c \ test_os_calls.c \ + test_os_calls_signals.c \ test_ssl_calls.c \ test_base64.c \ test_guid.c diff --git a/tests/common/test_common.h b/tests/common/test_common.h index 09f3acf1d8..ea700c30b8 100644 --- a/tests/common/test_common.h +++ b/tests/common/test_common.h @@ -15,4 +15,9 @@ Suite *make_suite_test_ssl_calls(void); Suite *make_suite_test_base64(void); Suite *make_suite_test_guid(void); +TCase *make_tcase_test_os_calls_signals(void); + +void os_calls_signals_init(void); +void os_calls_signals_deinit(void); + #endif /* TEST_COMMON_H */ diff --git a/tests/common/test_common_main.c b/tests/common/test_common_main.c index ec3f579db8..05eacd2775 100644 --- a/tests/common/test_common_main.c +++ b/tests/common/test_common_main.c @@ -64,14 +64,17 @@ int main (void) * reporting when running in libcheck fork mode */ setvbuf(stdout, NULL, _IONBF, 0); - /* Initialise the ssl module */ + /* Initialise modules */ ssl_init(); + os_calls_signals_init(); srunner_run_all (sr, CK_ENV); number_failed = srunner_ntests_failed(sr); srunner_free(sr); ssl_finish(); + os_calls_signals_deinit(); + log_end(); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/common/test_os_calls.c b/tests/common/test_os_calls.c index e0f44bbc1b..c2a3e09e8b 100644 --- a/tests/common/test_os_calls.c +++ b/tests/common/test_os_calls.c @@ -512,5 +512,9 @@ make_suite_test_os_calls(void) tcase_add_test(tc_os_calls, test_g_file_is_open); tcase_add_test(tc_os_calls, test_g_sck_fd_passing); tcase_add_test(tc_os_calls, test_g_sck_fd_overflow); + + // Add other test cases in other files + suite_add_tcase(s, make_tcase_test_os_calls_signals()); + return s; }