Presentation is loading. Please wait.

Presentation is loading. Please wait.

Processes 1: Fork & Exec CS 360 proc1. Page 2 proc1 CS 360, WSU Vancouver Agenda What are processes? Creating a process Miscellaneous details Tiny shell.

Similar presentations


Presentation on theme: "Processes 1: Fork & Exec CS 360 proc1. Page 2 proc1 CS 360, WSU Vancouver Agenda What are processes? Creating a process Miscellaneous details Tiny shell."— Presentation transcript:

1 Processes 1: Fork & Exec CS 360 proc1

2 Page 2 proc1 CS 360, WSU Vancouver Agenda What are processes? Creating a process Miscellaneous details Tiny shell example Wrap-up T his week we begin learning about Unix processes - independently running programs

3 Page 3 proc1 CS 360, WSU Vancouver What Are Processes?

4 Page 4 proc1 CS 360, WSU Vancouver Layered Architecture Kernel: essential basic services 4 only one kernel 4 general Libraries: useful additional services 4 many libraries 4 specific Programs: executable files 4 numerous & specific Shell: command line environment 4 few & powerful Users: humans users shell programs unix libraries unix kernel

5 Page 5 proc1 CS 360, WSU Vancouver The Two Unix Building Blocks Files - storage areas on disk store data Processes - running programs in memory manipulate data

6 Page 6 proc1 CS 360, WSU Vancouver What Is a Process? An instance of an executing program A fundamental computer science concept and powerful coding technique program bits a file a process independent computations interact via messages

7 Page 7 proc1 CS 360, WSU Vancouver % factor 19384779834734444128792384733311159 & % echo hello hello % ps PID TTY S TIME CMD 23122 ttyp1 I 0:00.17 -ksh (ksh) 24849 ttyp1 I + 0:00.04 vi pipe2.c 23793 ttyp2 S 0:00.05 factor % kill 23793 Examples of Processes 1 Start a "background" process: Notes: 4 "pid" = "process id" (an integer) 4 a process can be in one of several states: –runningactually has machine –sleepingready to run, but waiting for turn –idlesleeping for more than 20 seconds –waitingwaiting for an event (such as disk I/O) –zombieended, but parent has not yet received notification –...

8 Page 8 proc1 CS 360, WSU Vancouver Pipe together several processes: % tr " " "\n" | sort | uniq print unique words tr " " "\n" stdin sortuniq stdout process 2process 1process 3 buffer new stdout 1new stdin 2new stdout 2new stdin 3 Examples of Processes 2 simple, powerful Notes: 4 each process has it's own independent existence 4 each process runs asynchronously 4 they can communicate only in limited ways (pipes, signals,...) 4 they will wait when stdin pipe is not yet ready, or stdout pipe is full

9 Page 9 proc1 CS 360, WSU Vancouver Examples of Processes 3 Graphics server: program 1 program 2 program 3 graphics server workstation screen Web server: server disk web server machine 1 machine 2 one machine many machines

10 Page 10 proc1 CS 360, WSU Vancouver Key Process Routines Creating: 4 how to create a processfork, exec, wait Communicating: 4 how to read/write between processes pipe, dup, sockets Controlling: 4 how to cause and handle exceptionssignal, alarm Scripting: 4 how to use the shell from a programsystem, popen key routines We won't cover: administrationprocess groups, sessions, terminals, job control advanced commIPC flavors accountingpriorities, resources, accounting error handlingsetjmp, longjmp today's topic everything else next week

11 Page 11 proc1 CS 360, WSU Vancouver Creating Processes

12 Page 12 proc1 CS 360, WSU Vancouver Process = Image + Context Process 1 image context Process n image context... key addresses current instruction counter (IC) stack pointer (SP) frame pointer (FP) heap bottom, stack bottom, etc. register values scheduling priority process id's (me & parent) user & group id's file descriptors 0:... 1:... 2:... current working directory aka "thread" data heap  stack avail aka "address space" 000...... fff shell stuff "text""bss" typical layout kernel loads un-initialized data code environment variables

13 Page 13 proc1 CS 360, WSU Vancouver How Do We Create a Process? As we have seen, a process is a very complicated thing We might expect a complicated way to create a process Is there a simple way to avoid this complexity?

14 Page 14 proc1 CS 360, WSU Vancouver To Create a Process, Clone an Existing Process Then the new process modifies itself gradually using the usual kernel routines (open,...). a general principle: create complex objects simply by copying an existing object 1. "parent" 3. "child" 2. "clone"

15 Page 15 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: step 2: step 3: step 4: step 5: single process parent processchild process two independent processes two independent processes

16 Page 16 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: step 2: parent processchild process step 3: step 4: step 5:

17 Page 17 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: step 3: step 4: step 5: parent processchild process

18 Page 18 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created step 3: step 4: step 5: clone image & clone context (stdin, stdout,...) parent processchild process

19 Page 19 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: step 4: step 5: two asynchronous processes parent processchild process

20 Page 20 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: if statement chooses a "parent path" if statement chooses a "child path" step 4: step 5: two asynchronous processes parent processchild process

21 Page 21 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: if statement chooses a "parent path" if statement chooses a "child path" step 4: compute something...compute something else... step 5: parent processchild process

22 Page 22 proc1 CS 360, WSU Vancouver "Fork": Clones a Process step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: if statement chooses a "parent path" if statement chooses a "child path" step 4: compute something...compute something else... step 5: cloned image & cloned context (stdin, stdout,...) completely independent parent processchild process

23 Page 23 proc1 CS 360, WSU Vancouver #include int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); } The Parent and Child are Duplicates fork1.c % fork1 *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child program codeprogram behavior make sure you understand this fork returns twice!

24 Page 24 proc1 CS 360, WSU Vancouver Again: The Parent and Child are Duplicates parent processprogram behavior int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); } child process  int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); } int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); } process is cloned; fork returns new pid in original, 0 in clone   int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); }   int main (int argc, char *argv[]) { char *who; int i; if (fork ()) { who = "parent"; } else { who = "child"; } for (i = 0; i < 6; i++) { printf ("*fork1: %s\n", who); } exit (0); } % fork1 *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child *fork1: parent *fork1: child

25 Page 25 proc1 CS 360, WSU Vancouver Execution Is Asynchronous #include int main (int argc, char *argv[]) { int i; /* loop counter */ char *who; /* name of process */ int n; /* seconds to sleep */ if (fork ()) { who = "parent"; n = 2; } else { who = "child"; n = 1; } for (i = 1; i <= 10; ++i) { fprintf (stdout, "*%2d. %7s: my pid = %6d, ppid = %6d\n", i, who, getpid (), getppid ()); fflush (stdout); sleep (n); } exit(0); } fork2.c % fork2 * 1. parent: my pid = 11597, ppid = 7125 * 1. child: my pid = 10843, ppid = 11597 * 2. child: my pid = 10843, ppid = 11597 * 2. parent: my pid = 11597, ppid = 7125 * 3. child: my pid = 10843, ppid = 11597 * 4. child: my pid = 10843, ppid = 11597 * 3. parent: my pid = 11597, ppid = 7125 * 5. child: my pid = 10843, ppid = 11597 * 6. child: my pid = 10843, ppid = 11597 * 4. parent: my pid = 11597, ppid = 7125 * 7. child: my pid = 10843, ppid = 11597 * 8. child: my pid = 10843, ppid = 11597 * 5. parent: my pid = 11597, ppid = 7125 * 9. child: my pid = 10843, ppid = 11597 *10. child: my pid = 10843, ppid = 11597 * 6. parent: my pid = 11597, ppid = 7125 * 7. parent: my pid = 11597, ppid = 7125 * 8. parent: my pid = 11597, ppid = 7125 * 9. parent: my pid = 11597, ppid = 7125 *10. parent: my pid = 11597, ppid = 7125 program codeprogram behavior unpredictable interleaving sleep n seconds

26 Page 26 proc1 CS 360, WSU Vancouver "Exec": Loads a Program step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: if statement chooses a "parent path" if statement chooses a "child path" step 4: compute something step 5: step 6: new steps parent processchild process

27 Page 27 proc1 CS 360, WSU Vancouver "Exec": Loads a Program step 1: execute "fork ()" step 2: complete parent state is cloned...... and child is created fork returns pid of childfork returns 0 step 3: if statement chooses a "parent path" if statement chooses a "child path" step 4: compute something overlay with new image from an executable file step 5: cloned image & cloned context (stdin, stdout,...) new image (but stdin etc. not changed) wait for child to complete step 6: exit with status code parent processchild process

28 Page 28 proc1 CS 360, WSU Vancouver You Can Exec a Program #include int main (int argc, char *argv[]) { char *who; int status; if (fork ()) { who = "parent"; printf ("pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/usr/bin/date", "date", (char *)0); } exec1.c % exec1 pi=3.141593 Fri Feb 19 17:11:16 PST 1999 program code program behavior exec doesn't return! wait for child to exit overlays with new image preserves most of context (e.g.: open file descriptors) asynchronous execution

29 Page 29 proc1 CS 360, WSU Vancouver Again: You Can Exec a Program program behavior  parent process if (fork ()) { who = "parent"; printf ("pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/usr/bin/date", "date", (char *)0); } % exec1 pi=3.141593 Fri Feb 19 17:11:16 PST 1999 if (fork ()) { who = "parent"; printf ("pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/usr/bin/date", "date", (char *)0); } /usr/bin/date: argc: 1 argv[0]: "date" argv[1]: NULL exec exit same stdout     poof! overlay! clone! poof! child process if (fork ()) { who = "parent"; printf ("pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/usr/bin/date", "date", (char *)0); } if (fork ()) { who = "parent"; printf ("pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/usr/bin/date", "date", (char *)0); } fork

30 Page 30 proc1 CS 360, WSU Vancouver Exec Issues Why does the "date" output appear on the terminal? Is that output guaranteed to follow the parent output? What would happen to the parent if the child did this...? close (1); What if the child closed 0 and then did an open? What if the child did another exec? What if the parent process exited before the child? What is the output from this program?... printf ("a"); if (fork ()) { printf ("b"); } else { printf ("c"); } exit (0);... % foo foo.c

31 Page 31 proc1 CS 360, WSU Vancouver You Can Also Exec a Script program code #include int main (int argc, char *argv[]) { char *who; int status; if (fork ()) { who = "parent"; printf pi=%f\n", 4*atan(1)); wait (&status); exit (0); } else { who = "child"; execlp ("/bin/my-script", "my-script", "a", "b", (char *)0); } exec2.c #! /bin/ksh echo "*my-script: argv[1]=$1 argv[2]=$2" /bin/my-script % exec2 pi= 3.141593 *my-script: argv[1]=a argv[2]=b program behavior pathname of script which shell to use

32 Page 32 proc1 CS 360, WSU Vancouver "Fork" and "Exec" Synopsis Exec = start new program: 4 $PATH is searched to resolve the filename –can resolve to a program or a script (shell used in that case) 4 image of current process is replaced; can only return if that fails 4 most of context preserved (stdin/stdout/stderr, pid, uid, gid, cwd, getenv,...) 4 but: stdio buffers not flushed (use fflush or fclose before the exec) execlp (filename, argv0, argv1,..., (char *)0); execvp (filename, argv); final execvp argv must be NULL Fork = create new process: 4 returns twice: with 0 in child; with a new pid in parent 4 both child & parent continue with duplicated image & context –however, parent of child == parent (not the parent's parent) 4 child completes via "exit(status)"; parent can "wait" on child completion 4 processes can also "signal" each other (more next week) if ((child-pid = fork ()) != 0) { parent-code } else { child-code }

33 Page 33 proc1 CS 360, WSU Vancouver Some Miscellaneous Details

34 Page 34 proc1 CS 360, WSU Vancouver Environment Variables Shell makes "environment variables" available to your program: % export FOO="something important" % doit FOO is something important... char *foo; foo = getenv ("FOO"); if (foo == NULL) foo = "undefined"; printf ("FOO is %s\n", foo);... doit.c NULL if "FOO" not exported Notes: 4 by convention environment variables are all upper case 4 the shell always sets several useful variables: PATH, HOME, LOGNAME,... 4 you can change a value via "putenv" 4 change is only "downwards" -- can't change parent's environment 4 it's possible to scan the entire environment via an array, but that is unusual

35 Page 35 proc1 CS 360, WSU Vancouver A Real Example: Tiny Shell the TSH icon See the process routines in action and understand more about how a shell works

36 Page 36 proc1 CS 360, WSU Vancouver Our Tiny Shell is a Subset of the Full Shell Tsh is a real shell: % tsh ? echo "hello, world!" hello, world ? ls -l -rwxrwxrwa 1 0 0 2689 Feb 18 12:44 main.c -rwxrwxrwa 1 0 0 47 Feb 17 22:59 makefile.txt ? cp main.c backup ? cat bar ? exit % However, command syntax is greatly simplified: 4 single line commands from stdin (no line continuation or semi-colons) 4 arguments are words or strings (with either " or ' quotes) 4 I/O redirection only for stdin and stdout; no pipes 4 no substitutions ($, ~, *,...) 4 simple program invocation only (no scripts, no control structures, no arithmetic) 4 foreground operation only (no ampersands)

37 Page 37 proc1 CS 360, WSU Vancouver Tsh Overall Logic various includes, defines, externs tsh.h main (...) { repeat until eof or exit command: get command line into a string area (see get.c) parse command into argc, argv and redirect [0..1](see parse.c) exec command using argc, argv and redirect (see exec.c below) note: exec command returns 0 if the command was an exit, else 1 } main.c int exec_command (int argc, char *argv[], char *redirect[]) { handle the built-in commands (exit & cd) specially otherwise, call exec_program to do the work (see prog.c) return 0 if did an "exit", else return 1 exec.c int exec_program (int argc, char *argv[], char *redirect[]) { fflush (stdout) fork if I am the child: redirect stdin & stdout as needed using redirect [0..1](see redirect.c) make argv[argc] = 0 execvp (argv[0], argv) if execvp returns, complain to stderr and terminate myself else I am the parent: wait for child process to terminate return the exit status (which exec-command currently ignores) prog.c list of all files: tsh.h main.c, get.c, parse.c, misc.c exec.c, prog.c, redirect.c

38 Page 38 proc1 CS 360, WSU Vancouver /* standard includes... */ #include /* defines and variables... */ #define VERSION "v7"/* version number */ #define MAX_LENGTH1024/* max length of a command line */ #define MAX_ARGC 50/* max number of args */ #define PROMPT "? "/* command prompt */ /* command routines... */ extern int get_command (char *cmd, int max_length); extern int parse_command (char *argv[], int max_argc, char *redirect[], char *cmd); extern int exec_command (int argc, char *argv[], char *redirect[]); extern int exec_program (int argc, char *argv[], char *redirect[]); extern void redirect_stdin (char *pathname); extern void redirect_stdout (char *pathname); /* misc routines (see misc.c for details)... */ extern void initialize (int argc, char *argv[]); extern int complain (char *message, void *value); /* fprintf to stderr; returns 0 */ extern int verify (char *argv[], int argc, int min, int max); /* min <= argc <= max */ /* debugging... */ extern int debug; /* initialized in misc.c */ #define trace if (debug) printf The Header File tsh.h main routines helper routines

39 Page 39 proc1 CS 360, WSU Vancouver #include "tsh.h" int debug = 0; /********************************************************************** main: Usage: tsh [-d] **********************************************************************/ int main (int main_argc, char *main_argv[]) { /* declare variables */ char cmd[MAX_LENGTH];/* command line area */ char *argv[MAX_ARGC+1];/* args found in cmd */ int argc;/* number of args found */ char *redirect[2];/* filenames for stdin/stdout or null */ int more;/* when 0, command loop below ends */ /* process command line and get ready */ initialize (main_argc, main_argv); /* get, parse, and execute commands until eof or "exit" command */ more = 1; while (more && get_command (cmd, MAX_LENGTH)) { argc = parse_command (argv, MAX_ARGC, redirect, cmd); more = exec_command (argc, argv, redirect); } /* exit */ exit (0); } main.c The Main Routine environment main loop

40 Page 40 proc1 CS 360, WSU Vancouver #include "tsh.h" /********************************************************************** get_command: Prompt and read command. Complain and ignore lines that are longer than max_length. Return 0 if eof. **********************************************************************/ int get_command (char *cmd, int max_length) { /* declare variables */ int eof, c; /* prompt user for a command */ fputs (PROMPT, stdout); /* read one line into cmd area */ eof = (fgets (cmd, max_length, stdin) == NULL); /* complain if line was truncated; and if so, ignore the entire command */ if (!eof && (cmd[strlen(cmd)-1] != '\n')) { complain ("line longer than %d\n", (void *) max_length); while (c = fgetc (stdin), c != '\n' && c != EOF) {}; /* ignore rest of line */ cmd[0] = '\0'; /* make command empty */ } /* return with true if not eof */ return !eof; } Get_Command get.c prompt and then read command line

41 Page 41 proc1 CS 360, WSU Vancouver Parse_Command Source omitted:  breaks cmd into argv and returns argc 4 understands single and double quotes  redirect[0] is a pathname if there is a '<', else null  ditto redirect[1] for '>' #include "tsh.h" #include /***************************************************************************** parse_command : Parse cmd into argv and redirect. Return argc (0 if errors or empty cmd). *****************************************************************************/ int parse_command (char *argv[], int max_argc, char *redirect[], char *cmd) {... } parse.c argc:4 argv[0]:"ls" argv[1]:"-l" argv[2]:"foo.c" argv[3]:"bar.c" cmd:"ls -l foo.c bar.c > /tmp/listing\n" redirect[0]:0 redirect[1]:"/tmp/listing" note the 0 Example:

42 Page 42 proc1 CS 360, WSU Vancouver #include "tsh.h" /********************************************************************** exec_command : Execute a single command per argv[0..argc-1] and redirect[0..1]. Command is built-in or a program. Return 1 (0 if command was "exit"). **********************************************************************/ int exec_command (int argc, char *argv[], char *redirect[]) { /* declare variables */ int result, status; /* execute the command and set result */ if (argc <= 0) { result = 1; /* empty command; keep going */ } else if (strcmp (argv[0], "exit") == 0) { result = 0; /* exit command; stop the tsh */ } else if (strcmp (argv[0], "cd") == 0) { if (verify (argv, argc, 1, 2)) { if (argc == 1) argv[1] = getenv ("HOME"); if (chdir (argv[1]) < 0) complain ("can't cd to %s", argv[1]); } result = 1; /* keep going */ } else { status = exec_program (argc, argv, redirect); result = 1; /* keep going */ } /* return result */ return result; } Exec_Command exec.c exec a program built-in: empty, "exit" and "cd" commands

43 Page 43 proc1 CS 360, WSU Vancouver #include "tsh.h" #include /********************************************************************** exec_program: Execute a program per argv[0..argc-1] and redirect[0..1]. Return exit status. **********************************************************************/ int exec_program (int argc, char *argv[], char *redirect[]) { /* declare variables */ pid_t child;/* child process pid or 0 */ int status;/* child process exit status */ /* fork into child and parent processes */ fflush (stdout); if ((child = fork ()) != 0) { /* this is the parent: wait for child to end */ wait (&status); return status; } else { /* this is the child: overlay with another program */ if (redirect[0] != NULL) redirect_stdin (redirect[0]); if (redirect[1] != NULL) redirect_stdout (redirect[1]); argv[argc] = NULL; execvp (argv[0], argv); complain ("can't execvp %s", argv[0]); exit (1); } Exec_Program prog.c fork, change stdin/stdout as needed, then exec the program flush and fork

44 Page 44 proc1 CS 360, WSU Vancouver #include "tsh.h" #include /********************************************************************** redirect routines: Close and then reopen file descriptor 0 or 1. Exit if errors. **********************************************************************/ void redirect_stdin (char *pathname) { int fd; close (0); fd = open (pathname, O_RDONLY); if (fd < 0) { complain ("can't open %s as stdin", pathname); exit (1); } void redirect_stdout (char *pathname) { int fd; close (1); fd = open (pathname, O_WRONLY|O_TRUNC|O_CREAT, 0666); if (fd < 0) { complain ("can't open %s as stdout", pathname); exit (1); } Exec_Redirect redirect.c we exploit the "lowest avail" file descriptor logic of "open" why do we exit when there is an error?

45 Page 45 proc1 CS 360, WSU Vancouver Discussion The full source is posted in /encs_share/cs/class/cs360/src/tsh Worth examination 4 see how a medium-sized program is structured 4 see how debugging routines are used in source  if adventurous, read " parse.c "  invoke tsh with debugging switch (-d) to see detailed operation Areas for improvement: 4 built-in commands 4 semicolons 4 pipes which common commands need "built-in" handling?

46 Page 46 proc1 CS 360, WSU Vancouver Summary The concept of "process" is fundamental to both computer science and engineering A process is 4 an instance of an executing program It is implemented as 4 an image (address space) + a context (thread) Unix creates processes by cloning 4 achieves simplicity by copying a complex object, instead of creating piecemeal The key process creation routines are: 4 fork-- both image & context duplicated; returns twice 4 exec-- image replaced, most of context preserved; doesn't return 4 wait With ingenuity, you can do many things with fork/exec and wait e.g.: open file descriptors


Download ppt "Processes 1: Fork & Exec CS 360 proc1. Page 2 proc1 CS 360, WSU Vancouver Agenda What are processes? Creating a process Miscellaneous details Tiny shell."

Similar presentations


Ads by Google