CS 110 Summer 2018 Midterm Review Session Matthew Katzman Thanks - - PowerPoint PPT Presentation

cs 110 summer 2018 midterm review session
SMART_READER_LITE
LIVE PREVIEW

CS 110 Summer 2018 Midterm Review Session Matthew Katzman Thanks - - PowerPoint PPT Presentation

CS 110 Summer 2018 Midterm Review Session Matthew Katzman Thanks to Ryan Eberhardt Kristine Guo Grace Hong Hemanth Kini for some slide materials. Exam Time Monday, July 23 7PM-9PM Hewlett 201 Study Resources Be sure to look over:


slide-1
SLIDE 1

CS 110 Summer 2018 Midterm Review Session

Matthew Katzman Thanks to Ryan Eberhardt Kristine Guo Grace Hong Hemanth Kini for some slide materials.

slide-2
SLIDE 2

Exam Time

Monday, July 23 7PM-9PM Hewlett 201

slide-3
SLIDE 3

Study Resources

Be sure to look over:

  • Assignments and Class Notes
  • Labs and Handouts
  • Practice Midterms
slide-4
SLIDE 4

FILESYSTEMS

See assign1

slide-5
SLIDE 5

The Important Types

  • The Inode
  • The File
  • The Directory
  • The Link
slide-6
SLIDE 6

The Inode/FIle Layers

slide-7
SLIDE 7

Directories

  • A DIRECTORY IS A FILE
  • Stores some important

information, but mostly made up of dirEnt’s (directory entries)

  • Each of these consists of a

filename and an inumber.

slide-8
SLIDE 8

Links (two types)

HARD LINKS:

  • The SAME as directory entries
  • Map a filename to an inumber
  • Increase the file’s reference count

SYMBOLIC (soft) LINKS:

  • Different type of file
  • File contents include path to file
  • Does not increase reference count
slide-9
SLIDE 9

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

slide-10
SLIDE 10

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (/) 1 . 1 .. 2 MCU 3 wormhole 2 Refcnt: 4 Inode Block DIRECTORY (/MCU)

slide-11
SLIDE 11

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (MCU) 2 . 1 .. 4 space 5 quinjet 4 Refcnt: 4 Inode Block DIRECTORY (/MCU/space)

slide-12
SLIDE 12

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (space) 4 . 2 .. 6 Sakaar 7 Asgard 6 Refcnt: 3 Inode Block DIRECTORY (/MCU/space/ Sakaar)

slide-13
SLIDE 13

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (Sakaar) 6 . 4 .. 8 arena 9 monster.smash 8 Refcnt: 3 Inode Block DIRECTORY (/MCU/space/ Sakaar/arena)

slide-14
SLIDE 14

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (arena) 5 . 2 .. 9 Hulk.smash 10 Waititi 9 Refcnt: 2 Inode Block

“HULK...SMASH!”

slide-15
SLIDE 15

Where’s Hulk?

Hulk is located at /MCU/space/Sakaar/arena/Hulk.smash. How can we find him?

DIRECTORY (/) 1 . 1 .. 2 MCU 3 wormhole 3 Refcnt: 1 Inode Block “/MCU/space/ Sakaar”

slide-16
SLIDE 16

The Filesystem Tables (stored in Kernel Space)

a.txt b.txt c.txt d.txt Vnode table

slide-17
SLIDE 17

The Filesystem Tables

refcnt = 1 type = FILE inumber = 17 refcnt = 2 type = FILE inumber = 32 refcnt = 1 type = FILE inumber = 5 Vnode table status = r, refcnt = ? cursor = 10 status = r, refcnt = ? cursor = 0 status = w, refcnt = ? cursor = 50 status = w, refcnt = ? cursor = 15 File entry table

slide-18
SLIDE 18

The Filesystem Tables

refcnt = 1 type = FILE inumber = 17 refcnt = 2 type = FILE inumber = 32 refcnt = 1 type = FILE inumber = 5 Vnode table status = r, refcnt = 2 cursor = 10 status = r, refcnt = 1 cursor = 0 status = w, refcnt = 1 cursor = 50 status = w, refcnt = 1 cursor = 15 File entry table File descriptor table 1 2 3 4 5 6 7

STDIN STDOUT STDERR

slide-19
SLIDE 19

The Filesystem Tables

refcnt = 1 type = FILE inumber = 17 refcnt = 2 type = FILE inumber = 32 refcnt = 1 type = FILE inumber = 5 Vnode table status = r, refcnt = 2 cursor = 10 status = r, refcnt = 1 cursor = 0 status = w, refcnt = 1 cursor = 50 status = w, refcnt = 0 cursor = 15 File entry table File descriptor table 1 2 3 4 5 6 7

STDIN STDOUT STDERR

slide-20
SLIDE 20

The Filesystem Tables

refcnt = 1 type = FILE inumber = 17 refcnt = 2 type = FILE inumber = 32 refcnt = 0 type = FILE inumber = 5 Vnode table status = r, refcnt = 2 cursor = 10 status = r, refcnt = 1 cursor = 0 status = w, refcnt = 1 cursor = 50 File entry table File descriptor table 1 2 3 4 5 6 7

STDIN STDOUT STDERR

slide-21
SLIDE 21

The Filesystem Tables

refcnt = 1 type = FILE inumber = 17 refcnt = 2 type = FILE inumber = 32 Vnode table status = r, refcnt = 2 cursor = 10 status = r, refcnt = 1 cursor = 0 status = w, refcnt = 1 cursor = 50 File entry table File descriptor table 1 2 3 4 5 6 7

STDIN STDOUT STDERR

slide-22
SLIDE 22

MULTIPROCESSING

See assign2, assign3

slide-23
SLIDE 23

System Calls

Interact with the raw blocks that users do not (and should not) have access to (privileged operations)

  • Syscalls you should know:

  • pen()

○ read() ○ write() ○ close() ○ pipe() ○ dup2() ○ fork() ○ execvp() ○ kill() ○ waitpid() ○ kill() ○ signal() ○ sigprocmask() ○ sigsuspend()

slide-24
SLIDE 24

pipe(int[] fds)

STDIN STDOUT STDERR

slide-25
SLIDE 25

pipe(int[] fds)

STDIN STDOUT STDERR status = r, refcnt = 1, cursor = 0 status = w, refcnt = 1, cursor = 0 refcnt = 1, type = PIPE refcnt = 1, type = PIPE

slide-26
SLIDE 26

fork()

STDIN STDOUT STDERR status = r, refcnt = 1, cursor = 0 status = w, refcnt = 1, cursor = 0 refcnt = 1, type = PIPE refcnt = 1, type = PIPE

slide-27
SLIDE 27

fork()

STDIN STDOUT STDERR status = r, refcnt = 2, cursor = 0 status = w, refcnt = 2, cursor = 0 refcnt = 1, type = PIPE refcnt = 1, type = PIPE STDIN STDOUT STDERR

slide-28
SLIDE 28

dup2(int oldfd, int newfd)

STDIN STDOUT STDERR status = r, refcnt = 2, cursor = 0 status = w, refcnt = 2, cursor = 0 refcnt = 1, type = PIPE refcnt = 1, type = PIPE STDIN STDOUT STDERR Calling dup2(3, STDIN_FILENO) in child:

slide-29
SLIDE 29

dup2(int oldfd, int newfd)

STDIN STDOUT STDERR status = r, refcnt = 3, cursor = 0 status = w, refcnt = 2, cursor = 0 refcnt = 1, type = PIPE refcnt = 1, type = PIPE STDIN STDOUT STDERR Calling dup2(3, STDIN_FILENO) in child:

slide-30
SLIDE 30

What will print here?

void createUltron() { pid_t pid = fork(); if (pid == 0) { printf(“Ultron is here.”); } printf(“Jarvis is here.”); } int main(int argc, char* argv[]) { createUltron(); while(true) { pid_t pid = waitpid(-1, NULL, 0); if (pid == -1) break; } assert(errno == ECHILD); printf(“The world is safe.”); }

slide-31
SLIDE 31

What will print here?

void createUltron() { pid_t pid = fork(); if (pid == 0) { printf(“Ultron is here.”); return; } printf(“Jarvis is here.”); } int main(int argc, char* argv[]) { createUltron(); while(true) { pid_t pid = waitpid(-1, NULL, 0); if (pid == -1) break; } assert(errno == ECHILD); printf(“The world is safe.”); }

slide-32
SLIDE 32

What will print here?

void createUltron() { pid_t pid = fork(); if (pid == 0) { printf(“Ultron is here.”); exit(0); } printf(“Jarvis is here.”); } int main(int argc, char* argv[]) { createUltron(); while(true) { pid_t pid = waitpid(-1, NULL, 0); if (pid == -1) break; } assert(errno == ECHILD); printf(“The world is safe.”); }

slide-33
SLIDE 33

waitpid()

First argument (pid_t pid):

  • <-1 (any child with pgid = |pid|
  • 1 (any child)
  • 0 (any child with pgid = getpgid())
  • >0 the child with pid = pid.

Third argument (int options)

  • 0 (returns only after child terminates)
  • WUNTRACED (also after child stops)
  • WNOHANG (returns immediately)
  • WCONTINUED (also after child continues)

Second argument (int* status):

  • Create int status and pass in

&status

○ WIFEXITED(status) ○ WIFSTOPPED(status) ○ WIFCONTINUED(status)

slide-34
SLIDE 34

Signals

The ones you should know:

  • SIGINT (ctrl + C)
  • SIGTSTP (ctrl + Z)

The two above can be caught and handled. The two below cannot:

  • SIGKILL
  • SIGSTOP

These have the same respective behavior, but cannot be caught.

  • SIGCHLD
  • SIGCONT

Wrong universe, but it worked too well...

slide-35
SLIDE 35

sigsuspend(const sigset_t* mask)

Does the following ATOMICALLY:

  • sigprocmask(SIG_SETMASK, &mask, &old);
  • sleep(); // wait for signal to wake us up
  • sigprocmask(SIG_SETMASK, &old, NULL);
slide-36
SLIDE 36

What will print?

int counter = 0; static void reapChild(int sig) { printf(“Wakanda Forever!”); counter++; } int main(int argc, char* argv[]) { pid_t pid = fork(); if (pid == 0) { char[] argv = [“echo”, “Black Panther”, NULL]; execvp(argv[0], argv); } sigset_t mask; sigemptyset(&mask); while (counter < 1) { sigsuspend(&mask); } printf(“T\’Challa has won.”); }

slide-37
SLIDE 37

What will print?

int counter = 0; static void reapChild(int sig) { printf(“Wakanda Forever!”); counter++; } int main(int argc, char* argv[]) { pid_t pid = fork(); if (pid == 0) { char[] argv = [“echo”, “Black Panther”, NULL]; execvp(argv[0], argv); } sigset_t mask; sigemptyset(&mask); while (counter < 1) { sigsuspend(&mask); } printf(“T\’Challa has won.”); }

RACE CONDITION!!!

slide-38
SLIDE 38

What will print?

int counter = 0; static void reapChild(int sig) { printf(“Wakanda Forever!”); counter++; } int main(int argc, char* argv[]) { pid_t pid = fork(); if (pid == 0) { char[] argv = [“echo”, “Black Panther”, NULL]; execvp(argv[0], argv); } sigset_t mask; sigemptyset(&mask); sigset_t existing = blockSIGCHLD(); while (counter < 1) { sigsuspend(&mask); } unblockSIGCHLD(existing); printf(“T\’Challa has won.”); }

slide-39
SLIDE 39

sigprocmask(int how, const sigset_t* set, sigset_t* oldset)

sigset_t blockSIGCHLD() { sigset_t mask; sigset_t existing; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_BLOCK, &mask, &existing); return existing; } void unblockSIGCHLD(sigset_t existing) { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_UNBLOCK, &mask, &existing); }

slide-40
SLIDE 40

Virtual Memory

slide-41
SLIDE 41

Virtualization

Every process thinks it has exclusive access to addresses 0x00000000 to 0xffffffff.

slide-42
SLIDE 42

Virtualization

Every process thinks it has exclusive access to addresses 0x00000000 to 0xffffffff.

slide-43
SLIDE 43

Virtual Memory

Instead, the kernel keeps the MEMORY MANAGEMENT UNIT which helps map the virtual address spaces of every process to actual locations in physical memory.

slide-44
SLIDE 44

Lazy Loading

If a process needs to use a large library, the library will

  • nly be loaded into working

memory as needed. That way we can run many more processes at once.

Memory management is LAZY like these guys.

slide-45
SLIDE 45

Copy-on-write

While every process has its

  • wn virtual memory space,

physical memory is only duplicated when necessary. In fact, this is not even done when a process reads from memory, only when it writes.

Memory management is LAZY like these guys.

slide-46
SLIDE 46

Question

What are some situations in which the same virtual address in multiple processes map to the same physical address in main memory?

Iron Man is stumped. Are you?

slide-47
SLIDE 47

Question

  • Right after a fork if the OS is using copy-on-write
  • Forked processes explicitly want to share data among

themselves (mmap)

  • Shared code segments

What are some situations in which the same virtual address in multiple processes map to the same physical address in main memory?

slide-48
SLIDE 48

Scheduling

slide-49
SLIDE 49

Scheduling

Each process has an associated PCB (process control block) representing its state. This includes (among other things):

  • Register values

○ Including %rip so it knows what code was being executed

  • PID
slide-50
SLIDE 50

Scheduling

Each process has an associated PCB (process control block) representing its state. This includes (among other things):

  • Register values

○ Including %rip so it knows what code was being executed

  • PID

From Lab 2:

  • What commands may or may not move a

running process to the blocked set?

  • What commands are 100% guaranteed to

move a running process to the blocked set?

  • What needs to happen for a blocked

process to be moved back into the ready queue?

slide-51
SLIDE 51

MULTITHREADING

No assignments yet (assign4, assign5, assign6)

slide-52
SLIDE 52

What is a thread?

  • Threads are sometimes referred to as

“lightweight processes”.

  • They still have their own stacks, but unlike

processes they share the same heap, global variables, file descriptor table, etc.

  • We create them in C++ by passing in the

method we want to run in the newly spawned thread: thread newThread = thread(sayHello());

  • The above line will spawn a thread called

newThread that will run concurrently until sayHello() is completed.

slide-53
SLIDE 53

Joining threads

If you forget to call waitpid() on a process, you have a memory leak. If you forget to call .join() on a thread, your code will crash!

slide-54
SLIDE 54

Passing arguments to threads

Suppose we want a new thread to run the method foobar(int n, semaphore& sem) , where foobar() is a method in MyClass. There are a few ways to do so:

  • thread t([this, n, &sem] {foobar(n, sem)});

○ This captures all necessary variables and defines a lambda function that takes no parameters

  • thread t([this](int number, semaphore& s) {

....foobar(number, s); }, n, ref(sem); ○ This instead defines a lambda function that takes two parameters

  • thread t(&MyClass::foobar, this, n, ref(sem));

○ This is more like what we saw in Lab 3.

slide-55
SLIDE 55

Synchronization

This picture from last quarter’s review session sums this up better than any Marvel picture.

slide-56
SLIDE 56

Mutex

int main(int argc, const char *argv[]) { int counter = 0; thread thread1 = thread([&] () { counter++; }); thread thread2 = thread([&] () { counter++; }); thread1.join(); thread2.join(); cout << "counter = " << counter << endl; return 0; }

As we saw, the code on the left is not thread-safe. Because ++ is not an atomic

  • peration (the value is copied into a register,

increased, and copied back), it is possible that we will end up printing “counter = 1”

slide-57
SLIDE 57

Mutex

static mutex counterLock; int main(int argc, const char *argv[]) { int counter = 0; thread thread1 = thread([&] () { counterLock.lock(); counter++; counterLock.unlock(); }); thread thread2 = thread([&] () { counterLock.lock(); counter++; counterLock.unlock(); }); thread1.join(); thread2.join(); cout << "counter = " << counter << endl; return 0; }

This fixes the issue because whenever a thread is accessing or modifying counter’s value, no

  • ther thread can be doing so.

When counterLock.lock() is reached in

  • ne thread, it will block any other thread that

reads that line until the lock is released. Be sure to release the lock before going out of scope. Or you could use a...

slide-58
SLIDE 58

Lock Guard

static mutex counterLock; int main(int argc, const char *argv[]) { int counter = 0; thread thread1 = thread([&] () { lock_guard<mutex> lg(counterLock); counter++; }); thread thread2 = thread([&] () { lock_guard<mutex> lg(counterLock); counter++; }); thread1.join(); thread2.join(); cout << "counter = " << counter << endl; return 0; }

This is the same thing as using a mutex, except will automatically unlock when lg goes out of scope.

slide-59
SLIDE 59

Condition Variable

Unlike mutexes and lock guards, these provide notifications when a state has changed. In this sense, they are similar to signals. Similar to sigsuspend(), we get race conditions if we repeatedly check a condition and then wait until that condition may no longer

  • hold. Just as sigsuspend() atomically

unblocks signals and waits, condition variables atomically check the condition and wait. Condition Variable commands:

  • condition_variable_any cv;
  • cv.wait(mutex m, Predicate p);
  • cv.notify_all();

Also cv.notify_one() , but more on that later.

slide-60
SLIDE 60

Condition Variable

while (numQueued == 0) { //WHAT IF numQueued becomes 0 right here? RACE CONDITION!!! numQueuedLock.unlock(); queueCv.wait(); numQueuedLock.lock(); } vs. queueCv.wait(numQueuedLock, [&](){return numQueued > 0;}); //Since this is done atomically, no risk.

slide-61
SLIDE 61

Semaphore

Very often, we will want to limit the number of threads that can be doing something, but not restrict it to a single thread.

slide-62
SLIDE 62

Semaphore

Very often, we will want to limit the number of threads that can be doing something, but not restrict it to a single thread.

ENTER SEMAPHORE!!!

slide-63
SLIDE 63

Semaphore

Very often, we will want to limit the number of threads that can be doing something, but not restrict it to a single thread. A semaphore can be thought of as a set of permission slips. The initial value is the number

  • f permission slips, signal() adds a

permission slip, and wait() (once it is unblocked) takes a permission slip. Again, this is all done atomically. Semaphore commands:

  • semaphore sem(int value);
  • sem.signal();
  • sem.wait();

Just like with mutexes (mutices? this seems to be a point of contention on stack overflow...) be sure to signal() before going out of scope, because signaling is not the default behavior.

slide-64
SLIDE 64

Semaphore

Very often, we will want to limit the number of threads that can be doing something, but not restrict it to a single thread. A semaphore can be thought of as a set of permission slips. The initial value is the number

  • f permission slips, signal() adds a

permission slip, and wait() (once it is unblocked) takes a permission slip. Again, this is all done atomically. Keep in mind that semphores are implemented using condition variables, so anything a semaphore does can also be done using only condition variables (but shouldn’t be!). Semaphore commands:

  • semaphore sem(int value);
  • sem.signal();
  • sem.wait();

Just like with mutexes (mutices? this seems to be a point of contention on stack overflow...) be sure to signal() before going out of scope, because signaling is not the default behavior.

slide-65
SLIDE 65

Example

The Avengers need to fight Thanos! They need to take away all 5 infinity stones to win, but only 3 of them can attack Thanos at any given time (this entails sleeping and with some probability removing an infinity stone)! How can we handle this?

slide-66
SLIDE 66

Example

numInfinityStones = 5; int main(int argc, char* argv[]) { thread avengers[kNumAvengers]; for (int i = 0; i < kNumAvengers; i++) { thread(fightThanos, i); } for (thread avenger : avengers) { avenger.join(); } if (numInfinityStones == 0) { cout << oslock << “Hooray, the Avengers have defeated Thanos!” << endl << osunlock; } else { cout << oslock << “Yep, the Universe has been destroyed..." << endl << osunlock; } }

slide-67
SLIDE 67

Example

void fightThanos(int i) { //SOMEHOW WE CAN ONLY HAVE 3 MOVE ON AT A TIME: sleep_for(rand() % i * 100); if (rand() % i == 0) numInfinityStones--; }

slide-68
SLIDE 68

Example

static semaphore attackPermission(3); void fightThanos(int i) { attackPermission.wait(); sleep_for(rand() % i * 100); if (rand() % i == 0) numInfinityStones--; attackPermission.signal(); }

slide-69
SLIDE 69

Example

static semaphore attackPermission(3); static mutex infinityStoneLock; void fightThanos(int i) { attackPermission.wait(); sleep_for(rand() % i * 100); if (rand() % i == 0) { lock_guard<mutex> lg(infinityStoneLock); numInfinityStones--; } //lg goes out of scope here, infinityStoneLock is released. attackPermission.signal(); }

slide-70
SLIDE 70

Threads Processes

slide-71
SLIDE 71

Threads

  • Thread.join() //wait for a

thread to finish

  • ?

Processes

slide-72
SLIDE 72

Threads

  • Thread.join()
  • waitpid()

Processes

slide-73
SLIDE 73

Threads

  • Thread.join()
  • cv.wait(pred) //block until

some notification that the state may have changed

  • waitpid()
  • ?

Processes

slide-74
SLIDE 74

Threads

  • Thread.join()
  • cv.wait(pred)
  • waitpid()
  • while (pred) {sigsuspend()}

Processes

slide-75
SLIDE 75

Threads

  • Thread.join();
  • cv.wait(pred);
  • m.lock(); //prevent other

threads from interrupting

  • waitpid();
  • while (pred) {sigsuspend();}
  • ?

Processes

slide-76
SLIDE 76

Threads

  • Thread.join();
  • cv.wait(pred);
  • m.lock();
  • waitpid();
  • while (pred) {sigsuspend();}
  • sigprocmask(SIG_BLOCK,...);

Processes

slide-77
SLIDE 77

GOOD LUCK!

Any questions?