kernel - Fix itimer hard critical section panic
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Nov 2011 00:26:48 +0000 (16:26 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Nov 2011 00:26:48 +0000 (16:26 -0800)
* ksignal() needs per-lwp tokens as well as the process token, the existing
  itimer code only gets the process token.

* Flag the itimer signal and issue the ksignal() in the trap's AST code
  instead of trying to issue it from the hardclock.

Reported-by: swildner
sys/kern/kern_clock.c
sys/kern/kern_time.c
sys/platform/pc32/i386/trap.c
sys/platform/pc64/x86_64/trap.c
sys/platform/vkernel/i386/trap.c
sys/platform/vkernel64/x86_64/trap.c
sys/sys/proc.h

index 697b327..63e9951 100644 (file)
@@ -554,17 +554,26 @@ hardclock(systimer_t info, int in_ipi __unused, struct intrframe *frame)
         * ITimer handling is per-tick, per-cpu.
         *
         * We must acquire the per-process token in order for ksignal()
-        * to be non-blocking.
+        * to be non-blocking.  For the moment this requires an AST fault,
+        * the ksignal() cannot be safely issued from this hard interrupt.
+        *
+        * XXX Even the trytoken here isn't right, and itimer operation in
+        *     a multi threaded environment is going to be weird at the
+        *     very least.
         */
        if ((p = curproc) != NULL && lwkt_trytoken(&p->p_token)) {
                crit_enter_hard();
                if (frame && CLKF_USERMODE(frame) &&
                    timevalisset(&p->p_timer[ITIMER_VIRTUAL].it_value) &&
-                   itimerdecr(&p->p_timer[ITIMER_VIRTUAL], ustick) == 0)
-                       ksignal(p, SIGVTALRM);
+                   itimerdecr(&p->p_timer[ITIMER_VIRTUAL], ustick) == 0) {
+                       p->p_flag |= P_SIGVTALRM;
+                       need_user_resched();
+               }
                if (timevalisset(&p->p_timer[ITIMER_PROF].it_value) &&
-                   itimerdecr(&p->p_timer[ITIMER_PROF], ustick) == 0)
-                       ksignal(p, SIGPROF);
+                   itimerdecr(&p->p_timer[ITIMER_PROF], ustick) == 0) {
+                       p->p_flag |= P_SIGPROF;
+                       need_user_resched();
+               }
                crit_exit_hard();
                lwkt_reltoken(&p->p_token);
        }
index f454feb..d77f93d 100644 (file)
@@ -753,6 +753,14 @@ sys_setitimer(struct setitimer_args *uap)
                p->p_realtimer = aitv;
        } else {
                p->p_timer[uap->which] = aitv;
+               switch(uap->which) {
+               case ITIMER_VIRTUAL:
+                       p->p_flag &= ~P_SIGVTALRM;
+                       break;
+               case ITIMER_PROF:
+                       p->p_flag &= ~P_SIGPROF;
+                       break;
+               }
        }
        lwkt_reltoken(&p->p_token);
        return (0);
index 2b4b900..4676fbd 100644 (file)
@@ -273,10 +273,20 @@ recheck:
         * Post any pending upcalls.  If running a virtual kernel be sure
         * to restore the virtual kernel's vmspace before posting the upcall.
         */
-       if (p->p_flag & P_UPCALLPEND) {
+       if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) {
                lwkt_gettoken(&p->p_token);
-               p->p_flag &= ~P_UPCALLPEND;
-               postupcall(lp);
+               if (p->p_flag & P_SIGVTALRM) {
+                       p->p_flag &= ~P_SIGVTALRM;
+                       ksignal(p, SIGVTALRM);
+               }
+               if (p->p_flag & P_SIGPROF) {
+                       p->p_flag &= ~P_SIGPROF;
+                       ksignal(p, SIGPROF);
+               }
+               if (p->p_flag & P_UPCALLPEND) {
+                       p->p_flag &= ~P_UPCALLPEND;
+                       postupcall(lp);
+               }
                lwkt_reltoken(&p->p_token);
                goto recheck;
        }
index 795fbfc..cdde57d 100644 (file)
@@ -250,10 +250,20 @@ recheck:
         * Post any pending upcalls.  If running a virtual kernel be sure
         * to restore the virtual kernel's vmspace before posting the upcall.
         */
-       if (p->p_flag & P_UPCALLPEND) {
+       if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) {
                lwkt_gettoken(&p->p_token);
-               p->p_flag &= ~P_UPCALLPEND;
-               postupcall(lp);
+               if (p->p_flag & P_SIGVTALRM) {
+                       p->p_flag &= ~P_SIGVTALRM;
+                       ksignal(p, SIGVTALRM);
+               }
+               if (p->p_flag & P_SIGPROF) {
+                       p->p_flag &= ~P_SIGPROF;
+                       ksignal(p, SIGPROF);
+               }
+               if (p->p_flag & P_UPCALLPEND) {
+                       p->p_flag &= ~P_UPCALLPEND;
+                       postupcall(lp);
+               }
                lwkt_reltoken(&p->p_token);
                goto recheck;
        }
index 3d36f4e..9af5110 100644 (file)
@@ -244,12 +244,23 @@ recheck:
        }
 
        /*
-        * Post any pending upcalls
+        * Post any pending upcalls.  If running a virtual kernel be sure
+        * to restore the virtual kernel's vmspace before posting the upcall.
         */
-       if (p->p_flag & P_UPCALLPEND) {
+       if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) {
                lwkt_gettoken(&p->p_token);
-               p->p_flag &= ~P_UPCALLPEND;
-               postupcall(lp);
+               if (p->p_flag & P_SIGVTALRM) {
+                       p->p_flag &= ~P_SIGVTALRM;
+                       ksignal(p, SIGVTALRM);
+               }
+               if (p->p_flag & P_SIGPROF) {
+                       p->p_flag &= ~P_SIGPROF;
+                       ksignal(p, SIGPROF);
+               }
+               if (p->p_flag & P_UPCALLPEND) {
+                       p->p_flag &= ~P_UPCALLPEND;
+                       postupcall(lp);
+               }
                lwkt_reltoken(&p->p_token);
                goto recheck;
        }
index 9398421..c7ffa5f 100644 (file)
@@ -244,12 +244,23 @@ recheck:
        }
 
        /*
-        * Post any pending upcalls
+        * Post any pending upcalls.  If running a virtual kernel be sure
+        * to restore the virtual kernel's vmspace before posting the upcall.
         */
-       if (p->p_flag & P_UPCALLPEND) {
+       if (p->p_flag & (P_SIGVTALRM | P_SIGPROF | P_UPCALLPEND)) {
                lwkt_gettoken(&p->p_token);
-               p->p_flag &= ~P_UPCALLPEND;
-               postupcall(lp);
+               if (p->p_flag & P_SIGVTALRM) {
+                       p->p_flag &= ~P_SIGVTALRM;
+                       ksignal(p, SIGVTALRM);
+               }
+               if (p->p_flag & P_SIGPROF) {
+                       p->p_flag &= ~P_SIGPROF;
+                       ksignal(p, SIGPROF);
+               }
+               if (p->p_flag & P_UPCALLPEND) {
+                       p->p_flag &= ~P_UPCALLPEND;
+                       postupcall(lp);
+               }
                lwkt_reltoken(&p->p_token);
                goto recheck;
        }
index 8ab2ec1..15ba8ef 100644 (file)
@@ -366,8 +366,8 @@ struct      proc {
 #define P_IDLESWAP     0x400000 /* Swapout was due to idleswap, not load */
 
 #define        P_JAILED        0x1000000 /* Process is in jail */
-#define        P_UNUSED0       0x2000000 /* need to restore mask before pause */
-#define        P_UNUSED1       0x4000000 /* have alternate signal stack */
+#define        P_SIGVTALRM     0x2000000 /* signal SIGVTALRM pending due to itimer */
+#define        P_SIGPROF       0x4000000 /* signal SIGPROF pending due to itimer */
 #define        P_INEXEC        0x8000000 /* Process is in execve(). */
 #define P_UNUSED1000   0x10000000
 #define        P_UPCALLWAIT    0x20000000 /* Wait for upcall or signal */