CS452/652 Real-Time Programming Course Notes
Daniel M. Berry, Cheriton School of Computer Science University of Waterloo
2007 Daniel M. Berry Real-Time Programming: Trains
- Pg. 1
CS452/652 Real-Time Programming Course Notes Daniel M. Berry, - - PowerPoint PPT Presentation
CS452/652 Real-Time Programming Course Notes Daniel M. Berry, Cheriton School of Computer Science University of Waterloo 2007 Daniel M. Berry Real-Time Programming: Trains Pg. 1 Three Levels of Task Switching 1. High: Unbounded number
Daniel M. Berry, Cheriton School of Computer Science University of Waterloo
2007 Daniel M. Berry Real-Time Programming: Trains
CPU, and kernel routines
and kernel task
Unbounded number of processors: A system service is either g instantaneous, like an ordinary instruction, or g blocking, causing the executing processor to be blocked. Distinction between running and ready does not exist.
inst1
XXX1 code1
stack1 task1 1 rrr1
syscall n1 inst2
XXX2 code2
stack2 task2 2 rrr2
syscall n2
In the previous snapshot, both processors are running. Next two snapshots shows one processor blocked (asleep) and the other running.
inst1
XXX1 code1
stack1 task1 1 rrr1
syscall n1 inst2
XXX2 code2
stack2 task2 2 rrr2
syscall n2
ZZZZZ
inst1
XXX1 code1
stack1 task1 1 rrr1
syscall n1 inst2
XXX2’ code2
stack2 task2 2 rrr2’
syscall n2
ZZZZZ
Unbounded number of processes, one CPU, and kernel routines That is, a system service is done in a non-task kernel that is made up of procedures that can be called by the CPU.
Task switching is done as a side effect of making a syscall, which does both the requested service and switches to the task with the highest priority, usually leaving the calling task blocked or ready. It is possible that if the calling task were to be left ready, it might be chosen as the task to switch to, but
Note that any task that is not running is left blocked or ready in the middle of the syscall routine. So task switching is done by changing the stack and base pointers while keeping the instruction pointer pointing into the syscall routine.
returnValue in possibly leaving Handle syscall n, current stack; syscall(n)
Context Switching Code CPU & Registers 2
π
rrr2 ’s
returnValue2 n2 syscall n2
task2 code2 XXX2
inst2 current stack; Ready Running 170 130 95 75
stack2 stack1 AR syscall saved state
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt;
rrr1
Π
syscall n1
task1 code1 XXX1
inst1
current stack; syscall(n)
Context Switching Code CPU & Registers 2
π
rrr2 ’s
returnValue2 n2 syscall n2
task2 code2 XXX2
inst2
rrr1
Π
n1 syscall n1 Handle syscall n,
stack2 stack1 AR syscall AR syscall saved state
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt; current stack; returnValue in possibly leaving
task1 code1 XXX1
inst1
Context Switching Code CPU & Registers 2
π
1
π
rrr2 saved state ’s ’s
returnValue2 n2 syscall n2
task2 code2 XXX2
inst2
rrr0
Π
rrr1
returnValue1 syscall(n)
stack2 stack1 AR syscall AR syscall saved state
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt; current stack; returnValue in possibly leaving Handle syscall n, current stack; n1 syscall n1
task1 code1 XXX1
inst1
Why does the instruction say “Handle syscall n, possibly leaving returnValue in current stack;” instead
If the syscall is an instantaneous kind, then handling syscall n will definitely leave returnValue in current stack.
If, on the other hand, the syscall is a blocking kind, then handling syscall n results in arranging that some later execution of syscall will discover that the data requested in this syscall are ready, that its value should be deposited at the top of this stack, via a pointer associated with the expected value, and that this stack should be changed from blocked to ready.
The difficulty of keeping track of these pending completions of syscalls through multiple invocations
record, is the reason that it is nice to make the kernel a task that keeps its own data.
Context Switching Code CPU & Registers 2
π
1
π
rrr2 saved state ’s ’s
returnValue2 n2 syscall n2
task2 code2 XXX2
inst2
rrr0’
Π
rrr1
returnValue1 syscall(n)
stack2 stack1 AR syscall AR syscall saved state
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt; current stack; returnValue in possibly leaving Handle syscall n, current stack; n1 syscall n1
task1 code1 XXX1
inst1
Context Switching Code CPU & Registers 2
π
1
π
rrr2 saved state ’s ’s
returnValue2 n2 syscall n2
task2 code2 XXX2
inst2
rrr2
Π
rrr1
returnValue1 syscall(n)
stack2 stack1 AR syscall AR syscall saved state
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt; current stack; returnValue in possibly leaving Handle syscall n, current stack; n1 syscall n1
task1 code1 XXX1
inst1
syscall(n)
Context Switching Code CPU & Registers 1
π
saved state ’s
syscall n2
task2 code2 XXX2
inst2
rrr2
Π
rrr1
returnValue1 n1 current stack;
stack2 stack1 AR syscall
Π Π Restore ’s state Save ’s state into returnValue; Return with from current stack; to tnxt’s stack; Change current stack Find next task tnxt; current stack; returnValue in possibly leaving Handle syscall n, syscall n1
task1 code1 XXX1
inst1
Unbounded number of processes, one CPU, and kernel task That is, a system service is done in a kernel task.
I tried to decompose the context switching code into the three pieces suggested by the explanation given of the diagram:
Context Switch Task Kernel
exitKernel (iretl) return return syscall (int n)
for the transition from task1 to the kernel and from the kernel to task2, but it did not quite work.
Note that what I show is only one possible decomposition of the behavior. Others will work, in particular e.g., making only one procedure instead of three.
First, a view of the context switching and the kernel code.
Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
kernel’s stack; Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, to kernel’s stack Change current stack current stack; Save ’s state into [sc]: exitKernel int syscalll(n) . . . exitKernel; ptr points; storing it where returnValue and possibly getting
κ’s
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . Running Ready
saved state
returnValue2
’s rrr2
π2
saved state syscall AR stack1 stack2 rrrK exitKernel AR
instKI
XXXk kernelTask kernelStack
syscalll(n) Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
Π int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π n2 inst1
XXX1 code1 task1
syscall n1
Π
rrr1 CPU & Registers
inst2
XXX2 code2 task2
syscall n2
XXXk kernelTask kernelStack saved state
κ’s
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; instKI
XXX2 code2 task2
syscall n2 n2 returnValue2
’s rrr2
π2
saved state syscall AR stack1 stack2 rrrK exitKernel AR
. . . Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
Π syscalll(n) int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π inst2 inst1
XXX1 code1 task1
syscall n1 n1
Π
rrr1 CPU & Registers syscall AR
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrr1 CPU & Registers syscall AR
inst2
XXX2 code2 task2
syscall n2
kernelTask kernelStack saved state
κ’s
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1
XXXk
n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2 rrrK exitKernel AR
instKI Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state to tnxt’s stack; syscalll(n) int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack from current stack; Return; . . . . . .
Context Switching Code
AR
instKI
XXXk kernelTask kernelStack saved state
κ’s
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points;
exitKernel code2 task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2 rrrk
exitKernel; Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
n1 n1 Π . . . syscalll(n) int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π
XXX2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrr1 CPU & Registers syscall AR
inst2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk CPU & Registers syscall AR
inst2
XXX2 code2 task2
syscall n2
kernelTask kernelStack saved state
κ’s
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 n1
XXXk
n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2 rrrk exitKernel AR
instKI Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; to tnxt’s stack; syscalll(n) int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack Return; . . . . . .
Context Switching Code
XXXk kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 n1 instKI
task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
syscalll(n) Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
Π int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π
code2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk CPU & Registers syscall AR
inst2
XXX2
XXXk’ kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) instKI
task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
int to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1 Save n & ptr, pointer exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π
code2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk’ CPU & Registers syscall AR
inst2
XXX2
instKI
XXXk’ kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n)
stack2 XXX2 code2 task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1
int int [sc]; Return; to top of current Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR
to returnValue slot; exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer inst2 inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk’’ CPU & Registers syscall AR
kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) int exitKernel
XXXk’ code2 task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
instKI [sc]: Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR rrrk’’ saved state
κ’s
to top of current Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return;
XXX2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk’’ CPU & Registers syscall AR
inst2
kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) int exitKernel
XXXk’ code2 task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
instKI [sc]: Copy n & ptr from top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR rrrk’’ saved state
κ’s
to top of current Save ’s state into current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return;
XXX2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
rrrk’’’ CPU & Registers syscall AR
inst2
kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) int exitKernel [sc]:
kernelTask task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
instKI
XXXk’
Save ’s state into top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR rrrk’’ saved state
κ’s
rrr2
Copy n & ptr from current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current
code2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
CPU & Registers syscall AR
inst2
XXX2
kernelStack
Jump;
kernelCode
. . . Get value to return as n & ptr; Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) int exitKernel [sc]:
kernelTask task2
syscall n2 n2 returnValue2
’s ’s saved state rrr2
π1 π2
saved state syscall AR stack1 stack2
instKI
XXXk’
Save ’s state into top of current AR stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR rrrk’’ saved state
κ’s
rrr2’
Copy n & ptr from current stack; Change current stack to kernel’s stack kernel’s stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current
code2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
CPU & Registers syscall AR
inst2
XXX2
Handle syscall n, possibly getting returnValue and storing it where ptr points; exitKernel; . . . n1 syscalll(n) int exitKernel [sc]: Save ’s state into current stack; Change current stack to kernel’s stack as n & ptr;
code2 task2
syscall n2
’s saved state
π1
stack1 stack2
instKI
XXXk’ kernelTask kernelStack
Jump;
kernelCode
. . . Get value to return kernel’s stack; Jump; Π Restore ’s state from current stack; Return; . . . . . .
Context Switching Code
returnValue1
exitKernel AR rrrk’’ saved state
κ’s
rrr2’
stack; Find next task tnxt; Change current stack to tnxt’s stack; Restore ’s state from current stack; iretl; Π Save ’s state into Π Π Save n & ptr, pointer to returnValue slot; int [sc]; Return; to top of current Copy n & ptr from top of current AR
XXX2
inst1
XXX1 code1 task1
syscall n1 n1
rrr1
Π
CPU & Registers syscall AR
inst2