Messages in this thread | | | From | "Michael Clarke" <> | Subject | LINUX task switching on i386 | Date | Fri, 27 Mar 1998 09:03:50 -0000 |
| |
Hello once again to all LINUX kings ! (especially Jean Wolter who helped me last time !),
As my studies of the LINUX kernel continue, I have found one last obstacle in the way of my understanding. This is the real life implementation of hardware task switching (i.e. using TSS's) in the LINUX OS / i386.
Regarding TSS's, when a new task is JUMPed to (via its TSS descriptor), then the old task TSS should be chained (by the hardware), through its link field, to other descheduled tasks (and have their NT flag set), this is according to the text description of the TSS task linking section of the 386 manual (section 7.6). If you look at table 7-2, it says that the link field is only used when a task switch is caused by a CALL or INTERRUPTS**, which one is true ? I assume it is the chart which is correct because if you link switched tasks (after the JMP tss in switch_to() called by schedule() ) their busy bit remains set and you cant re-enter them when switch_to() is called again for the new task -> cause a GPE quickly. The only way to unchain would be via iret which i dont think user processes will do voluntarily and this would not be good scheduling ! :)
**just checking here: LINUX doesnt use a new task for interrupts, it just executes in the kernel segment using the current tasks context - is this correct ? - if it is true, then task linking never occurs in LINUX which answers some of my problems !
Leading on from this to a more LINUX specific issue, I will present what I think happens when a timer interrupt occurs and would appreciate any corrections that anyone can make:
Say a timer interrupt occurs while a user process is executing in user mode, the timer interrupt handler is invoked (looking at build_timer_irq in irq.h), this invokes do_timer still at interrupt level (this is slightly different to other slow interrupts which re-enable OTHER types of interrupt before doing do_irq) i.e. no more timer interrupts allowed, which sets up its bottom half and exits. All interrupts are still disabled while build_timer_irq calls ret_from_sys_call. At this point if we interrupted another interrupt (intr_count!=0) we just iret otherwise the presence of activated bottom halves is detected and interrupts are re-enabled before calling handle_bottom_half, this invokes timer_bh (but only if another timer bottom half hasn't been interrupted (a check in do_bottom_half) - is this correct ? or is there something else preventing bottom halves from being re-entered) which is responsible for setting need_resched if quanta have expired etc. When the bottom half exits back to ret_from_sys_call, we check to see if we interrupted someone in a system call (iret straight away) else (interrupted someone in user space) we call schedule() if need_resched is set which performs the magic JMP tss to switch to a new task. When this task is re-invoked the last part of schedule() executes and returns us to ret_from_sys_call which calls RESTORE_ALL which performs the iret to return from the original timer interrupt to the user process
Somewhere I am getting mixed up with exactly how bottom halves work, how do they avoid being re-entered (is it like i think ?), can you have more than one type of bottom half on the active list e.g. 2 timer bottom halves, and how does LINUX ensure that only one bottom half is being executed at a time (in the presence of other interrupts which call ret_from_sys_call and do_bottom_half - it must be to do with intr_count but I dont see where the bottom half code sets intr_count)...
Cheers for any help offered,
Mike
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu
| |