signals: rework when CURSIG/issignal can stop a thread for tracing
authorSimon Schubert <corecode@dragonflybsd.org>
Sat, 7 Mar 2009 17:09:13 +0000 (18:09 +0100)
committerSimon Schubert <simon.schubert@epfl.ch>
Mon, 9 Mar 2009 17:00:03 +0000 (18:00 +0100)
When tracing a process, it can happen that the thread would get stopped
due to the signal and its tracing.  In this case the tracing parent
would get notified and it might choose to let the process to serve the
signal.

However if this stop+trace is happening somewhere deep in the kernel due
to a call to CURSIG(), it might happen that the same signal again is the
cause for a stop+trace cycle because of another call to CURSIG() while
the call stack is unwinding.

Introduce CURSIG_TRACE(), which explicitly allows stopping for tracing
signal delivery.  This is only called from userret().
All other instances of CURSIG() may still block/sleep because of SA_STOP
signals, but these invocations may not trace + repost signals.

As such, the only place where trace + repost of signals can happen now
is userret().  Nevertheless, CURSIG() still decides not to ignore a
currently ignored signal and rather lets the kernel unwind until this
signal arrives in the CURSIG_TRACE() called from userret().

sys/kern/kern_sig.c
sys/platform/pc32/i386/trap.c
sys/platform/pc64/amd64/trap.c
sys/platform/vkernel/i386/trap.c
sys/sys/signal2.h
sys/sys/signalvar.h

index 541a3ea..c8030e7 100644 (file)
@@ -1410,7 +1410,7 @@ kern_sigtimedwait(sigset_t waitset, siginfo_t *info, struct timespec *timeout)
                        SIGFILLSET(lp->lwp_sigmask);
                        SIGDELSET(lp->lwp_sigmask, sig);
                        SIG_CANTMASK(lp->lwp_sigmask);
-                       sig = issignal(lp);
+                       sig = issignal(lp, 1);
                        /*
                         * It may be a STOP signal, in the case, issignal
                         * returns 0, because we may stop there, and new
@@ -1587,7 +1587,7 @@ iscaught(struct lwp *lp)
  *             postsig(sig);
  */
 int
-issignal(struct lwp *lp)
+issignal(struct lwp *lp, int maytrace)
 {
        struct proc *p = lp->lwp_proc;
        sigset_t mask;
@@ -1597,6 +1597,12 @@ issignal(struct lwp *lp)
        for (;;) {
                int traced = (p->p_flag & P_TRACED) || (p->p_stops & S_SIG);
 
+               /*
+                * If this process is supposed to stop, stop this thread.
+                */
+               if (p->p_stat == SSTOP)
+                       tstop();
+
                mask = lwp_sigpend(lp);
                SIGSETNAND(mask, lp->lwp_sigmask);
                if (p->p_flag & P_PPWAIT)
@@ -1617,7 +1623,7 @@ issignal(struct lwp *lp)
                        lwp_delsig(lp, sig);
                        continue;
                }
-               if ((p->p_flag & P_TRACED) && (p->p_flag & P_PPWAIT) == 0) {
+               if (maytrace && (p->p_flag & P_TRACED) && (p->p_flag & P_PPWAIT) == 0) {
                        /*
                         * If traced, always stop, and stay stopped until
                         * released by the parent.
@@ -1710,9 +1716,7 @@ issignal(struct lwp *lp)
                                        break;  /* == ignore */
                                p->p_xstat = sig;
                                proc_stop(p);
-                               while (p->p_stat == SSTOP) {
-                                       tstop();
-                               }
+                               tstop();
                                break;
                        } else if (prop & SA_IGNORE) {
                                /*
index 739b747..c31c13e 100644 (file)
@@ -284,7 +284,7 @@ recheck:
         * Post any pending signals.  If running a virtual kernel be sure
         * to restore the virtual kernel's vmspace before posting the signal.
         */
-       if ((sig = CURSIG(lp)) != 0) {
+       if ((sig = CURSIG_TRACE(lp)) != 0) {
                get_mplock();
                postsig(sig);
                rel_mplock();
index aaf8fd2..dc8c603 100644 (file)
@@ -255,7 +255,7 @@ recheck:
         * Post any pending signals.  If running a virtual kernel be sure
         * to restore the virtual kernel's vmspace before posting the signal.
         */
-       if ((sig = CURSIG(lp)) != 0) {
+       if ((sig = CURSIG_TRACE(lp)) != 0) {
                get_mplock();
                postsig(sig);
                rel_mplock();
index bd1bfed..a3ed277 100644 (file)
@@ -268,7 +268,7 @@ recheck:
        /*
         * Post any pending signals
         */
-       if ((sig = CURSIG(lp)) != 0) {
+       if ((sig = CURSIG_TRACE(lp)) != 0) {
                get_mplock();
                postsig(sig);
                rel_mplock();
index 0e7aa29..3414eda 100644 (file)
@@ -66,7 +66,8 @@ lwp_delsig(struct lwp *lp, int sig)
        SIGDELSET(lp->lwp_proc->p_siglist, sig);
 }
 
-#define        CURSIG(lp)      __cursig(lp)
+#define        CURSIG(lp)              __cursig(lp, 0)
+#define        CURSIG_TRACE(lp)        __cursig(lp, 1)
 #define CURSIGNB(lp)   __cursignb(lp)
 
 /*
@@ -78,7 +79,7 @@ lwp_delsig(struct lwp *lp, int sig)
  */
 static __inline
 int
-__cursig(struct lwp *lp)
+__cursig(struct lwp *lp, int maytrace)
 {
        struct proc *p;
        sigset_t tmpset;
@@ -89,7 +90,7 @@ __cursig(struct lwp *lp)
        SIGSETNAND(tmpset, lp->lwp_sigmask);
        if (!(p->p_flag & P_TRACED) && SIGISEMPTY(tmpset))
                return(0);
-       r = issignal(lp);
+       r = issignal(lp, maytrace);
        return(r);
 }
 
index 0266cd0..875fa24 100644 (file)
@@ -192,7 +192,7 @@ extern int sugid_coredump;  /* Sysctl variable kern.sugid_coredump */
  */
 void   execsigs (struct proc *p);
 void   gsignal (int pgid, int sig);
-int    issignal (struct lwp *lp);
+int    issignal (struct lwp *lp, int maytrace);
 int    iscaught (struct lwp *p);
 void   killproc (struct proc *p, char *why);
 void   pgsigio (struct sigio *, int signum, int checkctty);