Lab 2
Part 2
1
Admin
2
Admin
3
Monitors
4
What’s a monitor?
Why do we use monitors?
5
What the heck is a monitor?
Why do we use monitors?
6
Monitors in xk
7
No Condition Variables in xk
The starter code does not provide the object-oriented std::condition_variable API you can find in C++: LINK
Instead it provides the sleep and wakeup helper functions (which together can implement the monitor pattern)
8
Sleep
9
Wakeup
10
Monitors in xk
wait(), exit()
pipe()
11
Lab 2 - Pipe
12
What is a Pipe?
A pipe is essentially a queue of bytes with two ends:
When you type ‘ls | wc’ into the shell, you are using a pipe!!!
13
pipe(fds)
14
An Example to Illustrate Pipes
Now let’s go through a demonstration of what happens as a sample user uses the pipe API (in the context of multiprocessing)!
15
Pipe usage
16
Process 1’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
Pipe usage
17
Process 1’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
read end
write end
18
Process 1’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
read end
write end
File Struct
(Read only)
File Struct
(Write only)
Pipe
What will the newly allocated pipe fds point to?
Pipe usage
19
Process 1’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
read end
Process 2’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
write end
read end
write end
pipe in user’s shell
20
Pipe usage
21
Process 1’s File Descriptor Array
0
1
2
3
PROC_MAX_FILE
struct proc
Process 2’s File Descriptor Array
0
1
2
3
struct proc
PROC_MAX_FILE
Abstraction of a pipe
write end
read end
pipe FAQs
22
struct pipe* p = kalloc();
p->buffer = ???
should be right past the struct, and what would that be?
23
a page of memory (4096 bytes)
struct pipe {
metadata…
char* buffer;
}
actual buffer
pipe FAQs
24
Interaction with File API
Pipes are accessed through file descriptors.
This means you need to think through how the lab 1 syscalls will work when called on pipe file descriptors:
25
What should pipe contain?
26
What should pipe contain?
27
28
And that’s pipe!
… But wait! There’s more! (that you have to do in lab 2 part 2)
But wait! …. There’s more! (in lab 2 part 2)
In lab 2 part 2 you are also implementing exec
29
Lab 2 - exec
30
Motivation
Why do we have exec?
31
exec(program, args)
32
exec(path, argv) arguments validation
33
string0
0
string5
string4
string3
string2
string1
must be validated for an 8 byte pointer before we can access argv[0] and validate string0
argv / &argv[0]
exec(path, argv) arguments validation
34
must be validated for an 8 byte pointer before we can access argv[1] and validate string1
&argv[1]
string0
0
string5
string4
string3
string2
string1
exec(path, argv) arguments validation
35
must be validated for an 8 byte pointer before we can access argv[2] and validate string2
&argv[2]
repeat this process until
string0
0
string5
string4
string3
string2
string1
exec(program, args)
36
How are the args set up in exec?
37
Another look at main()
exec sets up the function arguments for main!
int main(int argc, char** argv)
38
Setting up the Stack
39
Quick Review: X86_64 Calling Conventions
From 351:
40
Quick Review: X86_64 Calling Conventions
From 351:
41
Stack For User Process
42
argc
%RDI
argv
%RSI
*
%RSP
Return PC
argv[0]
argv[1]
[ … ]
argv[argc - 1]
argv[argc] = NULL
Arg #0 string
Arg #1 string
[ … ]
Arg #(argc-1)string
// High addresses
// Stack grows
// down
SZ_2G
\0… (padding)
Let’s Practice!
43
Practice Exercise 1
44
%RDI
%RSI
%RSP
// High addresses
Now it’s your turn!
Draw stack layout and determine register values for exec() called with:
“cat cat.txt”
Stack grows down
Practice Exercise 1: “cat cat.txt” Solution
45
%RDI
%RSI
%RSP
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
46
%RDI
%RSI
%RSP
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
47
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
48
2
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
49
\0\0\0\0
2
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
50
\0\0\0\0
NULL (argv[2])
2
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
51
addr of "cat.txt" (argv[1])
\0\0\0\0
NULL (argv[2])
2
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
52
addr of "cat" (argv[0])
addr of "cat.txt" (argv[1])
\0\0\0\0
NULL (argv[2])
2
%RDI
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
53
addr of "cat" (argv[0])
addr of "cat.txt" (argv[1])
\0\0\0\0
NULL (argv[2])
2
%RDI
argv
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
54
Return PC
addr of "cat" (argv[0])
addr of "cat.txt" (argv[1])
\0\0\0\0
NULL (argv[2])
2
%RDI
argv
%RSI
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
stackptr
Practice Exercise 1: “cat cat.txt” Solution
55
Return PC
addr of "cat" (argv[0])
addr of "cat.txt" (argv[1])
\0\0\0\0
NULL (argv[2])
2
%RDI
argv
%RSI
stackptr
%RSP
“cat”
“cat.txt”
// High addresses
// Stack grows
// down
Practice Exercise 2
56
%RDI
%RSI
%RSP
// High addresses
Now it’s your turn!
Draw stack layout and determine register values for exec() called with:
“kill -9 500”
Stack grows down
Practice Exercise 2: “kill -9 500” Solution
57
3
%RDI
argv
%RSI
*
%RSP
Return PC
argv[0]
argv[1]
argv[2]
argv[3] = NULL
“kill”
“-9”
“500”
// High addresses
// Stack grows
// down
\0\0\0\0