------------------------------ MODULE sched2 --------------------------------
EXTENDS Naturals, Sequences, FiniteSets, TLC
CONSTANTS CPU,
THREADS
(* --algorithm sched {
variables
current = "idle";
in_interrupt = FALSE;
interrupts_on = FALSE;
worked = [t \in THREADS |-> FALSE];
thread_pc = [t \in THREADS |-> "start_thread"];
thread_stack = [t \in THREADS |-> << >>];
\* concurrency test
count = 0;
define {
\* Handle interrupt. Save current thread context and invoke handler
HandleInt(self) == /\ interrupts_on \* only when interrupts are enabled
/\ interrupts_on' = FALSE \* turn interrupts off
/\ in_interrupt' = TRUE
/\ thread_pc' = [thread_pc EXCEPT ![current] = pc[self]]
/\ thread_stack' = [thread_stack EXCEPT ![current] = stack[self]]
/\ pc' = [pc EXCEPT ![self] = "interrupt_handler"]
/\ UNCHANGED <<current, worked, stack, count>>
\* Return from interrupt. Restore current thread context
ReturnInt(self) == /\ pc[self] = "ret_from_interrupt"
/\ pc' = [pc EXCEPT ![self] = thread_pc[current]]
/\ stack' = [stack EXCEPT ![self] = thread_stack[current]]
/\ in_interrupt' = FALSE
/\ interrupts_on' = TRUE \* re-enable interrupts
/\ UNCHANGED <<current, worked, thread_pc, thread_stack, count>>
Interrupt(self) == HandleInt(self) \/ ReturnInt(self)
TypeInv == /\ current \in THREADS \cup {"idle"}
/\ worked \in [THREADS -> BOOLEAN]
SchedInv == count < Cardinality(THREADS)
AllWorked == <>(\A t \in THREADS : worked[t])
}
procedure interrupt()
{
interrupt_handler:
\* re-schedule
with (t \in THREADS)
current := t;
ret_from_interrupt:
\* Never pass this point
await FALSE;
}
procedure thread()
{
start_thread:
interrupts_on := TRUE;
main_loop:
while (TRUE) {
assert ~in_interrupt;
worked[current] := TRUE;
\* Concurrency test (should not trigger if ~interrupts_on)
interrupts_on := FALSE;
count := count + 1;
maybe_preempt:
count := count - 1;
interrupts_on := TRUE;
}
}
process (Processor = CPU)
{
start_cpu:
with (t \in THREADS) {
current := t;
call thread();
};
}
} *)
\* BEGIN TRANSLATION
\* removed
\* END TRANSLATION
PreemptNext == Interrupt(CPU) \/ Next
PreemptSpec == Init /\ [][PreemptNext]_vars
==============================================================================