Commit 4d0b85ea authored by Robert Love's avatar Robert Love Committed by Dave Kleikamp

[PATCH] kernel preemption bits (2/2)

In both preempt_schedule in sched.c and resume_kernel in entry.S, it is
possible to return with need_resched set and thus a pending preemption
but not service that preemption for some time.

Consider:

	- return from schedule() to preempt_schedule
	- interrupt occurs, sets need_resched
	- we cannot preempt since preempt_count = PREEMPT_ACTIVE
	- back in preempt_schedule, set preempt_count = 0

Now we again can preempt, but we will not.  Instead we return and
continue executing.  On the next interrupt, we will redo the whole
fiasco which is a waste since we could of reentered schedule while we
were there.  Worse, if we acquire a lock before the next interrupt we
can potentially delay the pending reschedule a very long time.  This is
not acceptable.

The solution is to check for and loop on need_resched on resume_kernel
and preempt_schedule like schedule itself does.
parent d257b778
...@@ -211,6 +211,7 @@ ENTRY(resume_userspace) ...@@ -211,6 +211,7 @@ ENTRY(resume_userspace)
ENTRY(resume_kernel) ENTRY(resume_kernel)
cmpl $0,TI_PRE_COUNT(%ebx) # non-zero preempt_count ? cmpl $0,TI_PRE_COUNT(%ebx) # non-zero preempt_count ?
jnz restore_all jnz restore_all
need_resched:
movl TI_FLAGS(%ebx), %ecx # need_resched set ? movl TI_FLAGS(%ebx), %ecx # need_resched set ?
testb $_TIF_NEED_RESCHED, %cl testb $_TIF_NEED_RESCHED, %cl
jz restore_all jz restore_all
...@@ -220,7 +221,8 @@ ENTRY(resume_kernel) ...@@ -220,7 +221,8 @@ ENTRY(resume_kernel)
sti sti
call schedule call schedule
movl $0,TI_PRE_COUNT(%ebx) movl $0,TI_PRE_COUNT(%ebx)
jmp restore_all cli
jmp need_resched
#endif #endif
# system call handler stub # system call handler stub
......
...@@ -893,9 +893,15 @@ asmlinkage void preempt_schedule(void) ...@@ -893,9 +893,15 @@ asmlinkage void preempt_schedule(void)
if (unlikely(ti->preempt_count)) if (unlikely(ti->preempt_count))
return; return;
need_resched:
ti->preempt_count = PREEMPT_ACTIVE; ti->preempt_count = PREEMPT_ACTIVE;
schedule(); schedule();
ti->preempt_count = 0; ti->preempt_count = 0;
/* we can miss a preemption opportunity between schedule and now */
barrier();
if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
goto need_resched;
} }
#endif /* CONFIG_PREEMPT */ #endif /* CONFIG_PREEMPT */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment