Interrupts hadling while idle
- 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.
This commit is contained in:
		
							parent
							
								
									bde2109b7c
								
							
						
					
					
						commit
						8451a86f0a
					
				@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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								;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
@ -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								;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -141,4 +141,13 @@
 | 
			
		||||
	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__ */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user