Situation:
I am writing a program in C that maintains a number of threads. Once a thread ends, a new one is created.
Each thread forks - the child runs a process via exec() and the parent waits for it to finish.
In addition, there is a signal handler thread that waits for signals. If SIGINT is detected then it tells the main thread to stop creating threads so eventually all the threads end and the program can exit.
Signals are blocked in all threads except of course the signal handler thread.
Aim:
I want to be able to terminate the program by sending SIGTERM. This would work by stopping the main thread creating new threads and also terminating the running processes created by threads.
Problem:
If signals are blocked in all the threads, how can I send a signal to the running processes to terminate them?
Is there some way to make the spawned processes only receive signals sent from the main program and not signals sent to the main program?
Create all child processes in a new process group, then send the signal to the group.
Edit:
Here's some minimal code that shows how process can change it's group and control child processes with a signal.
#include <err.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t pgid; /* process group to kill */
void terminator( int s ) /* signal handler */
{
printf( "[%d:%d] received signal %d, exiting\n",
getpid(), getpgrp(), s );
exit( 1 );
}
int main() /* program entry */
{
printf( "[%d:%d] before first fork\n",
getpid(), getpgrp() );
switch ( fork()) /* try with and without first fork */
{
case -1: err( 1, "fork" );
case 0: break;
default: exit( 0 );
}
if ( signal( SIGTERM, terminator ) == SIG_ERR )
err( 1, "signal" );
if ( setpgrp() < 0 ) err( 1, "setpgrp" );
if (( pgid = getpgrp()) < 0 ) err( 1, "getpgrp" );
printf( "[%d:%d -> %d] before second fork\n",
getpid(), getpgrp(), pgid );
switch ( fork())
{
case -1: err( 1, "fork" );
case 0: /* child */
{
printf( "child [%d:%d]\n", getpid(), getpgrp());
sleep( 20 );
break;
}
default: /* parent */
{
printf( "parent [%d:%d]\n", getpid(), getpgrp());
sleep( 5 );
killpg( pgid, SIGTERM );
sleep( 20 );
}
}
printf( "[%d:%d] exiting\n", getpid(), getpgrp());
exit( 1 );
}