Hi,

Since the recent futex(2) changes the posixtestsuite regress does
not finish within the given time frame.  Depending on some races
tests hang, e.g. this one:

/usr/local/libexec/posixtestsuite/conformance/interfaces/pthread_atfork/3-3.test

It spans a worker thread that allows to handle SIGUSR1 or SIGUSR2.
Two signal sending threads are created that kill the process with
SIGUSR1 or SIGUSR2 repectively.  The main thread and the signal
sending threads block these signals.  The signal handler in the
worker thread uses semaphores to acknowledge signals and then the
sending threads kill again.

It may happen that the worker thread is in the signal handler and
also blocks the signals.  Then all threads block them and ptsignal()
sends it to the main thread.  In the test program the main thread
blocks them forever and the process gets stuck.

According to POSIX any thread should process the signal when it
unblocks.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_01
    If there are no threads in a call to a sigwait() function
    selecting that signal, and if all threads within the process
    block delivery of the signal, the signal shall remain pending
    on the process until a thread calls a sigwait() function selecting
    that signal, a thread unblocks delivery of the signal, or the
    action associated with the signal is set to ignore the signal.

For this purpose NetBSD has l_sigpend for the thread and p_sigpend
for the process.

As prsignal() sends the signal to ps_mainproc if it cannot be
delivered immediately, we could also consider the main proc when
we check for pending signals.  This fixes my use case without beeing
to invasive.

ok?

bluhm

Index: kern/kern_sig.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.220
diff -u -p -r1.220 kern_sig.c
--- kern/kern_sig.c     28 Apr 2018 03:13:04 -0000      1.220
+++ kern/kern_sig.c     22 Jun 2018 19:28:54 -0000
@@ -1155,14 +1155,18 @@ issignal(struct proc *p)
        int s;
 
        for (;;) {
-               mask = p->p_siglist & ~p->p_sigmask;
+               mask = p->p_siglist | pr->ps_mainproc->p_siglist;
+               mask &= ~p->p_sigmask;
                if (pr->ps_flags & PS_PPWAIT)
                        mask &= ~stopsigmask;
                if (mask == 0)          /* no signal to send */
                        return (0);
                signum = ffs((long)mask);
                mask = sigmask(signum);
-               atomic_clearbits_int(&p->p_siglist, mask);
+               if (p->p_siglist & mask)
+                       atomic_clearbits_int(&p->p_siglist, mask);
+               else
+                       atomic_clearbits_int(&pr->ps_mainproc->p_siglist, mask);
 
                /*
                 * We should see pending but ignored signals
Index: sys/signalvar.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/signalvar.h,v
retrieving revision 1.30
diff -u -p -r1.30 signalvar.h
--- sys/signalvar.h     24 Mar 2018 04:13:59 -0000      1.30
+++ sys/signalvar.h     22 Jun 2018 19:28:54 -0000
@@ -68,7 +68,9 @@ struct        sigacts {
 /*
  * Check if process p has an unmasked signal pending.
  */
-#define        SIGPENDING(p)   (((p)->p_siglist & ~(p)->p_sigmask) != 0)
+#define        SIGPENDING(p)                                                   
\
+       ((((p)->p_siglist | (p)->p_p->ps_mainproc->p_siglist) &         \
+           ~(p)->p_sigmask) != 0)
 
 /*
  * Determine signal that should be delivered to process p, the current
@@ -76,9 +78,11 @@ struct       sigacts {
  * action, the process stops in issignal().
  */
 #define        CURSIG(p)                                                       
\
-       (((p)->p_siglist == 0 ||                                        \
+       ((((p)->p_siglist == 0 &&                                       \
+           (p)->p_p->ps_mainproc->p_siglist == 0) ||                   \
            (((p)->p_p->ps_flags & PS_TRACED) == 0 &&                   \
-           ((p)->p_siglist & ~(p)->p_sigmask) == 0)) ?                 \
+           (((p)->p_siglist | (p)->p_p->ps_mainproc->p_siglist) &      \
+           ~(p)->p_sigmask) == 0)) ?                                   \
            0 : issignal(p))
 
 /*

Reply via email to