aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2005-12-21 12:26:25 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-22 12:17:39 -0500
commitd6f029130fb83b36fb709a187275b0494035d689 (patch)
tree27a5f8fb9fe1fc0df911231b5d9913b246427039 /include/linux
parentd5ea4e26602fa7f5141872f2c17a862f1974a73f (diff)
[PATCH] fix race with preempt_enable()
Currently a simple void foo(void) { preempt_enable(); } produces the following code on ARM: foo: bic r3, sp, #8128 bic r3, r3, #63 ldr r2, [r3, #4] ldr r1, [r3, #0] sub r2, r2, #1 tst r1, #4 str r2, [r3, #4] blne preempt_schedule mov pc, lr The problem is that the TIF_NEED_RESCHED flag is loaded _before_ the preemption count is stored back, hence any interrupt coming within that 3 instruction window causing TIF_NEED_RESCHED to be set won't be seen and scheduling won't happen as it should. Nothing currently prevents gcc from performing that reordering. There is already a barrier() before the decrement of the preemption count, but another one is needed between this and the TIF_NEED_RESCHED flag test for proper code ordering. Signed-off-by: Nicolas Pitre <nico@cam.org> Acked-by: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/preempt.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index d9a2f5254a51..5769d14d1e6a 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -48,6 +48,7 @@ do { \
48#define preempt_enable() \ 48#define preempt_enable() \
49do { \ 49do { \
50 preempt_enable_no_resched(); \ 50 preempt_enable_no_resched(); \
51 barrier(); \
51 preempt_check_resched(); \ 52 preempt_check_resched(); \
52} while (0) 53} while (0)
53 54