1 / 26

CS 3214 Introduction to Computer Systems

Explore the structure of process groups, signal management, and concurrency control in computer systems. Learn about terminal access, reentrancy, and accessing data structures in a concurrent environment.

rfraley
Download Presentation

CS 3214 Introduction to Computer Systems

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS 3214Introduction to Computer Systems Godmar Back Lecture 14

  2. 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

  3. Part 3 Threads and Processes CS 3214 Fall 2009

  4. 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

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

  6. 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

  7. 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

  8. 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

  9. 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 unblock(SIGNAL) block(SIGNAL) signal pending handler signal sent Signal handler returns sigreturn() user mode kernel mode CS 3214 Fall 2009

  10. 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 2nd 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

  11. 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. 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 (structlist_elem *before, structlist_elem *elem) { elem->prev = before->prev; elem->next = before; before->prev->next = elem; before->prev = elem; } If signal arrives inside the instructions doing the list manipulation, signal handler will see inconsistent – calls to list_insert will lead to havoc CS 3214 Fall 2009

  13. 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

  14. 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 • intsetjmp(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

  15. setjmp/longjmp (cont) • void longjmp(jmp_buf j, inti) • Meaning: • return from the setjmp remembered by jump buffer j again... • …this time returningi 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 bufj. CS 3214 Fall 2009

  16. setjmp/longjmp Example #include <setjmp.h> jmp_bufbuf; main() { if (setjmp(buf) != 0) { printf("back in main due to an error\n"); else printf("first time through\n"); p1(); /* p1 calls p2, which calls p3 */ } ... p3() { <error checking code> if (error) longjmp(buf, 1) } CS 3214 Fall 2009

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

  18. 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

  19. 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

  20. 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

  21. 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

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

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

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

  25. Reference Counting • Multiple file descriptors may refer to same open file • Within the same process: • fd = open(“file”); fd2 = dup(fd); • Across anchestor processes: • fd = open(“file”); fork(); • But can also open a file multiple times: • fd = open(“file”); fd2 = open(“file”); • In this case, fd and fd2 have different read/write offsets • In both cases, closing fd does not affect fd2 • 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

  26. 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

More Related