void FProcState::Wait() { if (bHasBeenWaitedFor) { return; // we could try waitpid() another time, but why } for(;;) // infinite loop in case we get EINTR and have to repeat { siginfo_t SignalInfo; if (waitid(P_PID, GetProcessId(), &SignalInfo, WEXITED)) { if (errno != EINTR) { int ErrNo = errno; UE_LOG(LogHAL, Fatal, TEXT("FLinuxPlatformProcess::WaitForProc: waitid for pid %d failed (errno=%d, %s)"), static_cast< int32 >(GetProcessId()), ErrNo, ANSI_TO_TCHAR(strerror(ErrNo))); break; // exit the loop if for some reason Fatal log (above) returns } } else { check(SignalInfo.si_pid == GetProcessId()); ReturnCode = (SignalInfo.si_code == CLD_EXITED) ? SignalInfo.si_status : -1; bHasBeenWaitedFor = true; bIsRunning = false; // set in advance break; } } }
// Block until child_pid exits, then exit. Try to preserve the exit code. static void WaitForChildAndExit(pid_t child_pid) { int exit_code = -1; siginfo_t reaped_child_info; // Don't "Core" on SIGABRT. SIGABRT is sent by the Chrome OS session manager // when things are hanging. // Here, the current process is going to waitid() and _exit(), so there is no // point in generating a crash report. The child process is the one // blocking us. if (signal(SIGABRT, ExitWithErrorSignalHandler) == SIG_ERR) { FatalError("Failed to change signal handler"); } int wait_ret = HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED)); if (!wait_ret && reaped_child_info.si_pid == child_pid) { if (reaped_child_info.si_code == CLD_EXITED) { exit_code = reaped_child_info.si_status; } else { // Exit with code 0 if the child got signaled. exit_code = 0; } } _exit(exit_code); }
/* * helper function to wait on process exit or background the job */ void queue_job(job_t *job) { siginfo_t si; if (job->bg) { job->state = RUNNING; job_add(&root, job); } else { fg = job; si.si_pid = 0; waitid(P_PID, job->pid, &si, WEXITED|WSTOPPED); tcsetpgrp(0, s_pgid); if (si.si_pid != 0) { switch (si.si_code) { case CLD_EXITED: job_rm(&root, fg); job_free(&fg); break; case CLD_STOPPED: job->state = STOPPED; job_add(&root, fg); fg = NULL; break; } } } }
void event_child_signal(int sig_num) { siginfo_t siginfo; int retval; Event *event; SList *list; siginfo.si_pid = 0; retval = waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG); if (pikrellcam.verbose) printf("child exit: ret=%d pid=%d %m\n", retval, siginfo.si_pid); pthread_mutex_lock(&event_mutex); for (list = event_list; list; list = list->next) { event = (Event *) list->data; if (event->child_pid == siginfo.si_pid) { event->time = pikrellcam.t_now; break; } } pthread_mutex_unlock(&event_mutex); }
void kill_childs() { siginfo_t info; struct web_client *w; for(w = web_clients; w ; w = w->next) { debug(D_EXIT, "Stopping web client %s", w->client_ip); pthread_cancel(w->thread); pthread_join(w->thread, NULL); } int i; for (i = 0; static_threads[i].name != NULL ; i++) { if(static_threads[i].thread) { debug(D_EXIT, "Stopping %s thread", static_threads[i].name); pthread_cancel(*static_threads[i].thread); pthread_join(*static_threads[i].thread, NULL); static_threads[i].thread = NULL; } } if(tc_child_pid) { info("Killing tc-qos-helper procees"); if(killpid(tc_child_pid, SIGTERM) != -1) waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED); } tc_child_pid = 0; struct plugind *cd; for(cd = pluginsd_root ; cd ; cd = cd->next) { debug(D_EXIT, "Stopping %s plugin thread", cd->id); pthread_cancel(cd->thread); pthread_join(cd->thread, NULL); if(cd->pid && !cd->obsolete) { debug(D_EXIT, "killing %s plugin process", cd->id); if(killpid(cd->pid, SIGTERM) != -1) waitid(P_PID, (id_t) cd->pid, &info, WEXITED); } } // if, for any reason there is any child exited // catch it here waitid(P_PID, 0, &info, WEXITED|WNOHANG); debug(D_EXIT, "All threads/childs stopped."); }
static bool ReapOneProcess() { siginfo_t siginfo = {}; // This returns a zombie pid or informs us that there are no zombies left to be reaped. // It does NOT reap the pid; that is done below. if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) { PLOG(ERROR) << "waitid failed"; return false; } auto pid = siginfo.si_pid; if (pid == 0) return false; // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid // whenever the function returns from this point forward. // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we // want the pid to remain valid throughout that (and potentially future) usages. auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); std::string name; std::string wait_string; Service* service = nullptr; if (PropertyChildReap(pid)) { name = "Async property child"; } else if (SubcontextChildReap(pid)) { name = "Subcontext"; } else { service = ServiceList::GetInstance().FindService(pid, &Service::pid); if (service) { name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid); if (service->flags() & SVC_EXEC) { auto exec_duration = boot_clock::now() - service->time_started(); auto exec_duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count(); wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); } } else { name = StringPrintf("Untracked pid %d", pid); } } auto status = siginfo.si_status; if (WIFEXITED(status)) { LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string; } else if (WIFSIGNALED(status)) { LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string; } if (!service) return true; service->Reap(); if (service->flags() & SVC_TEMPORARY) { ServiceList::GetInstance().RemoveService(*service); } return true; }
/* * stress_wait * stress wait*() family of calls */ int stress_wait( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { int status, ret = EXIT_SUCCESS; pid_t pid_r, pid_k; (void)instance; pr_dbg(stderr, "%s: waiter started [%d]\n", name, getpid()); pid_r = spawn(name, runner, 0, counter, max_ops); if (pid_r < 0) { pr_fail_dbg(name, "fork"); exit(EXIT_FAILURE); } pid_k = spawn(name, killer, pid_r, counter, max_ops); if (pid_k < 0) { pr_fail_dbg(name, "fork"); ret = EXIT_FAILURE; goto tidy; } do { (void)waitpid(pid_r, &status, WCONTINUED); if (!opt_do_run) break; if (WIFCONTINUED(status)) (*counter)++; #if _SVID_SOURCE || _XOPEN_SOURCE >= 500 || \ _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED || \ _POSIX_C_SOURCE >= 200809L { siginfo_t info; (void)waitid(P_PID, pid_r, &info, WCONTINUED); if (!opt_do_run) break; if (WIFCONTINUED(status)) (*counter)++; } #endif } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)kill(pid_k, SIGKILL); (void)waitpid(pid_k, &status, 0); tidy: (void)kill(pid_r, SIGKILL); (void)waitpid(pid_r, &status, 0); return ret; }
static void wait_until_process_exited(pid_t pid, siginfo_t *si) { siginfo_t ignored_si; if (NULL == si) { si = &ignored_si; } memset(si, 0, sizeof(*si)); TRACE_ASSERT(0 == TEMP_FAILURE_RETRY(waitid(P_PID, pid, si, WEXITED))); }
static void _handle_sig_child(void) { siginfo_t info; memset(&info, 0, sizeof(info)); if (0 > waitid(P_ALL, 0, &info, WEXITED | WNOWAIT | WNOHANG)) return LOGGER_PERROR("waitid"); if (info.si_pid > 0) { LOGGER_ERROR("child process [%d] terminated unexpectedly: %s, status=%d", info.si_pid, _get_exit_reason(&info), info.si_status); epoll_worker_exit(); } }
pid_t _waitpid(pid_t pid, int *stat_loc, int options) { idtype_t idtype; id_t id; siginfo_t info; int error; if (pid > 0) { idtype = P_PID; id = pid; } else if (pid < -1) { idtype = P_PGID; id = -pid; } else if (pid == -1) { idtype = P_ALL; id = 0; } else { idtype = P_PGID; id = getpgid(0); } options |= (WEXITED|WTRAPPED); if ((error = waitid(idtype, id, &info, options)) < 0) return (error); if (stat_loc) { int stat = (info.si_status & 0377); switch (info.si_code) { case CLD_EXITED: stat <<= 8; break; case CLD_DUMPED: stat |= WCOREFLG; break; case CLD_KILLED: break; case CLD_TRAPPED: case CLD_STOPPED: stat <<= 8; stat |= WSTOPFLG; break; case CLD_CONTINUED: stat = WCONTFLG; break; } *stat_loc = stat; } return (info.si_pid); }
static siginfo_t wait_trap(pid_t chld) { siginfo_t si; if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0) err(1, "waitid"); if (si.si_pid != chld) errx(1, "got unexpected pid in event\n"); if (si.si_code != CLD_TRAPPED) errx(1, "got unexpected event type %d\n", si.si_code); return si; }
static int exec_and_report_test(const struct weston_test *t, void *test_data, int iteration) { int success = 0; int skip = 0; int hardfail = 0; siginfo_t info; pid_t pid = fork(); assert(pid >= 0); if (pid == 0) run_test(t, test_data); /* never returns */ if (waitid(P_ALL, 0, &info, WEXITED)) { fprintf(stderr, "waitid failed: %m\n"); abort(); } if (test_data) fprintf(stderr, "test \"%s/%i\":\t", t->name, iteration); else fprintf(stderr, "test \"%s\":\t", t->name); switch (info.si_code) { case CLD_EXITED: fprintf(stderr, "exit status %d", info.si_status); if (info.si_status == EXIT_SUCCESS) success = 1; else if (info.si_status == SKIP) skip = 1; break; case CLD_KILLED: case CLD_DUMPED: fprintf(stderr, "signal %d", info.si_status); if (info.si_status != SIGABRT) hardfail = 1; break; } if (t->must_fail) success = !success; if (success && !hardfail) { fprintf(stderr, ", pass.\n"); return 1; } else if (skip) { fprintf(stderr, ", skip.\n"); return SKIP; } else { fprintf(stderr, ", fail.\n"); return 0; } }
int waitsys(idtype_t idtype, id_t id, siginfo_t *infop, int options) { int error; k_siginfo_t info; if (error = waitid(idtype, id, &info, options)) return (set_errno(error)); if (copyout(&info, infop, sizeof (k_siginfo_t))) return (set_errno(EFAULT)); return (0); }
ATF_TC_BODY(waitid_options, tc) { size_t i = 0; int o; while((o = get_options6(i++)) != -1) { printf("Testing waitid(2) with options %x\n", o); ATF_REQUIRE_ERRNO(ECHILD, waitid(P_ALL, 0, NULL, o | TWAIT_OPTION) == -1); } }
void impl_exit_check(void) { if( is_exiting == TRUE && total_tracked == 0 ) { if( wait_mode == TRUE ) { /* Check for any active child processes. * NOTE: Because we are using waitid() here, and * that allows us to specify WNOWAIT, the child * will stay in a waitable state for to be reaped * whenever the actual program wants to. */ do { siginfo_t info; int rval = waitid(P_ALL, 0, &info, WNOHANG|WNOWAIT); if( rval < 0 && errno == EINTR ) { continue; } if( rval >= 0 || (rval < 0 && errno != ECHILD) ) { /* There are still active child processes. */ return; } break; } while( 1 ); } DEBUG("No active connections, finishing exit."); switch( exit_strategy ) { case FORK: /* We're done. * No more connections are active, and there's * presumably already a child process handling * new incoming connections. */ DEBUG("Goodbye!"); libc.exit(0); break; case EXEC: /* Let's do the exec. * We're wrapped up existing connections, we can * re-execute the application to start handling new * incoming connections. */ DEBUG("See you soon..."); impl_exec(); break; } } }
int main(void) { pid_t pid; int a = 1; siginfo_t infop; if ((pid = fork()) < 0) { err_msg("fork error\n"); } else if (0 == pid) { exit(7); } if (waitid(P_PID, pid, &infop, WEXITED) < 0) { err_msg("waitid error\n"); } pr_exit(infop); if ((pid = fork()) < 0) { err_msg("fork error\n"); } else if (0 == pid) { abort(); } if (waitid(P_PID, pid, &infop, WEXITED) < 0) { err_msg("waitid error\n"); } pr_exit(infop); if ((pid = fork()) < 0) { err_msg("fork error\n"); } else if (0 == pid) { a /= 0; } if (waitid(P_PID, pid, &infop, WEXITED) < 0) { err_msg("waitid error\n"); } pr_exit(infop); exit(0); }
static int signal_handler(int fd, uint32_t events, void *data, struct lxc_epoll_descr *descr) { struct signalfd_siginfo siginfo; siginfo_t info; int ret; pid_t *pid = data; bool init_died = false; ret = read(fd, &siginfo, sizeof(siginfo)); if (ret < 0) { ERROR("Failed to read signal info from signal file descriptor: %d.", fd); return -1; } if (ret != sizeof(siginfo)) { ERROR("Unexpected size for siginfo struct."); return -1; } /* Check whether init is running. */ info.si_pid = 0; ret = waitid(P_PID, *pid, &info, WEXITED | WNOWAIT | WNOHANG); if (ret == 0 && info.si_pid == *pid) init_died = true; if (siginfo.ssi_signo != SIGCHLD) { kill(*pid, siginfo.ssi_signo); INFO("Forwarded signal %d to pid %d.", siginfo.ssi_signo, *pid); return init_died ? 1 : 0; } if (siginfo.ssi_code == CLD_STOPPED) { INFO("Container init process was stopped."); return init_died ? 1 : 0; } else if (siginfo.ssi_code == CLD_CONTINUED) { INFO("Container init process was continued."); return init_died ? 1 : 0; } /* More robustness, protect ourself from a SIGCHLD sent * by a process different from the container init. */ if (siginfo.ssi_pid != *pid) { WARN("Invalid pid for SIGCHLD. Received pid %d, expected pid %d.", siginfo.ssi_pid, *pid); return init_died ? 1 : 0; } DEBUG("Container init process %d exited.", *pid); return 1; }
int waitsys32(idtype_t idtype, id_t id, siginfo_t *infop, int options) { int error; k_siginfo_t info; siginfo32_t info32; if (error = waitid(idtype, id, &info, options)) return (set_errno(error)); siginfo_kto32(&info, &info32); if (copyout(&info32, infop, sizeof (info32))) return (set_errno(EFAULT)); return (0); }
static int signal_handler(int fd, uint32_t events, void *data, struct lxc_epoll_descr *descr) { struct signalfd_siginfo siginfo; siginfo_t info; int ret; pid_t *pid = data; bool init_died = false; ret = read(fd, &siginfo, sizeof(siginfo)); if (ret < 0) { ERROR("failed to read signal info"); return -1; } if (ret != sizeof(siginfo)) { ERROR("unexpected siginfo size"); return -1; } // check whether init is running info.si_pid = 0; ret = waitid(P_PID, *pid, &info, WEXITED | WNOWAIT | WNOHANG); if (ret == 0 && info.si_pid == *pid) { init_died = true; } if (siginfo.ssi_signo != SIGCHLD) { kill(*pid, siginfo.ssi_signo); INFO("forwarded signal %d to pid %d", siginfo.ssi_signo, *pid); return init_died ? 1 : 0; } if (siginfo.ssi_code == CLD_STOPPED || siginfo.ssi_code == CLD_CONTINUED) { INFO("container init process was stopped/continued"); return init_died ? 1 : 0; } /* more robustness, protect ourself from a SIGCHLD sent * by a process different from the container init */ if (siginfo.ssi_pid != *pid) { WARN("invalid pid for SIGCHLD"); return init_died ? 1 : 0; } DEBUG("container init process exited"); return 1; }
bool app_launcher::update_status(bool wait) { if (m_status_code != STATUS_RUNNING) return false; assert(m_child_pid >= 0); int options = WEXITED; // WSTOPPED: wait for children stopped by delivery of signal. if(!wait) options |= WNOHANG; siginfo_t signalinfo; int ret = waitid(P_PID, m_child_pid, &signalinfo, options); if (ret == -1) { m_status_code = STATUS_ERROR; m_status = ret; assert(0); return false; } else { // If we ever care about signals and whatnot: // signalinfo.si_signo; // Signal number. // signalinfo.si_code; // Signal code: CLD_EXITED, CLD_DUMPED, CLD_KILLED. // signalinfo.si_errno; // Error number associated with signal. // signalinfo.si_status; // Exit value. switch(signalinfo.si_code) { default: assert(0); case CLD_EXITED: m_status_code = STATUS_EXITED; m_status = signalinfo.si_status; break; case CLD_KILLED: m_status_code = STATUS_KILLED; m_status = 0; break; case CLD_DUMPED: m_status_code = STATUS_DUMPED; m_status = 0; break; } } return true; }
int wait_for_child(int options) { id_t id_ignored = 0; siginfo_t infop; infop.si_pid = 0; waitid(P_ALL, id_ignored, &infop, WEXITED | options); if (infop.si_pid == 0) { return -1; /* Nothing to wait for */ } if (infop.si_code == CLD_EXITED) { return infop.si_status; } return 1; }
bool FProcState::IsRunning() { if (bIsRunning) { check(!bHasBeenWaitedFor); // check for the sake of internal consistency // check if actually running int KillResult = kill(GetProcessId(), 0); // no actual signal is sent check(KillResult != -1 || errno != EINVAL); bIsRunning = (KillResult == 0 || (KillResult == -1 && errno == EPERM)); // additional check if it's a zombie if (bIsRunning) { for(;;) // infinite loop in case we get EINTR and have to repeat { siginfo_t SignalInfo; SignalInfo.si_pid = 0; // if remains 0, treat as child was not waitable (i.e. was running) if (waitid(P_PID, GetProcessId(), &SignalInfo, WEXITED | WNOHANG | WNOWAIT)) { if (errno != EINTR) { int ErrNo = errno; UE_LOG(LogHAL, Fatal, TEXT("FLinuxPlatformProcess::WaitForProc: waitid for pid %d failed (errno=%d, %s)"), static_cast< int32 >(GetProcessId()), ErrNo, ANSI_TO_TCHAR(strerror(ErrNo))); break; // exit the loop if for some reason Fatal log (above) returns } } else { bIsRunning = ( SignalInfo.si_pid != GetProcessId() ); break; } } } // If child is a zombie, wait() immediately to free up kernel resources. Higher level code // (e.g. shader compiling manager) can hold on to handle of no longer running process for longer, // which is a dubious, but valid behavior. We don't want to keep zombie around though. if (!bIsRunning) { UE_LOG(LogHAL, Log, TEXT("Child %d is no more running (zombie), Wait()ing immediately."), GetProcessId() ); Wait(); } } return bIsRunning; }
/*Checa se ha job terminado no ultimo contexto, imprimindo e liberando espaco*/ void checkjob(){ siginfo_t signal; int i; for(i = 1; i < MAX_JOBS ; i++) { signal.si_pid = 0; if (!(!waitid(P_PID ,jobs[i].p_id, &signal, WNOHANG | WEXITED)) && signal.si_pid == 0){ if (jobs[i].flag != 0){ printf("[%d]\t", i); printf("Terminado\t"); printf("%s \n",jobs[i].p_name); jobs[i].flag = 0; } } } }
/*Imprime jobs em background*/ void imprimejob(){ siginfo_t signal; int i; for(i = 1; i < MAX_JOBS ; i++) { if ((jobs[i].flag == 0) || (jobs[i].flag == 2)) continue; signal.si_pid = 0; if ((!waitid(P_PID ,jobs[i].p_id, &signal, WNOHANG | WEXITED)) && signal.si_pid == 0){ if (jobs[i].flag !=3) jobs[i].flag = 1; printf("[%d]\t", jobs[i].p_id); printf("%%%d\t", jobs[i].j_id); printf("%s\t", jobs[i].p_status); printf("%s &\n",jobs[i].p_name); } else jobs[i].flag = 2; } }
void child_t::sigchld_handler(int sig) { siginfo_t siginfo; char line[MAX_PACKETLEN]={0}; fprintf(stderr, "parent: received signal %d.\n", sig); siginfo.si_pid=0; // get wait info if ( waitid(P_ALL, 0, &siginfo, WEXITED | WSTOPPED | WCONTINUED | WNOHANG) < 0 ) { perror("wait failed"); } if ( siginfo.si_pid == 0 ) { printf("warning: wait returned siginfo.si_pid==0.\n"); return; } child_t* child = child_t::findbyPID(siginfo.si_pid); // find corresponding child if ( child == NULL ) { printf("warning: received SIGCHLD from (pid %d), which is no child!\n", siginfo.si_pid); child_t::ListChildren(); return; } // update child status child->status = siginfo.si_code; child->pid = (pid_t)-1; line[0]=0; // clear line // compose info message lineadd(line, "%s > status=%s", child->clientid, child->ChildStatusString() ); //lineadd(line, "FIXME > status=%s", child->ChildStatusString() ); // FIXME: no clientid here lineadd(line, ", pid=%d", siginfo.si_pid); lineadd(line, ", uid=%d", siginfo.si_uid); if (WIFSIGNALED(siginfo.si_status)) { lineadd(line, ", termsig=%d", WTERMSIG(siginfo.si_status)); # ifdef WCOREDUMP lineadd(line, ", coredump=%s", WCOREDUMP(siginfo.si_status)?"true":"false"); # endif } if (WIFSTOPPED(siginfo.si_status) ) { lineadd(line, ", stopsig=%d", WSTOPSIG(siginfo.si_status)); } if (WIFEXITED(siginfo.si_status) ) { lineadd(line, ", return_status=%d", WEXITSTATUS(siginfo.si_status)); } if ( meptr != NULL ) { (meptr)->printf("%ld %s\n", time(NULL), line); } else { printf("%s\n", line); } }
// Block until child_pid exits, then exit. Try to preserve the exit code. static void WaitForChildAndExit(pid_t child_pid) { int exit_code = -1; siginfo_t reaped_child_info; int wait_ret = HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED)); if (!wait_ret && reaped_child_info.si_pid == child_pid) { if (reaped_child_info.si_code == CLD_EXITED) { exit_code = reaped_child_info.si_status; } else { // Exit with code 0 if the child got signaled. exit_code = 0; } } _exit(exit_code); }
/** Starts the web100srv process. Either args must be NULL or the last element * of **args must be NULL. */ pid_t start_server(int port, char **extra_args) { int extra_args_index = 0; char *arg; pid_t server_pid; siginfo_t server_status; char port_string[6]; // 32767 is the max port, so must hold 5 digits + \0 int rv; char *args_for_exec[256] = {"./web100srv", "--snaplog", "--tcpdump", "--cputime", "--log_dir", "/tmp", "-l", LOGFILE_TEMPLATE, "--port", NULL}; int exec_args_index = 0; // set exec_args_index to the first index of args_for_exec that is NULL while (args_for_exec[exec_args_index] != NULL) { // along the way, fill in the template for the test logs if (strcmp(args_for_exec[exec_args_index], LOGFILE_TEMPLATE) == 0) { mkstemp(args_for_exec[exec_args_index]); } exec_args_index++; } log_println(1, "Starting the server"); if ((server_pid = fork()) == 0) { sprintf(port_string, "%d", port); args_for_exec[exec_args_index++] = port_string; while (extra_args != NULL && extra_args[extra_args_index] != NULL) { CHECK((args_for_exec[exec_args_index++] = strdup(extra_args[extra_args_index++])) != NULL); } args_for_exec[exec_args_index++] = NULL; execv("./web100srv", args_for_exec); perror("SERVER START ERROR: SHOULD NEVER HAPPEN"); FAIL("The server should never return - it should only be killed."); exit(1); } // Wait until the server port (hopefully) becomes available. The server PID is // available immediately, but we need to make sure to lose the race condition // with the server startup process, so that the NDT port is open and ready to // receive traffic and we won't begin the test before the server's startup // routines are complete. sleep(1); // Double-check that the server didn't crash on startup. server_status.si_pid = 0; rv = waitid(P_PID, server_pid, &server_status, WEXITED | WSTOPPED | WNOHANG); ASSERT(rv == 0 && server_status.si_pid == 0, "The server did not start successfully (exit code %d)", rv); return server_pid; }
int main(void) { void *buf; pid_t child; int ret, i; siginfo_t info; uint8_t *ubuf; size_t mapsz = sysconf(_SC_PAGESIZE) * 2; buf = mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); assert(buf != MAP_FAILED); ret = memcntl(buf, mapsz, MC_INHERIT_ZERO, 0, 0, 0); assert(ret == 0); again: memset(buf, 'a' + nchild, mapsz); child = fork(); if (child == 0) { nchild--; for (i = 0, ubuf = buf; i < mapsz; i++) assert(ubuf[i] == 0); if (nchild != 0) goto again; exit(0); } assert(child != -1); do { ret = waitid(P_PID, child, &info, WEXITED); } while (ret == -1 && errno == EINTR); assert(ret == 0); assert(info.si_pid == child); assert(info.si_status == 0); for (i = 0, ubuf = buf; i < mapsz; i++) assert(ubuf[i] == 'a' + nchild); return (0); }
static int manager_signal_fn(sd_event_source *source, const struct signalfd_siginfo *ssi, void *data) { struct manager *m = data; if (ssi->ssi_signo == SIGCHLD) { log_debug("caught SIGCHLD for %ld, reaping child", (long)ssi->ssi_pid); waitid(P_PID, ssi->ssi_pid, NULL, WNOHANG|WEXITED); return 0; } else if (ssi->ssi_signo == SIGPIPE) { /* ignore SIGPIPE */ return 0; } log_notice("caught signal %d, exiting..", (int)ssi->ssi_signo); sd_event_exit(m->event, 0); return 0; }
int main(void) { int i = 0; pid_t pid; int status; siginfo_t si; ++i; pid = fork(); if (!pid) { usleep(100); exit(i); } test_assert(pid == wait(&status)); atomic_printf("%d exited with status %#x\n", pid, status); test_assert(WIFEXITED(status) && i == WEXITSTATUS(status)); ++i; pid = fork(); if (!pid) { usleep(100); exit(i); } test_assert(pid == waitpid(pid, &status, 0)); atomic_printf("%d exited with status %#x\n", pid, status); test_assert(WIFEXITED(status) && i == WEXITSTATUS(status)); ++i; pid = fork(); if (!pid) { usleep(100); exit(i); } test_assert(0 == waitid(P_PID, pid, &si, WEXITED | WSTOPPED)); atomic_printf("%d exited with exit-type %d; code %d\n", si.si_pid, si.si_code, si.si_status); test_assert(SIGCHLD == si.si_signo && CLD_EXITED == si.si_code); test_assert(pid == si.si_pid && i == si.si_status); atomic_puts("EXIT-SUCCESS"); return 0; }