-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for signal functions in os_calls.c
- Loading branch information
1 parent
d11617a
commit d098214
Showing
1 changed file
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
|
||
#if defined(HAVE_CONFIG_H) | ||
#include "config_ac.h" | ||
#endif | ||
|
||
#include <signal.h> | ||
|
||
#include "os_calls.h" | ||
|
||
#include "test_common.h" | ||
|
||
static tintptr g_wobj1 = 0; | ||
|
||
/******************************************************************************/ | ||
void | ||
os_calls_signals_init(void) | ||
{ | ||
g_wobj1 = g_create_wait_obj(""); | ||
} | ||
|
||
/******************************************************************************/ | ||
void | ||
os_calls_signals_deinit(void) | ||
{ | ||
g_delete_wait_obj(g_wobj1); | ||
g_wobj1 = 0; | ||
} | ||
|
||
/******************************************************************************/ | ||
/** | ||
* Set the global wait object g_wobj1 | ||
*/ | ||
static void | ||
set_wobj1(int signum) | ||
{ | ||
g_set_wait_obj(g_wobj1); | ||
} | ||
|
||
/******************************************************************************/ | ||
/** | ||
* Sends a number of signals to the process and checks they are all delivered | ||
* | ||
* @param sig Signal number | ||
* @param count Number of signals to send | ||
* | ||
* The caller is expected to establish a signal handler before this call | ||
* which sets the global g_wobj1 on signal delivery */ | ||
|
||
static | ||
void send_multiple_signals(int sig, unsigned int count) | ||
{ | ||
while (count-- > 0) | ||
{ | ||
g_reset_wait_obj(g_wobj1); | ||
ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); | ||
// Expect the signal to be delivered synchronously | ||
raise(sig); | ||
ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); | ||
} | ||
} | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_set_alarm) | ||
{ | ||
g_reset_wait_obj(g_wobj1); | ||
ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
g_set_alarm(set_wobj1, 1); | ||
|
||
g_obj_wait(&g_wobj1, 1, NULL, 0, 2000); | ||
|
||
ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
// Clean up | ||
g_set_alarm(NULL, 0); | ||
} | ||
END_TEST | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_child_stop_1) | ||
{ | ||
struct exit_status e; | ||
|
||
g_reset_wait_obj(g_wobj1); | ||
ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
g_signal_child_stop(set_wobj1); | ||
|
||
int pid = g_fork(); | ||
|
||
if (pid == 0) | ||
{ | ||
g_exit(45); | ||
} | ||
ck_assert_int_ne(pid, 0); | ||
g_obj_wait(&g_wobj1, 1, NULL, 0, 2000); | ||
ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
e = g_waitpid_status(pid); | ||
|
||
ck_assert_int_eq(e.reason, E_XR_STATUS_CODE); | ||
ck_assert_int_eq(e.val, 45); | ||
|
||
// Try another one to make sure the signal handler is still in place. | ||
// This one can generate a signal | ||
g_reset_wait_obj(g_wobj1); | ||
|
||
pid = g_fork(); | ||
if (pid == 0) | ||
{ | ||
raise(SIGSEGV); | ||
} | ||
ck_assert_int_ne(pid, 0); | ||
g_obj_wait(&g_wobj1, 1, NULL, 0, 2000); | ||
ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
e = g_waitpid_status(pid); | ||
|
||
ck_assert_int_eq(e.reason, E_XR_SIGNAL); | ||
ck_assert_int_eq(e.val, SIGSEGV); | ||
|
||
// Clean up | ||
g_signal_child_stop(NULL); | ||
} | ||
END_TEST | ||
|
||
/******************************************************************************/ | ||
/* Checks that multiple children finishing do not interrupt | ||
* g_waitpid_status() */ | ||
START_TEST(test_g_signal_child_stop_2) | ||
{ | ||
#define CHILD_COUNT 20 | ||
int pids[CHILD_COUNT]; | ||
unsigned int i; | ||
|
||
struct exit_status e; | ||
|
||
g_reset_wait_obj(g_wobj1); | ||
ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
g_signal_child_stop(set_wobj1); | ||
|
||
for (i = 0 ; i < CHILD_COUNT; ++i) | ||
{ | ||
int pid = g_fork(); | ||
if (pid == 0) | ||
{ | ||
g_sleep((i + 1) * 100); | ||
g_exit(i + 1); | ||
} | ||
ck_assert_int_ne(pid, 0); | ||
pids[i] = pid; | ||
} | ||
g_obj_wait(&g_wobj1, 1, NULL, 0, 2000); | ||
ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); | ||
|
||
for (i = 0 ; i < CHILD_COUNT; ++i) | ||
{ | ||
e = g_waitpid_status(pids[i]); | ||
ck_assert_int_eq(e.reason, E_XR_STATUS_CODE); | ||
ck_assert_int_eq(e.val, (i + 1)); | ||
} | ||
|
||
// Clean up | ||
g_signal_child_stop(NULL); | ||
#undef CHILD_COUNT | ||
} | ||
END_TEST | ||
|
||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_segfault) | ||
{ | ||
g_signal_segfault(set_wobj1); | ||
|
||
// Only one signal can be received in this way. After handling | ||
// the signal the handler should be automatically reset. | ||
send_multiple_signals(SIGSEGV, 1); | ||
|
||
g_signal_segfault(NULL); | ||
} | ||
END_TEST | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_hang_up) | ||
{ | ||
g_signal_hang_up(set_wobj1); | ||
|
||
send_multiple_signals(SIGHUP, 5); | ||
|
||
g_signal_hang_up(NULL); | ||
} | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_user_interrupt) | ||
{ | ||
g_signal_user_interrupt(set_wobj1); | ||
|
||
send_multiple_signals(SIGINT, 5); | ||
|
||
g_signal_user_interrupt(NULL); | ||
} | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_terminate) | ||
{ | ||
g_signal_terminate(set_wobj1); | ||
|
||
send_multiple_signals(SIGTERM, 5); | ||
|
||
g_signal_terminate(NULL); | ||
} | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_pipe) | ||
{ | ||
g_signal_pipe(set_wobj1); | ||
|
||
send_multiple_signals(SIGPIPE, 5); | ||
|
||
g_signal_pipe(NULL); | ||
} | ||
|
||
/******************************************************************************/ | ||
START_TEST(test_g_signal_usr1) | ||
{ | ||
g_signal_usr1(set_wobj1); | ||
|
||
send_multiple_signals(SIGUSR1, 5); | ||
|
||
g_signal_usr1(NULL); | ||
} | ||
|
||
/******************************************************************************/ | ||
TCase * | ||
make_tcase_test_os_calls_signals(void) | ||
{ | ||
TCase *tc = tcase_create("oscalls-signals"); | ||
|
||
tcase_add_test(tc, test_g_set_alarm); | ||
tcase_add_test(tc, test_g_signal_child_stop_1); | ||
tcase_add_test(tc, test_g_signal_child_stop_2); | ||
tcase_add_test(tc, test_g_signal_segfault); | ||
tcase_add_test(tc, test_g_signal_hang_up); | ||
tcase_add_test(tc, test_g_signal_user_interrupt); | ||
tcase_add_test(tc, test_g_signal_terminate); | ||
tcase_add_test(tc, test_g_signal_pipe); | ||
tcase_add_test(tc, test_g_signal_usr1); | ||
|
||
return tc; | ||
} |