Professional Documents
Culture Documents
Jeff Chase
Duke University
mem.c (OSTEP) data data
int
main(int argc, char *argv[]) pid: 5587 pid: 5588
{
int *p;
chase$ cc -o mem mem.c
p = malloc(sizeof(int));
chase$ ./mem 21 &
*p = atoi(argv[1]);
chase$ ./mem 42 &
while (1) {
(pid:5587) value of p: 22
Spin(1);
(pid:5587) value of p: 23
*p = *p + 1;
(pid:5587) value of p: 24
printf("(pid:%d) value of p: %d\n”,
(pid:5588) value of p: 43
getpid(), *p);
(pid:5588) value of p: 44
}
(pid:5587) value of p: 25
}
(pid:5587) value of p: 26
…
0x7fffffff 0x7fffffff
Reserved Reserved
Stack Stack
Text Text
(code) (code)
0x0 0x0
Operating Systems: The Classical View
The kernel code and data are protected from untrusted processes.
Processes: A Closer Look
virtual address space thread process descriptor (PCB)
user ID
process ID
+ stack
+ parent PID
sibling links
children resources
Threads
Program
Address space
Running a program is like performing a play.
[lpcox]
The sheep analogy
Address space
Thread
Code
and
data
CPU cores
+ stack
+…
Each process has a Each process has a thread
virtual address space From now on, we suppose
bound to the VAS, with
(VAS): a private name that a process could have
stacks (user and kernel).
space for the virtual multiple threads.
memory it uses. If we say a process does
We presume that they can
something, we really mean
The VAS is both a all make system calls and
its thread does it.
“sandbox” and a block independently.
“lockbox”: it limits what The kernel can
the process can suspend/restart the thread STOP
wait
see/do, and protects wherever and whenever it
its data from others. wants.
A thread running in a process VAS
0
CPU common runtime
x
your program
code library
address space
(virtual or physical)
your data
R0
e.g., a virtual memory
heap for a process
Rn
PC x
SP y
registers
y
stack
high
“memory”
Thread context
• Each thread has a context (exactly one).
CPU core
– Context == the thread’s register values.
– Including a (protected) identifier naming its VAS.
– And a pointer to thread’s stack in VAS/memory.
• Each core has a context (at least one).
R0
– Context == a register set that can hold values.
– The register set is baked into the hardware. Rn
setcontext(&context);
}
Messing with the context (2)
#include <ucontext.h>
int count = 0;
ucontext_t context; Save core context to memory
int main()
{ Loading the saved context
int i = 0; transfers control to this block
getcontext(&context); of code. (Why?)
%rip and %rbp are set “right”, then these references “work”.
Messing with the context (4)
#include <ucontext.h>
CPU Rn
(core) x
y
PC
SP y stack
registers
stack
high
Thread context switch
switch switch
out in address space
0
common runtime
x
program
code library
R0
data
1
Page links and
2 Each tab has its own stack.
back button
navigate a One tab is active at any given time.
“stack” of pages You create/destroy tabs as needed.
in each tab. You switch between tabs at your whim.
int count = 0;
ucontext_t context;
int main()
{
int i = 0;
getcontext(&context);
count += 1; What does this do?
i += 1;
sleep(1);
printf(”…", count, i);
setcontext(&context);
}
Thread/process states and
transitions
Scheduler governs
sleep these transitions.
“waiting for
someplace dispatch
to go” wakeup
blocked ready “requesting a car”
The handler accesses the core register context to read the details of
the exception (trap, fault, or interrupt). It may call other kernel routines.
CPU mode: User and Kernel
CPU mode (a field in some status register) indicates CPU core
whether a machine CPU (core) is running in a user
program or in the protected kernel (protected mode).
The syscall handler makes an indirect call through the system call
dispatch table to the handler registered for the specific system call.
“Classic Linux Address Space”
http://duartes.org/gustavo/blog/category/linux
Note: Something Wild
• The “Something Wild” example that follows was an
earlier version of “Messing with the context”.
• It was not discussed in class.
• “Messing with the context” simplifies the example, but
keeps all the essential info.
• “Something Wild” brings it just a little closer to coroutines
a context switch from one thread to another.
Something wild (1)
#include <ucontext.h>
time
Int count = 0;
int set = 0;
ucontext_t contexts[2];
void proc()
{ int
int i = 0; main() {
getcontext(&contexts[count]); set=0;
printf(”…", count, i); proc();
count += 1; proc();
i += 1; …
} }
Something wild (3)
void proc() {
int i = 0; int
printf(”…", count, i); main() {
count += 1; …
i += 1; set=1;
sleep(1); proc();
setcontext(&contexts[count&0x1]); }
}
Something wild (4)
We have a pair of
time
register contexts that
were saved at this
void proc() { point in the code. If we load either of the
int i = 0; saved contexts, it will
printf(”…", count, i); transfer control to this
count += 1; block of code. (Why?)
i += 1; What about the stack?
sleep(1);
setcontext(…); Switch to the other
saved register context.
} Alternate “even” and
“odd” contexts.
What will it print? The count is a
global variable…but what about i? Lather, rinse, repeat.
Something wild (5)
time
void proc() {
int i = 0;
printf("%4d %4d\n", count, i);
count += 1;
i += 1;
sleep(1); What does this do?
setcontext(…);
}