A. Harkous A. Harkous - 6 months ago 14
Linux Question

How to make two processes signalling each others continuously?

I want to simulate a game server that should continuously send and receive signals with its parent. The scenario is as follows:


  • Parent sends signal to game.

  • Game catches the signal and sends a signal to the parent.

  • Parent catches the signal and sends again a signal to game.



and so on...

The problem is that the stops receiving or sending after the first lap:

static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{

game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}


The output is the following:

game
parent


Why it stopped here? Shouldn't the game server catch parent's signal and print "game" again...

alk alk
Answer

By default the reception of a specific signal is blocked from the moment a process received this specific signal until the related signal handler had been left.

From man 3 signal:

void (*signal(int sig, void (*func)(int)))(int);

[...]

When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:

         signal(sig, SIG_DFL);

is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.

To change this behaviour establish the signal handling via sigaction() instead of signal() (which one should do any ways for portability reasons).

sigaction() takes a struct sigaction. The member sa_flags of the latter should have SA_NODEFER set.

From Linux' man 2 sigaction:

SA_NODEFER

Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.

POSIX words this differently:

SA_NODEFER

If set and sig is caught, sig shall not be added to the thread's signal mask on entry to the signal handler unless it is included in sa_mask. Otherwise, sig shall always be added to the thread's signal mask on entry to the signal handler.


Be aware that each signal handler gets it's own stack allocated each time it gets invoked, so sooner or later this recursive ping-pong ends up in an out-of-memory condition.

Comments