9static volatile sig_atomic_t handler_report = -1;
11static void caught(
int signal) {
13 if (signal == SIGUSR1 && handler_report >= 0) {
15 ssize_t result = write(handler_report, &value, 1);
24 atomic_uint ready, done;
25 int result, error, status;
29static void* wait_for_child(
void* argument) {
33 sigaddset(&mask, SIGUSR1);
34 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
36 atomic_store(&
waiter->ready, 1);
41 atomic_store(&
waiter->done, 1);
45static int interrupt_case(
int use_waitpid,
int restart) {
46 int failed = 0, started = 0, installed = 0;
47 int report[2] = {-1, -1};
48 struct cw_child child = CW_CHILD_INIT;
50 struct sigaction action = {.sa_handler = caught, .sa_flags = restart ? SA_RESTART : 0}, old;
52 CHECK(pipe(report) == 0);
53 handler_report = report[1];
54 sigemptyset(&action.sa_mask);
55 CHECK(sigaction(SIGUSR1, &action, &old) == 0);
57 CHECK(cw_spawn(&child, -1, (uid_t)-1, 96) == 0);
59 CHECK(pthread_create(&thread, NULL, wait_for_child, &
waiter) == 0);
61 CHECK(cw_atomic_wait(&
waiter.ready, 1) == 0);
64 for (
int i = 0; i < 8; ++i) {
65 CHECK(!atomic_load(&
waiter.done));
66 CHECK(pthread_kill(thread, SIGUSR1) == 0 && cw_receive(report[0],
'H') == 0);
68 CHECK(!atomic_load(&
waiter.done));
69 CHECK(cw_send(child.command,
'E') == 0 && cw_atomic_wait(&
waiter.done, 1) == 0);
70 CHECK(
waiter.result == (use_waitpid ? child.pid : 0));
72 CHECK(WIFEXITED(
waiter.status) && WEXITSTATUS(
waiter.status) == 96);
74 CHECK(cw_info(&
waiter.info, child.pid, getuid(), CLD_EXITED, 96) == 0);
77 const int64_t end = cw_now() + INT64_C(5000000000);
78 while (!atomic_load(&
waiter.done) && cw_now() < end) {
79 int result = pthread_kill(thread, SIGUSR1);
80 CHECK(result == 0 || (result == ESRCH && atomic_load(&
waiter.done)));
81 struct pollfd pending = {.fd = report[0], .events = POLLIN};
82 if (poll(&pending, 1, 20) > 0)
83 CHECK(cw_receive(report[0],
'H') == 0);
88 CHECK(!cw_empty_info(&
waiter.info));
90 CHECK(waitid(P_PID, child.pid, &info, WEXITED | WNOHANG) == 0 && !cw_empty_info(&info));
91 CHECK(cw_send(child.command,
'E') == 0 && waitid(P_PID, child.pid, &info, WEXITED) == 0);
92 CHECK(cw_info(&info, child.pid, getuid(), CLD_EXITED, 96) == 0);
98 if (!atomic_load(&
waiter.done))
99 pthread_cancel(thread);
100 if (pthread_join(thread, NULL))
104 if (installed && sigaction(SIGUSR1, &old, NULL))
113static int cancel_case(
int use_waitpid) {
114 int failed = 0, started = 0;
115 struct cw_child child = CW_CHILD_INIT;
120 CHECK(cw_spawn(&child, -1, (uid_t)-1, 97) == 0);
122 CHECK(pthread_create(&thread, NULL, wait_for_child, &
waiter) == 0);
124 CHECK(cw_atomic_wait(&
waiter.ready, 1) == 0);
125 CHECK(pthread_cancel(thread) == 0 && pthread_join(thread, &result) == 0);
127 CHECK(result == PTHREAD_CANCELED && !atomic_load(&
waiter.done));
128 CHECK(waitid(P_PID, child.pid, &info, WEXITED | WNOHANG) == 0 && !cw_empty_info(&info));
129 CHECK(cw_send(child.command,
'E') == 0 && waitid(P_PID, child.pid, &info, WEXITED) == 0);
130 CHECK(cw_info(&info, child.pid, getuid(), CLD_EXITED, 97) == 0);
135 pthread_cancel(thread);
136 if (pthread_join(thread, NULL))
142int cw_interruption(
void) {
143 for (
int use_waitpid = 0; use_waitpid < 2; ++use_waitpid)
144 if (interrupt_case(use_waitpid, 0) || interrupt_case(use_waitpid, 1) ||
145 cancel_case(use_waitpid))