]> Zhao Yanbai Git Server - minix.git/commitdiff
Interrupts hadling while idle
authorTomas Hruby <tom@minix3.org>
Tue, 23 Mar 2010 13:35:01 +0000 (13:35 +0000)
committerTomas Hruby <tom@minix3.org>
Tue, 23 Mar 2010 13:35:01 +0000 (13:35 +0000)
- When the cpu halts, the interrupts are enable so the cpu may be
  woken up. When the interrupt handler returns but another interrupt
  is available it is also serviced immediately. This is not a problem
  per-se. It only slightly breaks time accounting as idle accounted is
  for the kernel time in the interrupt handler.

-  As the big kernel lock is lock/unlocked in the smp branch in the
   time acounting functions as they are called exactly at the places
   we need to take the lock) this leads to a deadlock.

- we make sure that once the interrupt handler returns from the nested
  trap, the interrupts are disabled. This means that only one
  interrupt is serviced after idle is interrupted.

- this requires the loop in apic timer calibration to keep reenabling
  the interrupts. I admit it is a little bit hackish (one line),
  however, this code is a stupid corner case at the boot time.
  Hopefully it does not matter too much.

kernel/arch/i386/apic.c
kernel/arch/i386/apic_asm.S
kernel/arch/i386/klib386.S
kernel/arch/i386/mpx386.S
kernel/arch/i386/sconst.h

index 32b6d8bb70ba8f116ad26bcdbff2f29e6388ca8a..b5fa1a26f810ab2efa3eb2929363e464695a67c8 100644 (file)
@@ -144,7 +144,9 @@ PUBLIC void apic_calibrate_clocks(void)
        init_8253A_timer(system_hz);
 
        /* loop for some time to get a sample */
-       while(probe_ticks < PROBE_TICKS);
+       while(probe_ticks < PROBE_TICKS) {
+               intr_enable();
+       }
 
        intr_disable();
        stop_8253A_timer();
index 815ce2825ca3503f730ee874a60abb4c359afda3..d014928e9bfa17daae58428cec8858ea8c19c05b 100644 (file)
@@ -48,6 +48,7 @@
        pusha                                                           ;\
        call    cycles_accounting_stop_idle                             ;\
        APIC_IRQ_HANDLER(irq)                                           ;\
+       CLEAR_IF(10*4(%esp))                                            ;\
        popa                                                            ;\
        iret                                                            ;
 
@@ -158,6 +159,7 @@ apic_hwint15:
        pusha                                                           ;\
        call    cycles_accounting_stop_idle                             ;\
        LAPIC_INTR_HANDLER(func)                                        ;\
+       CLEAR_IF(10*4(%esp))                                            ;\
        popa                                                            ;\
        iret                                                            ;
 
index d1bb9c1aa0dde5a49e57dc9e1db3dfae6e5e242b..a4b09c005671a9119d4d49d9aa324dc8b3814b31 100644 (file)
@@ -608,8 +608,11 @@ idt_zero:
  */
 halt_cpu:
        sti
-       hlt
-       cli
+       hlt /* interrupts enabled only after this instruction is executed! */
+       /*
+        * interrupt handlers make sure that the interrupts are disabled when we
+        * get here so we take only _one_ interrupt after halting the CPU
+        */
        ret
 
 /*===========================================================================*/
index 293f1df025d11153826aadbe6d0e7e73f01f4fcb..a768db586392418a9fa5670a601b5561c95cc38d 100644 (file)
@@ -267,6 +267,7 @@ csinit:
        PIC_IRQ_HANDLER(irq)                                            ;\
        movb    $END_OF_INT, %al                                        ;\
        outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
+       CLEAR_IF(10*4(%esp))                                            ;\
        popa                                                            ;\
        iret                                                            ;
 
@@ -336,6 +337,7 @@ hwint07:
        movb    $END_OF_INT, %al                                        ;\
        outb    $INT_CTL        /* reenable interrupts in master pic */ ;\
        outb    $INT2_CTL       /* reenable slave 8259            */    ;\
+       CLEAR_IF(10*4(%esp))                                            ;\
        popa                                                            ;\
        iret                                                            ;
 
index efda211d0f5f0337a8a25e582c16468d7e5d7487..0bad53dd6ab5595bd38753f7efdfb6ce73ac2384 100644 (file)
        call    lazy_fpu                                        ;\
        add     $4, %esp                                        ;
 
+/*
+ * clear the IF flag in eflags which are stored somewhere in memory, e.g. on
+ * stack. iret or popf will load the new value later
+ */
+#define CLEAR_IF(where)        \
+       mov     where, %eax                                             ;\
+       andl    $0xfffffdff, %eax                                       ;\
+       mov     %eax, where                                             ;
+
 #endif /* __SCONST_H__ */