Kernel code interrupted by Timer
Frederic Weisbecker
fweisbec at gmail.com
Sat Feb 9 11:40:02 EST 2013
2013/2/9 anish kumar <anish198519851985 at gmail.com>:
> Thanks Frederic.
> On Sat, 2013-02-09 at 08:44 +0100, Frederic Weisbecker wrote:
>> In the case you have CONFIG_PREEMPT and it's the turn for some other
>> task to be scheduled, the function preempt_schedule_irq() is called
>> right before the irq return to the interrupted code. If the irq
>> interrupted preemptible code (code that was not under a
>> preempt_disable() section) then the scheduler may well schedule
>> another task.
> However if the code is under preempt_disable() when irq happened then it
> won't choose any other task and will come back immediately to the task
> which was preempted by the irq handler.
Right.
> I think what you are referring is below code:
>
> __irq_svc:
> svc_entry
> irq_handler
>
> #ifdef CONFIG_PREEMPT
> get_thread_info tsk
> ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
> ldr r0, [tsk, #TI_FLAGS] @ get flags
> teq r8, #0 @ if preempt count != 0
> movne r0, #0 @ force flags to 0
> tst r0, #_TIF_NEED_RESCHED
> blne svc_preempt
> #endif
>
> #ifdef CONFIG_PREEMPT
> svc_preempt:
> mov r8, lr
> 1: bl preempt_schedule_irq @ irq en/disable is done
> inside
> ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
> tst r0, #_TIF_NEED_RESCHED
> moveq pc, r8 @ go again
> b 1b
> #endif
>
>
> /*
> * this is the entry point to schedule() from kernel preemption
> * off of irq context.
> * Note, that this is called and return with irqs disabled. This will
> * protect us against recursive calling from irq.
> */
> asmlinkage void __sched preempt_schedule_irq(void)
> {
> struct thread_info *ti = current_thread_info();
>
> /* Catch callers which need to be fixed */
> BUG_ON(ti->preempt_count || !irqs_disabled());
>
> user_exit();
> do {
> add_preempt_count(PREEMPT_ACTIVE);
> local_irq_enable();
> __schedule();
> local_irq_disable();
> sub_preempt_count(PREEMPT_ACTIVE);
>
> /*
> * Check again in case we missed a preemption
> opportunity
> * between schedule and now.
> */
> barrier();
> } while (need_resched());
> }
>
>>
>> It may indeed sound suprising that we schedule from an interrupt but
> It is really *surprising* that we do scheduling from interrupt context.
> Doesn't Do's and Don't of scheduling from interrupt context apply here?
Yeah we typically don't want to be able to schedule from an interrupt
for a lot of reasons: the issuing device need to be informed quickly
that we are servicing the irq, sometimes the irq runs code that need
to be fast, the irq code assumes that it can't be itself interrupted
or preempted, etc... So for simplicity, it's simply not allowed.
But it doesn't apply here because the interrupt has been serviced and
we are about to resume to the interrupted code. From the logical
kernel point of view we have exited the irq (we have called
irq_exit()). So we can just re-enable the interrupts and schedule
another task. When we'll later schedule back the previous task that
called preempt_schedule_irq(), it will simply exit the irq and resume
to the interrupted code.
>> it's actually fine. Later on, the scheduler restores the previous task
>> to the middle of preempt_schedule_irq() and the irq completes its
> Sorry didn't understand this sentence i.e. "scheduler restores the
> previous task to the middle of preempt_schedule_irq()".
Yeah when we schedule another task we do a context switch. When the
previous task is rescheduled later it will resume from that context
switch point. Which is in the middle of schedule(), in the switch_to()
function.
More information about the Kernelnewbies
mailing list