mdbx-test: rework/fix actor_poll() to avoid loosing SIGCHLD.

Change-Id: I93aa2aa40e07e807795e050cd468d77dab62e67a
This commit is contained in:
Leonid Yuriev 2019-10-12 10:24:18 +03:00
parent c51a6e6d95
commit 23733bf4af

View File

@ -179,7 +179,11 @@ bool osal_progress_push(bool active) {
static std::unordered_map<pid_t, actor_status> childs; static std::unordered_map<pid_t, actor_status> childs;
static void handler_SIGCHLD(int signum) { (void)signum; } static volatile sig_atomic_t sigalarm_head;
static void handler_SIGCHLD(int signum) {
if (signum == SIGALRM)
sigalarm_head += 1;
}
mdbx_pid_t osal_getpid(void) { return getpid(); } mdbx_pid_t osal_getpid(void) { return getpid(); }
@ -191,6 +195,7 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
act.sa_handler = handler_SIGCHLD; act.sa_handler = handler_SIGCHLD;
sigaction(SIGCHLD, &act, nullptr); sigaction(SIGCHLD, &act, nullptr);
sigaction(SIGALRM, &act, nullptr);
act.sa_handler = handler_SIGUSR; act.sa_handler = handler_SIGUSR;
sigaction(SIGUSR1, &act, nullptr); sigaction(SIGUSR1, &act, nullptr);
sigaction(SIGUSR2, &act, nullptr); sigaction(SIGUSR2, &act, nullptr);
@ -229,70 +234,67 @@ void osal_killall_actors(void) {
} }
int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
struct timespec ts; static sig_atomic_t sigalarm_tail;
ts.tv_nsec = 0; alarm(0) /* cancel prev timeout */;
ts.tv_sec = (timeout > INT_MAX) ? INT_MAX : timeout; sigalarm_tail = sigalarm_head /* reset timeout flag */;
retry:
int status, options = WNOHANG; int options = WNOHANG;
if (timeout) {
alarm((timeout > INT_MAX) ? INT_MAX : timeout);
options = 0;
}
#ifdef WUNTRACED #ifdef WUNTRACED
options |= WUNTRACED; options |= WUNTRACED;
#endif #endif
#ifdef WCONTINUED #ifdef WCONTINUED
options |= WCONTINUED; options |= WCONTINUED;
#endif #endif
pid = waitpid(0, &status, options);
if (pid > 0) { while (sigalarm_tail == sigalarm_head) {
if (WIFEXITED(status)) int status;
childs[pid] = pid = waitpid(0, &status, options);
(WEXITSTATUS(status) == EXIT_SUCCESS) ? as_successful : as_failed;
else if (WCOREDUMP(status))
childs[pid] = as_coredump;
else if (WIFSIGNALED(status))
childs[pid] = as_killed;
else if (WIFSTOPPED(status))
childs[pid] = as_debuging;
else if (WIFCONTINUED(status))
childs[pid] = as_running;
else {
assert(false);
}
return 0;
}
static sig_atomic_t sigusr1_tail, sigusr2_tail; if (pid > 0) {
if (sigusr1_tail != sigusr1_head) { if (WIFEXITED(status))
sigusr1_tail = sigusr1_head; childs[pid] =
logging::progress_canary(true); (WEXITSTATUS(status) == EXIT_SUCCESS) ? as_successful : as_failed;
} else if (WCOREDUMP(status))
if (sigusr2_tail != sigusr2_head) { childs[pid] = as_coredump;
sigusr2_tail = sigusr2_head; else if (WIFSIGNALED(status))
logging::progress_canary(false); childs[pid] = as_killed;
} else if (WIFSTOPPED(status))
childs[pid] = as_debuging;
if (pid == 0) { else if (WIFCONTINUED(status))
/* child still running */ childs[pid] = as_running;
if (ts.tv_sec == 0 && ts.tv_nsec == 0) else {
ts.tv_nsec = 1; assert(false);
if (nanosleep(&ts, &ts) == 0) { }
/* timeout and no signal from child */
pid = 0;
return 0; return 0;
} }
if (errno == EINTR)
goto retry;
}
switch (errno) { static sig_atomic_t sigusr1_tail, sigusr2_tail;
case EINTR: if (sigusr1_tail != sigusr1_head) {
pid = 0; sigusr1_tail = sigusr1_head;
return 0; logging::progress_canary(true);
if (pid < 0 && errno == EINTR)
continue;
}
if (sigusr2_tail != sigusr2_head) {
sigusr2_tail = sigusr2_head;
logging::progress_canary(false);
if (pid < 0 && errno == EINTR)
continue;
}
case ECHILD: if (pid == 0)
default: break;
pid = 0;
return errno; int err = errno;
if (err != EINTR)
return err;
} }
return 0 /* timeout */;
} }
void osal_yield(void) { void osal_yield(void) {