Implement interrupt thread preemption + minor cleanup.
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 29 Jun 2003 05:29:31 +0000 (05:29 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 29 Jun 2003 05:29:31 +0000 (05:29 +0000)
sys/cpu/i386/include/cpu.h
sys/i386/include/cpu.h
sys/kern/kern_clock.c
sys/kern/kern_intr.c
sys/kern/lwkt_thread.c
sys/sys/thread.h

index a240e74..888abb8 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
  * $FreeBSD: src/sys/i386/include/cpu.h,v 1.43.2.2 2001/06/15 09:37:57 scottl Exp $
- * $DragonFly: src/sys/cpu/i386/include/cpu.h,v 1.5 2003/06/29 03:28:43 dillon Exp $
+ * $DragonFly: src/sys/cpu/i386/include/cpu.h,v 1.6 2003/06/29 05:29:30 dillon Exp $
  */
 
 #ifndef _MACHINE_CPU_H_
        ((ISPL((framep)->cf_cs) == SEL_UPL) || (framep->cf_eflags & PSL_VM))
 
 #define CLKF_INTR(framep)      (mycpu->gd_intr_nesting_level >= 2)
-#if 0
-/*
- * XXX splsoftclock() is very broken and barely worth fixing.  It doesn't
- * turn off the clock bit in imen or in the icu.  (This is not a serious
- * problem at 100 Hz but it is serious at 16000 Hz for pcaudio.  softclock()
- * can take more than 62.5 usec so clock interrupts are lost.)  It doesn't
- * check for pending interrupts being unmasked.  clkintr() and Xintr0()
- * assume that the ipl is high when hardclock() returns.  Our SWI_CLOCK
- * handling is efficient enough that little is gained by calling
- * softclock() directly.
- */
-#define        CLKF_BASEPRI(framep)    ((framep)->cf_ppl == 0)
-#else
-#define        CLKF_BASEPRI(framep)    (0)
-#endif
 #define        CLKF_PC(framep)         ((framep)->cf_eip)
 
 /*
index 700e916..55ab059 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
  * $FreeBSD: src/sys/i386/include/cpu.h,v 1.43.2.2 2001/06/15 09:37:57 scottl Exp $
- * $DragonFly: src/sys/i386/include/Attic/cpu.h,v 1.5 2003/06/29 03:28:43 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/cpu.h,v 1.6 2003/06/29 05:29:30 dillon Exp $
  */
 
 #ifndef _MACHINE_CPU_H_
        ((ISPL((framep)->cf_cs) == SEL_UPL) || (framep->cf_eflags & PSL_VM))
 
 #define CLKF_INTR(framep)      (mycpu->gd_intr_nesting_level >= 2)
-#if 0
-/*
- * XXX splsoftclock() is very broken and barely worth fixing.  It doesn't
- * turn off the clock bit in imen or in the icu.  (This is not a serious
- * problem at 100 Hz but it is serious at 16000 Hz for pcaudio.  softclock()
- * can take more than 62.5 usec so clock interrupts are lost.)  It doesn't
- * check for pending interrupts being unmasked.  clkintr() and Xintr0()
- * assume that the ipl is high when hardclock() returns.  Our SWI_CLOCK
- * handling is efficient enough that little is gained by calling
- * softclock() directly.
- */
-#define        CLKF_BASEPRI(framep)    ((framep)->cf_ppl == 0)
-#else
-#define        CLKF_BASEPRI(framep)    (0)
-#endif
 #define        CLKF_PC(framep)         ((framep)->cf_eip)
 
 /*
index a1fb47f..6fe2f2b 100644 (file)
@@ -38,7 +38,7 @@
  *
  *     @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/kern_clock.c,v 1.105.2.10 2002/10/17 13:19:40 maxim Exp $
- * $DragonFly: src/sys/kern/kern_clock.c,v 1.4 2003/06/28 04:16:04 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_clock.c,v 1.5 2003/06/29 05:29:31 dillon Exp $
  */
 
 #include "opt_ntp.h"
@@ -254,17 +254,10 @@ hardclock(frame)
         * relatively high clock interrupt priority any longer than necessary.
         */
        if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {
-               if (CLKF_BASEPRI(frame)) {
-                       /*
-                        * Save the overhead of a software interrupt;
-                        * it will happen as soon as we return, so do it now.
-                        */
-                       (void)splsoftclock();
-                       softclock();
-               } else
-                       setsoftclock();
-       } else if (softticks + 1 == ticks)
+               setsoftclock();
+       } else if (softticks + 1 == ticks) {
                ++softticks;
+       }
 }
 
 /*
index 3db8f47..249c91f 100644 (file)
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_intr.c,v 1.24.2.1 2001/10/14 20:05:50 luigi Exp $
- * $DragonFly: src/sys/kern/kern_intr.c,v 1.3 2003/06/29 03:28:44 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_intr.c,v 1.4 2003/06/29 05:29:31 dillon Exp $
  *
  */
 
@@ -139,7 +139,8 @@ unregister_int(int intr, inthand2_t handler)
 }
 
 /*
- * Dispatch an interrupt.
+ * Dispatch an interrupt.  If there's nothing to do we have a stray
+ * interrupt and can just return, leaving the interrupt masked.
  */
 void
 sched_ithd(int intr)
@@ -147,15 +148,20 @@ sched_ithd(int intr)
     thread_t td;
 
     if ((td = ithreads[intr]) != NULL) {
-       if (intlists[intr] == NULL)
+       if (intlists[intr] == NULL) {
            printf("sched_ithd: stray interrupt %d\n", intr);
-       else
+       } else {
            lwkt_schedule(td);
+           lwkt_preempt(td, intr);
+       }
     } else {
        printf("sched_ithd: stray interrupt %d\n", intr);
     }
 }
 
+/*
+ * Interrupt threads run this as their main loop.
+ */
 static void
 ithread_handler(void *arg)
 {
@@ -171,7 +177,14 @@ ithread_handler(void *arg)
            rec->handler(rec->argument);
        }
        ithread_done(intr);
-       KKASSERT(curthread->td_pri == TDPRI_CRIT);
+
+       /*
+        * temporary sanity check.  If we preempted another thread we
+        * are placed in another critical section by that thread which
+        * will be released when we block and resume the original thread.
+        */
+       KKASSERT(curthread->td_pri == TDPRI_CRIT ||
+           (curthread->td_preempted && curthread->td_pri == 2 * TDPRI_CRIT));
     }
     crit_exit();       /* not reached */
 }
index ba645e7..385678a 100644 (file)
@@ -27,7 +27,7 @@
  *     thread scheduler, which means that generally speaking we only need
  *     to use a critical section to prevent hicups.
  *
- * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.9 2003/06/29 03:28:44 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.10 2003/06/29 05:29:31 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -206,7 +206,7 @@ lwkt_switch(void)
     thread_t td = curthread;
     thread_t ntd;
 
-    if (mycpu->gd_intr_nesting_level)
+    if (mycpu->gd_intr_nesting_level && td->td_preempted == NULL)
        panic("lwkt_switch: cannot switch from within an interrupt\n");
 
     crit_enter();
@@ -216,6 +216,7 @@ lwkt_switch(void)
         * thread.
         */
        td->td_preempted = NULL;
+       td->td_pri -= TDPRI_CRIT;
        ntd->td_flags &= ~TDF_PREEMPTED;
     } else if ((ntd = TAILQ_FIRST(&mycpu->gd_tdrunq)) != NULL) {
        TAILQ_REMOVE(&mycpu->gd_tdrunq, ntd, td_threadq);
@@ -228,6 +229,36 @@ lwkt_switch(void)
     crit_exit();
 }
 
+/*
+ * The target thread preempts the current thread.  The target thread
+ * structure must be stable and preempt-safe (e.g. an interrupt thread).
+ * When the target thread blocks the current thread will be resumed.
+ *
+ * XXX the target runs in a critical section so it does not open the original
+ * thread up to additional interrupts that the original thread believes it
+ * is blocking.
+ *
+ * Normal kernel threads should not preempt other normal kernel threads
+ * as it breaks the assumptions kernel threads are allowed to make.  Note
+ * that preemption does not mess around with the current thread's RUNQ
+ * state.
+ */
+void
+lwkt_preempt(struct thread *ntd, int id)
+{
+    struct thread *td = curthread;
+
+    crit_enter();
+    if (ntd->td_preempted == NULL) {
+       ntd->td_preempted = curthread;
+       td->td_flags |= TDF_PREEMPTED;
+       ntd->td_pri += TDPRI_CRIT;
+       while (td->td_flags & TDF_PREEMPTED)
+           ntd->td_switch(ntd);
+    }
+    crit_exit_noyield();
+}
+
 /*
  * Yield our thread while higher priority threads are pending.  This is
  * typically called when we leave a critical section but it can be safely
index 1b9f3b3..d18648f 100644 (file)
@@ -4,7 +4,7 @@
  *     Implements the architecture independant portion of the LWKT 
  *     subsystem.
  * 
- * $DragonFly: src/sys/sys/thread.h,v 1.13 2003/06/29 03:28:46 dillon Exp $
+ * $DragonFly: src/sys/sys/thread.h,v 1.14 2003/06/29 05:29:31 dillon Exp $
  */
 
 #ifndef _SYS_THREAD_H_
@@ -198,7 +198,7 @@ extern void lwkt_free_thread(struct thread *td);
 extern void lwkt_init_wait(struct lwkt_wait *w);
 extern void lwkt_gdinit(struct globaldata *gd);
 extern void lwkt_switch(void);
-extern void lwkt_preempt(void);
+extern void lwkt_preempt(thread_t ntd, int id);
 extern void lwkt_schedule(thread_t td);
 extern void lwkt_schedule_self(void);
 extern void lwkt_deschedule(thread_t td);