NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pselect and signal handling issue



Hi,

I have an issue with netBSD 5.1. My problem is related to

 * http://mail-index.netbsd.org/netbsd-users/2010/07/10/msg006559.html
 * http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=43625

but seem the issue isn't fixed.

I'm the developper of yaddns (https://github.com/yaddns/yaddns), a
small program to use dyndns services (no-ip, dyndns.org, ...). I'm
trying to porting yaddns (developped on Linux) on NetBSD but i have
found a problem with pselect and signals handling.

In my program, i install signal handler for SIGHUP, SIGTERM, SIGINT,
SIGUSR1 and SIGUSR2 signals. In this signal handler, i modify global
variables to inform what signal was received. As i want to process
signals only in "waiting state", i use pselect() with a sigset empty.
If pselect() return -1 and errno = EINTR, i known signal was caught.
So, i read global variable to known what signal i've received.

Here the relevent code (purified):

 static void sig_handler(int signum)
 {
        if(signum == SIGTERM || signum == SIGINT)
        {
                log_notice("Receive SIGTERM or SIGINT. Exit.");
                keep_going = 0;
        }
        /* ... etc ... */
 }

 {
        struct sigaction sa;

        memset(&sa, 0, sizeof(struct sigaction));
        sa.sa_handler = sig_handler;

        sigaction(SIGTERM, &sa, NULL);
        /* ... repeated for all handling signals ... */

        sigfillset(&set);
        sigprocmask(SIG_BLOCK, &set, NULL);

        sigemptyset(&unblocked);

        while(1)
        {
               clock_gettime(CLOCK_MONOTONIC, &tp)

               if(pselect(max_fd + 1, &readset, &writeset, NULL,
                             &timeout, &unblocked) < 0)
               {
                     /* signal was caught ? */
                     if(errno == EINTR)
                     {
                         /* ... check variable set by sig handler ... */
                         if(!keep_going)
                             /*... etc ...*/
                     }

               /*... etc ...*/
       }
 }

On my linux, the mecanism works well but in netbsd, the signal handler
isn't call.

ktrace:
{{{
  1008      1 yaddns   CALL
pselect(1,0xbfbfebb0,0xbfbfebd0,0,0xbfbfec28,0xbfbfec08)
  1008      1 yaddns   RET   pselect -1 errno 4 Interrupted system call
  1008      1 yaddns   CALL  clock_gettime(3,0xbfbfeaec)
  1008      1 yaddns   RET   clock_gettime 0
  1008      1 yaddns   CALL
pselect(1,0xbfbfebb0,0xbfbfebd0,0,0xbfbfec28,0xbfbfec08)
}}}

But, if i unblock all signals after pselect() was interrupted by
signal, it works:

                     if(errno == EINTR)
                     {
                          sigfillset(&set);
                          sigprocmask(SIG_UNBLOCK, &set, NULL);
                          /* ... etc ... */

ktrace:
{{{
  5997      1 yaddns   CALL
pselect(1,0xbfbfebc0,0xbfbfebe0,0,0xbfbfec28,0xbfbfec18)
  5997      1 yaddns   RET   pselect -1 errno 4 Interrupted system call
  5997      1 yaddns   CALL  __sigprocmask14(2,0xbfbfeb08,0)
  5997      1 yaddns   RET   __sigprocmask14 0
  5997      1 yaddns   PSIG  SIGINT caught handler=0x80491dc mask=():
code=SI_NOINFO
  5997      1 yaddns   CALL  write(1,0xbb91e000,0x21)
  5997      1 yaddns   GIO   fd 1 wrote 33 bytes
       "Receive SIGTERM or SIGINT. Exit.\n"
  5997      1 yaddns   RET   write 33/0x21
  5997      1 yaddns   CALL  setcontext(0xbfbfe7e4)
  5997      1 yaddns   RET   syscall JUSTRETURN
}}}

But accorded to all information have found (man, internet), the signal
is delivered BEFORE the pselect() call returns.

So i think there a problem in kernel code :)

Cheers,
Viallard Anthony.


Home | Main Index | Thread Index | Old Index