3

I have a problem with this little piece of code. I have a "server" and a "client". The server waits SIGUSR1 from the client. But when I send SIGUSR1 in a loop, the server doesn't handle every signal ! I do i++ each time I receive a signal, and I get 981 while I send 1000 signals.

usleep() and sleep() doesn't help.

here is the client code:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int     main(int ac, char **av)
{
  int   i = 0;
  int status = 0;

  if (ac < 2)
    return (0);
  printf("kill %s (%d)", av[1], atoi(av[1]));
  for (i=0;i<=1000;i++)
    {
      printf("%d\n", i);
      kill(atoi(av[1]), SIGUSR1);
    }
  kill(atoi(av[1]), SIGUSR2);
}

and the server code :

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int i = 0;

void    sig2(int signum)
{
  /* usleep(30); */
  printf("%d\n", i);
  i = 0;
}

void my_handler(int signum)
{
  i++;
}

int     main()
{
  printf("pid: %d\n", getpid());
  if (signal(SIGUSR1, my_handler) == SIG_ERR)
    {
      printf("rt\n");
      exit(0);
    }
  signal(SIGUSR2, sig2);
  while (1);
}
raph77777
  • 111
  • 1
  • 8
  • 2
    A note: `printf` is not "async-signal safe", which basically means, calling it from a signal handler is dangerous (IOW, don't do it), though in *this* very simple case I suppose it is ok, because your `while(1);` loop isn't calling any standard library functions (directly or indirectly). – hyde Jan 26 '16 at 22:08
  • actually the posted code is trying to send 1001 `kill` commands. Suggest replacing: `for (i=0;i<=1000;i++)` with: `for ( i=0; i<1000; i++ )` – user3629249 Jan 27 '16 at 17:15
  • the function: `atoi()` is relatively expensive. suggest adding a local variable to contain the result of the call to `atoi()` as in: `int pid = atoi( av[1];` then modify the loop to use the new local variable rather than repeatedly calling `atoi()` – user3629249 Jan 27 '16 at 17:19
  • the man page for `signal` has this to say: *The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.* – user3629249 Jan 27 '16 at 17:30

2 Answers2

5

You're missing a few signals that are arriving "on top" of each other, too fast for the application to handle.

The standard says:

If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required.

... which is a somewhat obscure way of saying that ordinary UNIX signals need not queue. On most implementations, they do not. For example, if five SIGFOO signals are generated before they can be disposed of, only one will be held pending and the application will thus receive only one.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
1

The behavior of signal is not consistent between platforms, on some systems signals are one-shot, on others it's repeating. Linux, specifically, uses System V behavior (unless the _BSD_SOURCE macro is defined) which is one-shot. After a signal have been handled, it resets to SIG_DFL.

To get consistent behavior you should be using sigaction instead where the behavior can be set using flags.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • sigaction is good advice, but the OP's problem is not the historical BSD SA_RESETHAND semantics. That's something the OP would notice with two signals, not with one thousand. – pilcrow Jan 26 '16 at 21:01