Skip to content

Instantly share code, notes, and snippets.

@epipping
Last active August 7, 2016 12:17
Show Gist options
  • Save epipping/5c00e0fd4e60a9c34174060551425511 to your computer and use it in GitHub Desktop.
Save epipping/5c00e0fd4e60a9c34174060551425511 to your computer and use it in GitHub Desktop.
experiment with waitid and waitpid
//#define _POSIX_C_SOURCE 199309L // POSIX.1b-1993
//#define _POSIX_C_SOURCE 199506L // POSIX.1c-1996
//#define _POSIX_C_SOURCE 200112L // POSIX.1-2001
#define _POSIX_C_SOURCE 200809L // POSIX.1-2008
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define print_status print_status_waitid_absolute
//#define print_status print_status_waitid
//#define print_status print_status_waitpid
void print_status_waitid_absolute(int pid) {
siginfo_t info;
// _POSIX_C_SOURCE >= 200809L will do
waitid(P_PID, pid, &info,
WEXITED | WSTOPPED | WCONTINUED | WNOHANG | WNOWAIT);
switch (info.si_code) {
case CLD_EXITED:
printf(">> Child has EXITED (now or sometime in the past) with status %d\n",
info.si_status);
return;
case CLD_KILLED:
case CLD_DUMPED:
// not checking if a core was dumped
printf(
">> Child has been KILLED (now or sometime in the past) by signal %d\n",
info.si_status);
return;
case CLD_STOPPED:
printf(">> Child is STOPPED; most recent signal was: %d\n", info.si_status);
return;
case CLD_CONTINUED:
// NOTE: On Linux (documented), this is SIGCONT, the only signal
// that can cause a child to continue. On macOS (undocumented),
// this appears to be the signal that caused the child to stop.
printf(">> Child CONTINUES (somehow related to the signal %d)\n",
info.si_status);
return;
default:
printf(">> Child is RUNNING (and has never slept).\n");
return;
}
}
void print_status_waitid(int pid) {
siginfo_t info;
// _POSIX_C_SOURCE >= 200809L will do
waitid(P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED | WNOHANG);
switch (info.si_code) {
case CLD_EXITED:
printf(">> Child has changed state to EXITED with status %d\n",
info.si_status);
return;
case CLD_KILLED:
case CLD_DUMPED:
// not checking if a core was dumped
printf(">> Child has changed state to KILLED by signal %d\n",
info.si_status);
return;
case CLD_STOPPED:
printf(">> Child has changed state to STOPPED by signal %d\n",
info.si_status);
return;
case CLD_CONTINUED:
printf(">> Child has changed state to CONTINUED by signal %d\n",
info.si_status);
return;
default:
printf(">> No changes.\n");
return;
}
}
void print_status_waitpid(int pid) {
int status;
int ret = waitpid(pid, &status, WNOHANG | WUNTRACED);
if (ret == -1) {
printf(">> No process. Must have terminated in the past.\n");
return;
}
if (ret == 0) {
printf(">> No changes recorded\n");
return;
}
assert(ret == pid);
if (WIFEXITED(status)) {
printf(">> Child has changed state to SIGNALED by signal %d\n",
WEXITSTATUS(status));
return;
}
if (WIFCONTINUED(status)) {
printf(">> Child has changed state to CONTINUED\n");
return;
}
if (WIFSIGNALED(status)) {
// not checking if a core was dumped via WCOREDUMP()
printf(">> Child has changed state to SIGNALED by signal %d\n",
WTERMSIG(status));
return;
}
if (WIFSTOPPED(status)) {
printf(">> Child has changed state to STOPPED by signal %d\n",
WSTOPSIG(status));
return;
}
printf("Warning: Should never get here!\n");
}
void print_time_since(struct timeval *initial_time) {
struct timeval final_time;
gettimeofday(&final_time, NULL);
printf("Time elapsed: %ld micro seconds\n",
(final_time.tv_sec - initial_time->tv_sec) * 1000000 +
final_time.tv_usec - initial_time->tv_usec);
}
int main() {
int child_pid = fork();
if (0 == child_pid) {
sleep(2);
} else {
struct timeval initial_time;
gettimeofday(&initial_time, NULL);
sleep(1);
print_status(child_pid);
kill(child_pid, SIGSTOP);
puts("SIGSTOP sent");
print_status(child_pid);
sleep(1);
puts("slept for 1s");
print_status(child_pid);
sleep(1);
puts("slept for 1s");
print_status(child_pid);
kill(child_pid, SIGCONT);
puts("SIGCONT sent");
print_status(child_pid);
print_status(child_pid);
sleep(2);
puts("waited for 2 seconds (child should be done now)");
print_status(child_pid);
print_status(child_pid);
print_time_since(&initial_time);
}
wait(NULL);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment