1 / 52

chapter 2

chapter 2. processes, pipes and signals. A process is a running program On multi-CPU machines, processes execute simultaneously on separate CPUs. On single-CPU machines, processes “appear” to run simultaneously through time-sharing.

mariel
Download Presentation

chapter 2

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

  2. processes, pipes and signals • A process is a running program • On multi-CPU machines, processes execute simultaneously on separate CPUs. • On single-CPU machines, processes “appear” to run simultaneously through time-sharing. • Most processes execute independent of one another; sharing nothing. • multitasking - one purpose with multiple threads of execution – implemented with cloning (fork()) and threads

  3. process state machine running on CPU IO request time out blocking because of IO request taking its turn IO complete waiting for CPU time

  4. fork(): • fork() is called with no arguments and returns a result code can potentially be used to share information fds shared parent child copy data $pid = fork(); if ($pid>0) { # parent } else { # child $ppid = getppid(); } $pid = fork(); if ($pid>0) { # parent } else { # child $ppid = getppid(); } child runs this code parent runs this code signal one another in child, $pid now has new value same program in both processes

  5. fork() (2): $pid = fork(); in child, this is 0; to get parent PID child executes $pid = getppid(); in parent, this is the child PID NOTE: In case of error, fork() returns undef and $! contains the appropriate error message

  6. process group: • All processes that fork() from the same ancestor belong to the same process group. The group PID is usually the parent process PID. • You can fork() from a child and produce grandchildren • You can fork() repeatedly and produce siblings $processid = getpgrp([$pid]); if $pid is not specified then get the group for the current process.

  7. sharing • Each member of group shares whatever filehandles were open when their common ancestor forked. • Shared filehandles can be used to exchange information between processes in the same group. • Processes in the same group share STDIN, STDOUT and STDERR.

  8. sharing files: • fork() is called with no arguments and returns a result code a shared file/filehandle shared parent child RW RW copy data book calls this “shar[ing] the current values”, p36

  9. Simple program: #!/usr/bin/perl # file: fork.pl print “PID = $$\n”; # $$ is current process PID my $child = fork(); die “Can’t fork: $!” unless defined $child; if ( $child > 0 ) { # parent since $child != 0 print “parent PID = $$, child PID = $child\n”; } else { # child since $child == 0 my $ppid = getppid(); print “child PID = $$, parent PID = $ppid\n”; } defined() is a function that tests if a variable has a value which print statement prints out first? on Windows? on Linux?

  10. Executing other programs: $result = system(“command and arguments”); • Executes a command from inside a perl program; the program blocks until the command completes and then continues executing at the next line • $result == 0 if all went well; -1 if command couldn’t start or command failed. Look at $? for the error. • None of the command’s STDOUT output is returned to the program but is sent rather to whatever STDOUT is currently writing to. This is relevant since you often want to process the STDOUT output that is generated by something called from a perl program.

  11. system(): #!/usr/bin/perl # system.pl system(“echo ‘hello, world!”); $ ./system.pl hello, world! $ • echoes “hello, world!” to terminal • sends “hello, world!” to the file fileout #!/usr/bin/perl # system.pl system(“echo ‘hello, world!”); $ ./system.pl > fileout $ cat fileout hello, world! $

  12. system() 2: #!/usr/bin/perl # system.pl $result = system(“echo ‘hello, world!”); printf $result . “\n”; $result = system(“cat nofile”); $err = $? >> 8; printf $result . “\n”; printf “error: $err\n”; $ ./system.pl hello, world! 0 cat: nofile: no such file or directory 256 error: 1 $ $result == 0 if ok error code comes as most significant byte of two byte word; shift right 8 bits to see actual value. $result != 0 if command fails

  13. exec(): • With exec() you actually replace the existing program with a new one using the same PID. • All data and “knowledge” about its past self are lost to the process; it becomes the program being execed.

  14. exec() 2: • use fork() and exec() to make one program startup and run another fds shared parent child $pid = fork(); if ($pid>0) { # parent } else { # child $err = exec(“command and args”); } $pid = fork(); if ($pid>0) { # parent } else { # child $err = exec(“command and args”); } child runs this code parent runs this code entire process replaced with “command and args”

  15. exec() 3: #!/usr/bin/perl my $child = fork(); if ( $child == 0 ) { open(STDOUT,”>log.txt”) or die “open() error: $!”; exec (“ls –l”); die “exec error: $!”; } exit 1; # parent exits redirect STDOUT output to log.txt the newly execed program inherits my STDOUT we only execute this only if exec() fails the parent process exits immediately Problem: IS STDOUT redirected in the parent process?

  16. pipes: • Used for communication between two processes running on the same host. • The processes may be related (parent-child-sibling) or unrelated. • The above opens a pipe between (from) the ls command and (to) the INFILE handle of this program. • The above opens a pipe between (from) this program (to) the OUTFILE handle of the wc command. open(INFILE, “ls –la | “); open (OUTFILE, “ | wc -l”);

  17. pipes 2: $wc = IO::Filehandle->open(“ | wc –lw”) or die “Can’t open: $!”;

  18. Using pipes (simple example): read perldoc perlvar about exit codes #!/usr/bin/perl # fle: whos_there.pl use strict; my %who; # accumulate login count open(WHOFH, “who |”) or die “can’t open who: $!”; while ( <WHOFH> ) { next unless /^(\S+)/; $who{$1}++; } foreach (sort {$who{$b} <=> $who{$a}} keys %who) { printf “%10s %d\n”,$_, $who{$_}; } close WHOFH or die “can’t close who: $!”; can’t use redirect since who is a command non-whitespace token anchored at start of line $1 == value of match found inside ( ) fancy way to sort a list of keys by hash value in ascending order read about sort() at perldoc perlfunc use $_ if foreach has no specified variable

  19. backtick (`…`): all stdout output read into a single scalar $arguments = “-lart”; $ls_output = `ls $arguments`; • is the same as $arguments = “-lart”; open(INFILE, “ls $arguments |”); while (<INFILE>) { $ls_output .= $_; } concatenate

  20. backtick and stderr: • ` … ` returns only STDOUT output; what about STDERR output? • The above delivers both STDOUT and STDERR output to $ls_output. $ls_output = `ls 2>&1`;

  21. pipe R W W R parent child close close pipe R W W R pipe(): $result = pipe(READHANDLE,WRITEHANDLE); • This opens a pipe; one can read from READHANDLE and write to WRITEHANDLE. • One uncommon usage is to open a pipe (in fact, two) just before forking a child. The pipe and all handles are shared by both processes. Close handles to leave two unidirectional pipes.

  22. WRITER READER pipe (in detail): pipe before fork() parent child pipe WRITER WRITER READER READER after fork()

  23. child2 parent child1 pipe pipe WRITER READER WRITER print while <READER>; factorial() fibonacci() pipe() 2: single WRITER handle shared by two siblings single READER handle in parent only one pipe two child processes

  24. #!/usr/bin/perl # file: facfib.pl use strict; my $arg = shift || 10; pipe(READER,WRITER) or die “Can’t open pipe: $!”); if ( fork() == 0 ) {# child 1 close READER; select WRITER; $| = 1; factorial($arg); exit 0; } if ( fork() == 0 ) {# child 2 close READER; select WRITER; $| = 1; fibonacci($arg); exit 0; } facfib.pl: at this point default output is WRITER

  25. facfib.pl 2: sub factorial { my $target = shift; for (my $result = 1, ,y $i = 1; $i <= $target; $i++) { print “factorial($i) => “ , $result *= $i , “\n”; } } sub fibonacci { my $target = shift; my ($a,$b) = (1,0); for (my $i = 1; $i <= $target; $i++) { my $c = $a + $b; print “fibonacci($i) => $c\n”; ($a,$b) = ($b,$c); } } default output is still WRITER list assignment

  26. pipe() as an alternative to open(): • The problem with • is that you can only read from the program and you are constrained by reading in a loop inside your program. • What if you want to read from and write to the program? • What if you want to program to go off on its own to do its own thing while you are busy doing something else? open(READER,”myprog.pl $args |”);

  27. Example 1: • almost identical to myprog.pl doesn’t execute in parallel in the open() example open(READER,”myprog.pl $args |”); pipe(READER,WRITER) or die “pipe no good: $!”; my $child = fork(); die “can’t fork: $!” unless defined $child; if ( $child == 0 ) { close READER; open(STDOUT, “>&WRITER”); exec myprog.pl $args; die “exec failed: $!”; } close WRITER; … at this point myprog.pl is executed in the process space originally intended for the child process; it inherits the STDOUT handle, which points to WRITER.

  28. bidirectional pipes: • pipes are created unidirectional; • is illegal • For true bidirectional communication we use socketpair() which is introduced in Chapter 4 open(FH, “| $cmd |”);

  29. Is a filehandle a pipe or what? • perl offers a file testing mechanism to determine many things about a file

  30. examples: • Test if we have closed STDIN for batch mode. • Test if a handle is a pipe. if ( -t STDIN ) { printf “STDIN not closed yet.\n”; } print “Not a pipe\n” if ! –p FILEHANDLE;

  31. PIPE Error: • Reading: no problem Suppose you are reading at one end of a pipe and your child is writing at the other end. Now suppose the child closes its end of the pipe or even exits? parent child pipe now close the pipe or exit the program R W W R when next you read, EOF will happen

  32. PIPE Error: • Writing: a problem Suppose you are writing at one end of a pipe and your parent is reading at the other end. Now suppose the parent closes its end of the pipe or even exits? parent child pipe when you try to write you get the Broken pip error R W W R now close the pipe or exit

  33. program example: #!/usr/bin/perl #file: write_ten.pl use strict; open(PIPE,”| read_three.pl”) or die “Can’t open pipe: $!”; select PIPE; $| = 1; select STDOUT; my $count = 0; for ( 1..10) { warn “Writing line $_\n”; print PIPE “This is line number $_\n”; $count++; sleep 1; # or select(undef,undef,undef,0.5) } close PIPE or die “Can’t close PIPE: $!”; print “Write $count lines of text\n”; #!/usr/bin/perl # file: read_three.pl use strict; for (1..3) { last unless defined ($line = <>); warn “read_three got: $line” } after the 3rd write, the read_three.pl program terminates and closes the PIPE. The output is

  34. program output: Writing line 1 Read_three got: This is line number 1 Writing line 2 Read_three got: This is line number 2 Writing line 3 Read_three got: This is line number 3 Writing line 4 Broken pipe this error is called a Pipe Exception tried to write to a pipe closed by read_three.pl; no line was successfully passed to the read_three.pl

  35. PIPE Exception: • A PIPE Exception results in a PIPE signal being delivered to the writing process. • Processes that receive the PIPE signal terminate by default. • This also happens when writing across a network to a remote program that has closed its end of the communication channel or exited. • To deal programmatically with a PIPE signal you mist write a signal handler.

  36. Signals: • A signal is a message sent to your program by the OS when something “important” occurs. • Processes can signal each other. Examples: - the program asks a stdlib routine to divide by zero - a user tries to interrupt the program (other than ^C). - a sub-process terminated but it is not the end of the world Examples: - when user hits ^C the shell sends a signal to the program - a process sends signals to itself - a user sends the USR1 signal to a program (using the a shell to send the signal) to have the program reread its configuration file w/o recycling.

  37. Common Signals: Name Value Notes Comment • There are 19 standard signals; each has associated with it a small integer and a name. Notes: A: Default is terminate process B: Default is ignore signal C: Default is terminate process and dump core D: Default is stop process E: Default is resume process F: Signal can not be caught or ignored

  38. Further Signal Comments: • We won’t use all these signals (italics) • HUP happens when a program is running in a terminal that is killed. • INT is send when someone hits ^C. • TERM and KILL used by one process (eg, shell) to terminate another. ^C sends TERM but you can disable the default behaviour by writing a TERM signal handler. • PIPE is sent when a process writes to a closed (remote end) pipe or socket. • ALRM used with alarm() to send a prearranged signal to yourself. • CHLD sent to parent when child process status changes (exit, stop, continue). • STOP suspends the current process; resumed by CONT. • TSTP suspends current process from tty (^Z); resumed by CONT and can be caught by your own signal handler.

  39. Catching Signals: • %SIG holds references all signal handlers (functions). • You catch a signal yourself by assigning a value to any signal except $SIG{KILL} and $SIG{TERM}. This value references a small function. $SIG{INT} references the current/default INT signal handler

  40. Example: #!/usr/bin/perl #file: interrupt.pl use strict; my $interruptions = 0; $SIG{INT} = \&handle_interruptions; while ($interruptions < 3) { print “I am sleeping.\n”; sleep(5); # blocks for 5 seconds } sub &handle_interruptions { $interruptions++; warn “Don’t interrupt me. You’ve already interrupted \ me ${interruptions}x.”; } replaces default behaviour (terminate) with pedantic counter this is a real/named subroutine. You can also use an anonymous subroutine (see next slide). you need the {} because you can’t write $interruptionsx.

  41. Anonymous Subroutine: $SIG{INT} = sub {$interruptions++; warn “Don’t interrupt me. You’ve already interrupted \ me ${interruptions}x.”; };

  42. Special Cases: • Perl recognizes two special values for an interrupt handler – DEFAULT and IGNORE. • DEFAULT restores the default behaviour • IGNORE tells perl to ignore this signal if received.

  43. Handler Reuse: $SIG{TERM} = $SIG{HUP} = $SIG{INT} = \&handler; sub &handler { my $sig = shift; warn “handling a $sig signal.\n”; } The signal number is obviously passed automatically to any signal handler as its first argument.

  44. PIPE Exceptions 1: #!/usr/bin/perl #file: write_ten_ph.pl use strict; $SIG{PIPE} = sub { undef $ok; } open(PIPE,”| read_three.pl”) or die “Can’t open pipe: $!”; select PIPE; $| = 1; select STDOUT; my $count = 0; for ( $_ = 1; $ok && $_ <= 10; $_++) { warn “Writing line $_\n”; print PIPE “This is line number $_\n”; $count++; sleep 1; # or select(undef,undef,undef,0.5) } close PIPE or die “Can’t close PIPE: $!”; print “Write $count lines of text\n”; Now when read_three.pl closes, instead of terminating write_ten_ph.pl the loop terminates gracefully (no Broken pipe message).

  45. PIPE Exceptions 2: #!/usr/bin/perl #file: write_ten_i.pl use strict; $SIG{PIPE} = ‘IGNORE’; open(PIPE,”| read_three.pl”) or die “Can’t open pipe: $!”; select PIPE; $| = 1; select STDOUT; my $count = 0; for ( 1..10) { warn “Writing line $_\n”; if (print PIPE “This is line number $_\n”) { $count++; } else { warn “An error occurred during writing: $!”; last; # break out of loop } sleep 1; # or select(undef,undef,undef,0.5) } close PIPE or die “Can’t close PIPE: $!”; print “Write $count lines of text\n”; Now when read_three.pl closes, instead of terminating write_ten_i.pl the loop terminates gracefully (we see Broken pipe message only because we ask to) by checking if the print() function failed.

  46. Exceptions 3: • What if we wanted to handle the Broken pipe error separately from all other errors print() could return? use Errno ‘:POSIX’; . . . unless (print PIPE “This is line number $_\n”) { last if $! == EPIPE; # break out of loop if Broken pipe die “IO error: $!”; # all other possible errors } numeric value only available if we import Errno ‘:POSIX’ or Errno qw(EPIPE)

  47. Sending Signals: you can send the signal to a list of processes but only if you have a right to do so – same user privileges or root can kill anything. • From a process: • Special kill signals: $count = kill($signal, @processes); number of processes successfully signaled you can use signal numbers or symbol names $count = kill(0,@processes); returns the number of processes from list which could receive a signal but no signal is sent $count = kill(-n,@processes); kill treats abs(n) as a process group ID an delivers signal to all processes in the group

  48. Sending signals 2: • Commiting suicide: kill INT => $$ ; # same as kill(‘INT’,$$)

  49. Caveats: • What if you are doing something important or executing a system() or other system command when a signal arrives? • keep it simple ($g_var = 1;) and handle the heavy lifting back in the main program • don’t do IO inside a handler (strip out warn() in production) • ok to call die() or exit() in a handler since you are exiting anyway but NOT on a Windows machine • In 2001 Windows only implemented a minimal set of signal handlers – CHLD was not implemented, for example.

  50. Timing out slow system calls: • If a signal occurs while perl is executing a slow system call, the handler is executed and the system call is restarted at the point it left off. • Some slow system calls don’t restart however; sleep() for example. $slept = sleep([$seconds]); sleeps $seconds or until signal received; sleeps forever if no argument returns how many seconds it actually slept

More Related