Presentation is loading. Please wait.

Presentation is loading. Please wait.

Processes 2: Signals & Pipes CS 360 proc2. Page 2 proc2 CS 360 WSU Vancouver The Big Picture For processes to cooperate, they must share data 4 why aren't.

Similar presentations


Presentation on theme: "Processes 2: Signals & Pipes CS 360 proc2. Page 2 proc2 CS 360 WSU Vancouver The Big Picture For processes to cooperate, they must share data 4 why aren't."— Presentation transcript:

1 Processes 2: Signals & Pipes CS 360 proc2

2 Page 2 proc2 CS 360 WSU Vancouver The Big Picture For processes to cooperate, they must share data 4 why aren't files good enough? Issue is called "inter-process communication" - IPC 4 Unix has several IPC mechanisms Basic IPC: 4 pipes 4 signals Elegant IPC: 4 Semaphores 4 Shared Memory Specialized IPC: 4 named pipes 4 record locking 4 message queues 4 FIFO's future lecture later in this lecture

3 Page 3 proc2 CS 360 WSU Vancouver Agenda Pipes Signals Atomic Operations Lab Assignment T his week we continue learning about Unix processes - independently running programs

4 Page 4 proc2 CS 360 WSU Vancouver Pipes

5 Page 5 proc2 CS 360 WSU Vancouver The Invention of Pipes The Unix inventors were trying to find the words in a file: They added some syntax to the shell as an abbreviation: They then had a flash of insight: 4 the two programs could run simultaneously (fork/exec consequence) 4 the temporary file doesn't have to exist on disk (could be just a kernel buffer) 4 one program fills the buffer, the other empties it 4 a tweak to open/close and read/write, and voila! % tr " " "\n" tempFile % sort -u outputFile % tr " " "\n" outputFile A Unix innovation: simple, useful

6 Page 6 proc2 CS 360 WSU Vancouver What is a Pipe? A pipe is a one-way communication channel between processes A simple but powerful technique for processes to communicate process 1 process 2 write file descriptor read file descriptor kernel buffer Logistics: 4 a pipe is a kernel buffer with a "read" and and a "write" end 4 kernel presents each end as a file descriptor (of course!) 4 the processes uses normal read/write routines (again, nothing special) 4 one process writes into one end; the other process reads from other end 4 parent creates the file descriptors (using "pipe" routine) 4 the descriptors are preserved across fork/exec (nothing special) 4 writer waits if buffer is full, reader waits if buffer is empty

7 Page 7 proc2 CS 360 WSU Vancouver A Closer Look at File Descriptors parent process file descriptor table Descriptors may share an inode or pnode Fork duplicates the descriptor table Open/close/pipe etc. modify the table child process file descriptor table fork open pipe

8 Page 8 proc2 CS 360 WSU Vancouver Problem statement: 4 parent will create a pipe and fork a child 4 the parent writes to pipe, the child reads A Pipe Example #include int fd[2]; pipe (fd); if (fork ()) { while (... have more data... ) { write (fd[1],... ) } } else { while (read (fd[0],... )) {... use the data... } exit (0); }... parent continues... parent child fd[0] fd[1] the header fd[0] = read end, fd[1] = write end fork write data into pipe for child to read read data from pipe until eof compute asynchronously from parent

9 Page 9 proc2 CS 360 WSU Vancouver A Complete Pipe Example Problem statement: 4 parent will create a pipe and fork a child 4 the parent will write to pipe, the child will read #include int fd[2]; pipe (fd); if (fork ()) { close (fd[0]); while (... have more data... ) { write (fd[1],... ); } close (fd[1]); } else { close (fd[1]); while (read (fd[0],... )) {... use the data... } exit (0); }... parent continues... fd[0] = read end, fd[1] = write end parent closes read end writes data into pipe for child to read child closes write end reads data from pipe until eof computes asynchronously from parent Notes: why close the end not used? parent child close write end when done fd[0] fd[1] the header

10 Page 10 proc2 CS 360 WSU Vancouver Using Exec with Pipes Consider this problem: 4 calculate 1 * 2 * 3 *... * 49 * 50 % bc < formula 24 1 * 2 * 3 * 4 formula Approach: 4 easy to code except the product is much too large for C int's or long's 4 however, there is a neat program "bc" that handles any size integers: % factorial 50 30414093201713378043612608166064768844377641568960512000000000000 Using pipes, we can use "bc" from inside a program that we write: Must fork/exec the bc program such that it's stdin = read end of a pipe Parent writes "1*2*3 *...*50\n" to the write end of the pipe Child reads that, computes, and writes its answer to stdout

11 Page 11 proc2 CS 360 WSU Vancouver int main (int argc, char *argv[]) { int i, n;/* i=1, 2,..., n */ int fd[2];/* pipe file descriptors */ int rdr, wtr; /* fd[0] and fd[1] */ char text[10]; /* "*6" etc. */ assert (sscanf (argv[1], "%d", &n) == 1); assert (pipe (fd) >= 0); rdr = fd[0]; wtr = fd[1]; if (fork ()) { /* parent writes... */ close (rdr); write (wtr, "1", 1); for (i = 2; i <= n; ++i) { sprintf (text, "*%d", i); write (wtr, text, strlen (text)); } write (wtr, "\n", 1); close (wtr); exit (0); } else { /* child becomes bc and reads... */ close (wtr); close (0); dup (rdr); close (rdr); execlp ("bc", "bc", 0); fprintf (stderr, "%s: exec of bc failed\n", argv[0]); exit (1); } Factorial Program Source... parent child stdin wtr

12 Page 12 proc2 CS 360 WSU Vancouver Assignment Write a program "connect" works like a shell pipeline % connect friday : wc -l = % friday | wc -l The colon argument breaks argv into a left portion and a right portion % connect friday : wc -l leftright parent child stdin stdout Implementation will fork/exec and setup a pipe such that: 4 parent: left portion runs with stdout = pipe write end 4 child:right portion runs with stdin = pipe read end Consider swapping these parent/child functions… Why?

13 Page 13 proc2 CS 360 WSU Vancouver Assignment (continued) Due before class on February 25 th (Wednesday) Submit “connect.c” 4 File connect.c should include all code and declarations other than library components Please note: The specification for this program is intentionally incomplete. Consider various situations and exception conditions that may occur. Determine a reasonable interpretation of the arguments, then design and implement a robust program.

14 Page 14 proc2 CS 360 WSU Vancouver Dup: A Useful Variant of Open "Dup" duplicates a file descriptor value new_fd = dup (old_fd); some inode or pipe end process file descriptor table before...... and after dup (1) some inode or pipe end Notes: 4 a new descriptor is returned (in above case, returns 3) 4 the new descriptor indexes same value as that the old descriptor indexes 4 the new descriptor is smallest index not open (very useful!)  There is another form: dup2(old_fd,new_fd) this form lets the programmer specify the new file descriptor number rather than letting the kernel pick it. (If the new_fd is open, it is first closed)

15 Page 15 proc2 CS 360 WSU Vancouver Some Pipe Details Reads: 4 if any data in pipe, return it (could be fewer bytes than requested) 4 if pipe is empty and there is a writer, wait for data to be added to the pipe 4 otherwise, return -1 (eof) Writes: 4 if there are no readers, return error (broken pipe) 4 if data fits into pipe, add it atomically (as an indivisible action) 4 otherwise, add data in chunks as readers make room 4 and, if some readers are waiting, wake them up (so they can remove data) These are simple and necessary rules

16 Page 16 proc2 CS 360 WSU Vancouver An Exercise For You To Try Situation: 4 setup a parent and child process with the following relationship: write file descriptor -- x[1]read file descriptor -- x[0] parent child read file descriptor -- y[0]write file descriptor -- y[1]

17 Page 17 proc2 CS 360 WSU Vancouver Signals

18 Page 18 proc2 CS 360 WSU Vancouver Interrupts An "interrupt" is an event that can occur at an unpredictable time 4 interrupt key received from keyboardSIGINT 4 alarm clock ringsSIGALRM 4 child process terminatesSIGCHLD 4 floating point exceptionSIGFPE 4 login connection hung upSIGHUP 4 urgent data received on network connection 4 CPU time limit exceeded 4... Unix handles interrupts using a basic facility called "signals" 4 each event has an associated integer code 4 when the event occurs, the kernel "sends the signal" to the effected process 4 the process then "receives the signal" and can take action Writing reliable programs that respond to such events is difficult 4 hard to anticipate all situations 4 hard to create test conditions

19 Page 19 proc2 CS 360 WSU Vancouver Signal Example 1: Critical Computation Situation: 4 a critical computation must not be interrupted by user’s ^C Code skeleton: #include critical_computation () { signal (SIGINT, SIG_IGN);... do the computation... signal (SIGINT, SIG_DFL); } begin ignoring SIGINT restore default SIGINT action signal codenew signal action

20 Page 20 proc2 CS 360 WSU Vancouver Signal Example 2: Mandatory Cleanup Situation: 4 a complicated computation must be always be properly cleaned up 4 e.g.: temporary files must be deleted Code skeleton: #include complicated_computation () {... prepare for computation... signal (SIGINT, my_handler);... do the computation... signal (SIGINT, SIG_DFL); cleanup (); } void my_handler() { printf ("\nInterrupt received!\n"); cleanup (); exit (1): } set new handler for SIGINT restore default SIGINT handler receive SIGINT signal: cleanup computation and exit

21 Page 21 proc2 CS 360 WSU Vancouver Set signal action: 4 previous setting is returned Send signal to a process: 4 uid of killer must be superuser or equal to uid of target Receive signal: 4 if action is to ignore, do nothing (some signals don't permit this, e.g.: SIGKILL) 4 if action is default, take default action (usually to terminate process) 4 if action is to call handler: –call the handler (argument is signal code after setting signal action back to default) –upon return from handler, resume the process where it was interrupted –if inside a blocked system call, return from that call with an error (e.g.: a read) Other routines: signal (code, SIG_IGN);/* ignore signal */ signal (code, SIG_DFL);/* take default action */ signal (code, handler);/* call handler */ kill (pid, code);/* send signal to a process */ pause ();/* put process into wait state */ alarm (seconds);/* send SIG_ALRM in seconds */ declared as: void handler (int); Signal Routines Capsule Summary

22 Page 22 proc2 CS 360 WSU Vancouver Signal Example 3: Sleep Situation: 4 write a routine "sleep" that makes process wait for specified seconds Usage:... sleep (5);/* process waits for (at least) 5 seconds */... static void handler (int); void sleep (int seconds) { signal (SIGALRM, handler); alarm (seconds); pause (); alarm (0); } static void handler (int code) { /* return makes the pause() return */ } Code:

23 Page 23 proc2 CS 360 WSU Vancouver Signal Example 4: Quick Reply Situation: 4 prompt user for a answer, but use default if user takes too long Code: static void handler (int code); static int expired; void ask (char *question, char *answer, int seconds, char *default) { int ok; /* fgets happy? */ fputs (question, stdout); fflush (stdout); signal (SIGALRM, handler); expired = 0; alarm (seconds); fgets (answer, 100, stdin); alarm (0); if (expired) strcpy (answer, default); } static void handler (int code) { expired = 1; /* return makes the fgets internal read return with error */ } issue: how about EOF? Why call alarm again?

24 Page 24 proc2 CS 360 WSU Vancouver Example 5: Restart a Computation Situation: 4 if user hits interrupt key, stop computation and begin again 4 e.g.: command line interpreter Code: #include static jmp_buf stack_state; static void handler (int); void commmand_line_loop () { setjmp (stack_state); signal (SIGINT, handler); while (... get command...) {... interpret the command... } signal (SIG_INT, SIG_DFL); } static void handler (int code) { printf ("\nCommand interrupted!\n"); longjmp (stack_state, 0); } save stack state restore stack state return 0 from setjmp Advanced

25 Page 25 proc2 CS 360 WSU Vancouver Signal Example 2: An Improvement #include static void my_handler (int); complicated_computation () { int prev;... prepare for computation... prev = signal (SIGINT, SIG_IGN); if (prev != SIG_IGN) signal (SIGINT, my_handler);... do computation... if (prev != SIG_IGN) signal (SIGINT, prev); cleanup (); } static void my_handler (int code) { printf ("\nInterrupt received!\n"); cleanup (); exit (1): } set new handler for SIGINT only if not currently ignoring receive SIGINT signal: cleanup computation and exit restore old SIGINT handler if we changed it declare the handler interface declare a variable "prev" Advanced

26 Page 26 proc2 CS 360 WSU Vancouver Atomic Operations

27 Page 27 proc2 CS 360 WSU Vancouver What If 2 Processes Manipulate 1 File? What is a concrete example of when this might happen? What are the possible outcomes? 4 think pessimistically! What do you make of this?

28 Page 28 proc2 CS 360 WSU Vancouver File Sharing & Atomic Operations Unix supports the sharing of open files between separate processes 4 provides the convenient stdin/stdout shell behavior without special cases 4 gives programmers maximum control The kernel operates like this: 4 each process has its own file status flags ("open for reading?",...) 4 each process has its own "current offset" into the file bytes The low level I/O operations are all "atomic" 4 an operation either completes fully or fails fully For example: 4 bytes are read or written as a chunk without interruption 4 open/close/lseek cannot be interrupted This is a consistency promise, not a timing promise! What are some consequences of this approach? 4

29 Page 29 proc2 CS 360 WSU Vancouver Summary The key process creation routines are: 4 fork 4 exec 4 wait The key process communication routines are: 4 pipe 4 dup, dup2 The key interrupt handling routines are 4 signal 4 setjmp (to restart a computation)


Download ppt "Processes 2: Signals & Pipes CS 360 proc2. Page 2 proc2 CS 360 WSU Vancouver The Big Picture For processes to cooperate, they must share data 4 why aren't."

Similar presentations


Ads by Google