I have been trying to understand how context switching works in Linux Kernel. It appears to me that there is a situation (explained later) which results in no invocation of IRET instruction after the interrupt (I am sure that there is something that I am missing!). I am assuming that invocation of IRET after the interrupt is extremely necessary, since you can't get the same interrupt until you invoke IRET. I am only worried about uni-processor kernel running on x86 arch.
The situation that I think might result in the described behavior is as follows:
Process A running in kernel mode calls
schedule()
voluntarily (for example while trying to acquire an already locked mutex).schedule()
decides to perform a context switch to process B and hence callscontext_switch()
context_switch()
switches virtual memory from A to B by callingswitch_mm()
context_switch()
runs macroswitch_to()
to switch stacks and actually change the running process from A to B. Note that process A is now stuck insideswitch_to()
and the stack of process A looks like (stack growing downwards):
...
[mutex_lock()]
[schedule()]
[context_switch()] (Stack Top)
Process B starts running. At some later time, it receives a timer interrupt and the timer interrupt handler decides that process B needs a reschedule.
On return from timer interrupt (but before invoking IRET)
preempt_schedule_irq()
is invoked.preempt_schedule_irq()
callsschedule()
.schedule()
decides to context switch to process A and callscontext_switch()
.context_switch()
callsswitch_mm()
to switch the virtual memory.context_switch()
callsswitch_to()
to switch stacks. At this point, stack of process B looks like following:
...
[IRET return frame]
[ret_from_interrupt()]
[preempt_schedule_irq()]
[schedule()]
[context_switch()] (Stack top)
Now process A is running with its stack resumed. Since, context_switch() function in A was not invoked due to a timer interrupt, process A does not call IRET and it continues execution of mutex_lock(). This scenario may lead to blocking of timer interrupt forever.
What am I missing here?