Let's break this down, step by step:
Install a signal handler
First we install a signal handler for SIGINT and SIGTERM in main(). Simple enough RTM job:
Code: Select all
static void sig_handler(int sig, siginfo_t *siginfo, void *context)
{
// Kill every process with the same PGID (should include all child processes)
kill(0, SIGKILL);
_Exit(0);
}
static void set_sig_handler(void)
{
struct sigaction act = {0};
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sig_handler;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
}
int main(...)
{
set_sig_handler();
...
}
The problem is that the OS will send signals in any thread, and we can't know which one. Could be the main thread, or any of the worker thread (each running games in parrallel). So we must tell the OS to block signals in each worker thread, so that only the main thread can receive them. Here thread_start is the function given to pthread_create(), where every worker thread begins its journey.
Code: Select all
static void set_sig_blocker(void)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
}
static void *thread_start(void *arg)
{
set_sig_blocker();
...
}
Spawning child processes with the PGID of the parent
I'll spare you all the boring details, and highlight ony the relevant part:
Code: Select all
static void engine_spawn(const Worker *w, Engine *e, const char *cwd, const char *run, char **argv)
{
...
e->pid = fork();
if (e->pid == 0) {
// in the child process
...
// Inherit process ID and group ID from parent
setpgid(0, 0);
// Set cwd as current directory, and execute run
chdir(cwd);
execvp(run, argv);
} else {
// in the parent process
...
}
}
Code: Select all
$ ps xao pid,ppid,pgid,comm |head -1
PID PPID PGID COMMAND
$ ps xao pid,ppid,pgid,comm |grep c-chess-cli
60979 1855 60979 c-chess-cli
$ ps xao pid,ppid,pgid,comm |grep cheng
60985 60979 60985 cheng_4.39
60987 60979 60987 cheng_4.39
60989 60979 60989 cheng_4.39
60991 60979 60991 cheng_4.39
60992 60979 60992 cheng_4.39
60993 60979 60993 cheng_4.39
60994 60979 60994 cheng_4.39
60995 60979 60995 cheng_4.39
Code: Select all
$ ps xao pid,ppid,pgid,comm |grep cheng
79473 1 79473 cheng_4.39
79475 1 79475 cheng_4.39
79479 1 79479 cheng_4.39
79482 1 79482 cheng_4.39