arc: fix race condition when returning from interrupt

A race condition would happend if a FIRQ interrupted a
return-from-interrupt from a RIRQ at the wrong moment: if a decision was
already taken which thread to context switch in and the FIRQ woke up
another thread of higher priority, the ready queue would be corrupted.

The solution is to lock interrupts at the moment the interrupt return
code starts looking at the kernel queues. Interrupts do not need to be
unlocked before exiting: the return-from-interrupt (rtie) instruction
will restore the correct interrupt locking state for the thread being
context switched in.

Change-Id: I777665c2faeca7b1f2a77ddd9ee2a520080bae88
Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
This commit is contained in:
Benjamin Walsh 2016-11-07 15:49:23 -05:00 committed by Andrew Boie
commit 5986ec040b

View file

@ -100,6 +100,13 @@ SECTION_FUNC(TEXT, _rirq_exit)
mov r1, _nanokernel mov r1, _nanokernel
ld_s r2, [r1, __tNANO_current_OFFSET] ld_s r2, [r1, __tNANO_current_OFFSET]
/*
* Lock interrupts to ensure kernel queues do not change from this
* point on until return from interrupt.
*/
clri
#if NUM_REGULAR_IRQ_PRIO_LEVELS > 1 #if NUM_REGULAR_IRQ_PRIO_LEVELS > 1
/* check if we're a nested interrupt: if so, let the interrupted interrupt /* check if we're a nested interrupt: if so, let the interrupted interrupt
* handle the reschedule */ * handle the reschedule */
@ -140,9 +147,9 @@ SECTION_FUNC(TEXT, _rirq_exit)
brgt.d r0, 0, _rirq_no_reschedule brgt.d r0, 0, _rirq_no_reschedule
ld sp, [r2, __tTCS_preempReg_OFFSET + __tPreempt_sp_OFFSET] ld sp, [r2, __tTCS_preempReg_OFFSET + __tPreempt_sp_OFFSET]
/* check if the current thread needs to be rescheduled */
push_s r2 push_s r2
push_s r1 push_s r1
/* check if the current thread needs to be rescheduled */
push_s blink push_s blink
jl _is_next_thread_current jl _is_next_thread_current
pop_s blink pop_s blink
@ -171,7 +178,7 @@ _rirq_reschedule:
st _CAUSE_RIRQ, [r2, __tTCS_relinquish_cause_OFFSET] st _CAUSE_RIRQ, [r2, __tTCS_relinquish_cause_OFFSET]
/* incoming fiber is in r0: it becomes the new 'current' */ /* incoming thread is in r0: it becomes the new 'current' */
mov r2, r0 mov r2, r0
st_s r2, [r1, __tNANO_current_OFFSET] st_s r2, [r1, __tNANO_current_OFFSET]