CS 3214 Introduction to Computer Systems Lecture 14

  • Slides: 26
Download presentation
CS 3214 Introduction to Computer Systems Lecture 14 Godmar Back

CS 3214 Introduction to Computer Systems Lecture 14 Godmar Back

Announcements • Read Chapter 8 & 11 • Exercise 9 due Oct 19 •

Announcements • Read Chapter 8 & 11 • Exercise 9 due Oct 19 • Project 3 has been published – See forum – due Oct 30 • Midterm: Tuesday Oct 20 CS 3214 Fall 2009 12/2/2020 2

Part 3 THREADS AND PROCESSES CS 3214 Fall 2009 12/2/2020 3

Part 3 THREADS AND PROCESSES CS 3214 Fall 2009 12/2/2020 3

Signals – Summary • Universal mechanism to notify a process of events – Internal

Signals – Summary • Universal mechanism to notify a process of events – Internal events (memory access violation, process -internal timers, …) – External events • User-driven: ^C, ^Z • Resulting from other processes: explicit kill(2), or SIGCHLD • Resulting from kernel event: e. g. , SIGTTOU, SIGTTIN • Signal handler can change program state before returning – Extremely powerful CS 3214 Fall 2009 12/2/2020 4

Process Groups • Every process belongs to exactly one process group pid=20 pgid=20 pid=10

Process Groups • Every process belongs to exactly one process group pid=20 pgid=20 pid=10 pgid=10 Foreground job Child pid=21 pgid=20 pid=22 pgid=20 Shell Background job #1 Background job #2 pid=32 pgid=32 Background process group 32 pid=40 pgid=40 Background process group 40 getpgrp() – Return process group of current process setpgid() – Change process group of a process Foreground process group 20 CS 3214 Fall 2009 12/2/2020 5

Process Groups, cont. • Every process can form a new process group by declaring

Process Groups, cont. • Every process can form a new process group by declaring themselves a leader – setpgid(0, 0) • But, this is not necessary – process groups can also be formed by having a parent place a process in its own or an existing group – E. g. , shell places all children belonging to the same pipeline into the same group • Process groups are populated simply by adding processes to them – Restriction: process group must be part of the same “session” – a concept that groups multiple procgroup’s. • See /proc/<pid>/stat to learn pgid of a process CS 3214 Fall 2009 12/2/2020 6

Managing Terminal Access • What if multiple processes wish to read from the terminal?

Managing Terminal Access • What if multiple processes wish to read from the terminal? – (default behavior: undefined) • Use process groups – One ‘foreground pgroup’ per terminal • Kernel will suspend (via SIGTTOU/TTIN) any process in background pgroup that attempts to read from terminal – Try: “vim &” • It’s up to shell to manage access to the terminal – Use tcsetpgrp() CS 3214 Fall 2009 12/2/2020 7

Signals & Concurrency • Signal handlers for external events can occur during *anytime* –

Signals & Concurrency • Signal handlers for external events can occur during *anytime* – Unless blocked – must think of signal handler as concurrent flow of control regular program handler signal delivered Signal handler returns sigreturn() user mode kernel mode CS 3214 Fall 2009 12/2/2020 8

Signals & Concurrency • Blocking a signal guarantees that signal handler execution will not

Signals & Concurrency • Blocking a signal guarantees that signal handler execution will not occur even when signal is delivered – Will occur as soon as the signal is unblocked block(SIGNAL) signal pending unblock(SIGNAL) handler signal sent Signal handler returns sigreturn() user mode kernel mode CS 3214 Fall 2009 12/2/2020 9

Reentrancy • A function is said to be reentrant if it can be safely

Reentrancy • A function is said to be reentrant if it can be safely called again even while a call is still in progress (i. e. , has not returned) – Could be on a regular control flow path, e. g. recursion – Or 2 nd call could be from signal handler – Or (discuss this later in more detail) from another thread • Examples of functions that are not reentrant – inet_ntoa(), strtok() – uses private buffer – printf() – takes a lock • You cannot call non-reentrant functions from a signal handler for signal ‘s’ – Unless you prevent the delivery of ‘s’ during calls in your main program via { block(s); …. ; unblock(s); } CS 3214 Fall 2009 12/2/2020 10

Async-Signal Safety • ‘async-signal safe functions’ - safe to call from a signal handler

Async-Signal Safety • ‘async-signal safe functions’ - safe to call from a signal handler – Provide the signal is allowed to occur (i. e. , is not blocked) while calls to these functions are in progress – else no issue arises • See list in man 2 signal. Includes waitpid(), etc. • The kicker: printf() is not safe to call in a signal handler – Frequent source of bugs (even in some textbook sample code…. !) – Can use ‘snprintf() + write(1, …)’ if needed CS 3214 Fall 2009 12/2/2020 11

Concurrent Accesses To Data Structures • Consider shell maintaining a list of jobs –

Concurrent Accesses To Data Structures • Consider shell maintaining a list of jobs – Main program forks, adds jobs – SIGCHLD handler may reap jobs, perhaps remove jobs from joblist void list_insert (struct list_elem *before, struct list_elem *elem) { If signal arrives inside the elem->prev = before->prev; instructions doing the list elem->next = before; manipulation, signal handler will before->prev->next = elem; see inconsistent – calls to before->prev = elem; list_insert will lead to havoc } CS 3214 Fall 2009 12/2/2020 12

Strategy • Identify data structures shared between signal handler and main program – E.

Strategy • Identify data structures shared between signal handler and main program – E. g. , everything the signal handler (or functions called from it) accesses • Then protect accesses to those data structures by blocking the signal around the access • Use ‘assert()’ – assert(esh_signal_is_blocked(SIGCHLD)); • Aside: the technique of delaying such interrupts is used inside OS in a very similar way, e. g. when devices trigger interrupts CS 3214 Fall 2009 12/2/2020 13

Nonlocal Jumps: setjmp/longjmp • Powerful (but dangerous) user-level mechanism for transferring control to an

Nonlocal Jumps: setjmp/longjmp • Powerful (but dangerous) user-level mechanism for transferring control to an arbitrary location. – Controlled to way to break the procedure call/return discipline – Useful for error recovery and signal handling • int setjmp(jmp_buf j) – Must be called before longjmp – Identifies a return site for a subsequent longjmp. – Called once, returns one or more times • Implementation: – Remember where you are by storing the current register context, stack pointer, and PC value in jmp_buf. – Return 0 CS 3214 Fall 2009 12/2/2020 14

setjmp/longjmp (cont) • void longjmp(jmp_buf j, int i) – Meaning: • return from the

setjmp/longjmp (cont) • void longjmp(jmp_buf j, int i) – Meaning: • return from the setjmp remembered by jump buffer j again. . . • …this time returning i instead of 0 – Called after setjmp – Called once, but never returns • longjmp Implementation: – Restore register context from jump buffer j – Set %eax (the return value) to i – Jump to the location indicated by the PC stored in jump buf j. CS 3214 Fall 2009 12/2/2020 15

setjmp/longjmp Example #include <setjmp. h> jmp_buf buf; main() { if (setjmp(buf) != 0) {

setjmp/longjmp Example #include <setjmp. h> jmp_buf buf; main() { if (setjmp(buf) != 0) { printf("back in main due to an errorn"); else printf("first time throughn"); p 1(); /* p 1 calls p 2, which calls p 3 */ }. . . p 3() { <error checking code> if (error) longjmp(buf, 1) } CS 3214 Fall 2009 12/2/2020 16

A Program That Restarts Itself When ctrl-c’d #include <stdio. h> #include <signal. h> #include

A Program That Restarts Itself When ctrl-c’d #include <stdio. h> #include <signal. h> #include <setjmp. h> sigjmp_buf buf; while(1) { sleep(1); printf("processing. . . n"); } } void handler(int sig) { siglongjmp(buf, 1); } bass> a. out starting processing. . . main() { restarting signal(SIGINT, handler); processing. . . if (!sigsetjmp(buf, 1)) processing. . . printf("startingn"); restarting else processing. . . printf("restartingn"); restarting processing. . . CS 3214 Fall 2009 Ctrl-c 12/2/2020 17

Limitation of setjmp/longjmp • Longjmp restores stack pointer – Thus activates a new stack

Limitation of setjmp/longjmp • Longjmp restores stack pointer – Thus activates a new stack frame – Stack frame must still be valid • Consequence: – Can only longjmp “up the stack” to functions that haven’t yet returned when longjmp() is called – repositioning the stack pointer automatically “destroys” intermediate stack frames • But does not call cleanup functions provided in some languages (e. g. C++ destructors or Java ‘finally’ clauses) – Longjmp’ing “down the stack” would “reactivate” already destroyed stack frames • Does not necessarily crash, but leads to unpredictable results • Think of setjmp/longjmp as a low-level mechanism to implement a variant of C++/Java style exceptions CS 3214 Fall 2009 12/2/2020 18

Summary • Signals provide process-level exception handling – Can generate from user programs –

Summary • Signals provide process-level exception handling – Can generate from user programs – Can define effect by declaring signal handler • Some caveats – Very high overhead • >10, 000 clock cycles • Only use for exceptional conditions – Don’t have queues (exception: “real-time signals”) • Just one bit for each pending signal type • Nonlocal jumps provide exceptional control flow within process – Within constraints of stack discipline CS 3214 Fall 2009 12/2/2020 19

Unix File Descriptors • Unix provides a file descriptor abstraction • File descriptors are

Unix File Descriptors • Unix provides a file descriptor abstraction • File descriptors are – Small integers that have a local meaning within one process – Can be obtained from kernel • Several functions create them, e. g. open() – Can refer to various kernel objects (not just files) – Can be passed to a standard set of functions: • read, write, close, lseek, (and more) – Can be inherited when a process forks a child CS 3214 Fall 2009 12/2/2020 20

Examples • 0 -2 are initially assigned – 0 – stdin – 1 –

Examples • 0 -2 are initially assigned – 0 – stdin – 1 – stdout – 2 – stderr – But this assignment is not fixed – process can change it via syscalls • int fd = open(“file”, O_RDONLY); • int fd = creat(“file”, 0600); CS 3214 Fall 2009 12/2/2020 21

Implementing I/O Redirection • dup and dup 2() system call • pipes: pipe(2) CS

Implementing I/O Redirection • dup and dup 2() system call • pipes: pipe(2) CS 3214 Fall 2009 12/2/2020 22

dup 2 #include <stdio. h> #include <stdlib. h> // redirect stdout to a file

dup 2 #include <stdio. h> #include <stdlib. h> // redirect stdout to a file int main(int ac, char *av[]) { int c; int fd = creat(av[1], 0600); if (fd == -1) perror("creat"), exit(-1); if (dup 2(fd, 1) == -1) perror("dup 2"), exit(-1); while ((c = fgetc(stdin)) != EOF) fputc(c, stdout); } CS 3214 Fall 2009 12/2/2020 23

user view kernel view 0 1 The Big Picture 2 3 4 Process 1

user view kernel view 0 1 The Big Picture 2 3 4 Process 1 0 1 open(“x”) Terminal Device File Descriptor Open File x open(“x”) close(4) File Descriptor 2 3 dup 2(3, 0) Process 2 CS 3214 Fall 2009 12/2/2020 24

Reference Counting • Multiple file descriptors may refer to same open file – Within

Reference Counting • Multiple file descriptors may refer to same open file – Within the same process: • fd = open(“file”); fd 2 = dup(fd); – Across anchestor processes: • fd = open(“file”); fork(); • But can also open a file multiple times: – fd = open(“file”); fd 2 = open(“file”); – In this case, fd and fd 2 have different read/write offsets • In both cases, closing fd does not affect fd 2 • Reference Counting at 2 Levels: – Kernel keeps track of how many processes refer to a file descriptor –fork() and dup() may add refs – And keeps track of how many file descriptors refer to open file • close(fd) removes reference in current process CS 3214 Fall 2009 12/2/2020 25

Practical Implications • Number of simultaneously open file descriptors per process is limited –

Practical Implications • Number of simultaneously open file descriptors per process is limited – 1024 on current Linux, for instance • Must make sure fd’s are closed – Else ‘open()’ may fail • Number space is reused – “double-close” error may inadvertently close a new file descriptor assigned the same number CS 3214 Fall 2009 12/2/2020 26