1 / 60

operating systems

operating systems. Processes in Unix. The Process ID. operating systems. Unix identifies each process with a unique integer called a process ID . The process that executes the request for creating a process is called the parent of the process.

hollie
Download Presentation

operating 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. operating systems Processes in Unix

  2. The Process ID operating systems Unix identifies each process with a unique integer called a process ID. The process that executes the request for creating a process is called the parent of the process. The created process is called the child process.

  3. operating systems Getting the Process ID #include <stdio.h> #include <sys/types.h> #include <unistd.h> int main ( ) { printf(“Process ID: %ld\n”, (long)getpid()); printf(“Parent process ID: %ld\n”, (long)getppid()); printf(“Process owner ID: %ld\n”, (long)getuid()); exit (0); } ex1.c

  4. operating systems Process Termination • Normal Termination • return from main • calling exit • calling _exit • Abnormal Termination • calling abort • terminated by a signal calls exit cleans up, closes all files leaves files open, does not flush buffers

  5. operating systems The atexit function ANSI C allows us to register up to 32 functions that are automatically called by exit( ). int atexit (void (*func) (void));

  6. User Process exit handler _exit user functions call & return return call call & return exit handler exit( ) main( ) _exit call & return return call C start-up routine I/O cleanup _exit exec Kernel

  7. operating systems More Process Termination When a process terminates, the operating system de-allocates the resources held by the process, and notifies other processes of its demise. When a process exits, its orphaned children are adopted by the init*process. If it’s parent process is not waiting for it when it terminates, it becomes a zombie process. * launchd on OS-X (do ps –ax)

  8. operating systems Process Creation Using fork( ) makes a copy of the parent’s system image and begins executing at the currentinstruction child process gets a copy of the parent’s data space, heap and stack. They do not share memory! The fork() call returns 0 to the child process, and the pid of the child to the parent process. Whether the parent or the child executes first, once the child is created, depends upon the scheduling algorithm used by the kernel.

  9. operating systems * Children Also Inherit user and group IDs controlling terminal current working directory root directory file mode creation masks all open file descriptors signal mask and dispositions environment attached shared memory segments resource limits * Keep in mind that the child process does not share these, but has copies of its own that it inherits from the parent.

  10. operating systems Children Are Different Because … They return a different value from fork They have different process IDs They have different parent process IDs The child does not inherit file locks set by the parent The set of pending signals for the child is set to the empty set

  11. Try the following code #include <stdio.h> #include <unistd.h> int main ( ) { int x; x = 0; fork( ); x = 1; printf(“I am process %ld and my x value is %d\n”, (long)getpid( ), x); return 0; } What happened? fork.c

  12. Try the following code #include <stdio.h> #include <unistd.h> int main ( ) { int x; x = 0; fork( ); x = 1; printf(“I am process %ld and my x value is %d\n”, (long)getpid( ), x); return 0; } At this point, there is one process.

  13. Try the following code #include <stdio.h> #include <unistd.h> int main ( ) { int x; x = 0; fork( ); x = 1; printf(“I am process %ld and my x value is %d\n”, (long)getpid( ), x); return 0; } A child process is created. It has the identical code and execution environment as the parent. fork.c

  14. Try the following code #include <stdio.h> #include <unistd.h> int main ( ) { int x; x = 0; fork( ); x = 1; printf(“I am process %ld and my x value is %d\n”, (long)getpid( ), x); return 0; } Both processes now execute this code, changing its own value of x, printing it, and exiting. The order depends on the scheduler.

  15. Try the following code #include <stdio.h> #include <unistd.h> int main ( ) { int x; x = 0; fork( ); x = 1; printf(“I am process %ld and my x value is %d\n”, (long)getpid( ), x); return 0; } Could the child process do something different from the parent process?

  16. Yes ... test the return value of the fork( ) #include <stdio.h> #include <unistd.h> int main ( ) { int x; pid_t childpid; x = 0; childpid = fork( ); if ( childpid == -1) { perror(“failed to fork a new process”); return 1; } fork1.c

  17. if (childpid == 0) { x = 1; printf(“I am the child, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } else { x = 2; printf(“I am the parent, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } return 0; } What happened?

  18. Both processes return here from the fork( ) call. However, the return value to the parent is the pid of the child process. The return value to the child is zero. if (childpid == 0) { x = 1; printf(“I am the child, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } else { x = 2; printf(“I am the parent, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } return 0; }

  19. if (childpid == 0) { x = 1; printf(“I am the child, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } else { x = 2; printf(“I am the parent, my ID = %ld, my x = &d\n”, (long)getpid( ), x); } return 0; } The child process executes this block, And ... the parent process executes this block

  20. operating systems What does this code do? int main(int argc, char *argv[ ] ) { pid_t childpid = 0; int i, n; n = atoi ( argv[1] ); for ( i = 1; i < n; i++) if (childpid = fork( ) ) break; fprintf(stderr, “i:%d process ID:%ld parent ID: %ld child ID %ld\n”, i, (long)getpid( ), (long)getppid( ), (long)childpid ); return 0;

  21. Creates a Chain of Processes operating systems int main(int argc, char *argv[ ] ) { pid_t childpid = 0; int i, n; n = atoi ( argv[1] ); for ( i = 1; i < n; i++) if (childpid = fork( ) ) break; fprintf(stderr, “i:%d process ID:%ld parent ID: %ld child ID %ld\n”, i, (long)getpid( ), (long)getppid( ), (long)childpid ); return 0; process 1 process 2 // non zero means I’m the parent process 3 the parent breaks out of the loop … the child continues through the loop one more time, forks a new child process and becomes the parent for the next iteration. process 4 a chain for n = 4 chain.c

  22. Creating a fan of processes operating systems int main(int argc, char *argv[ ] ) { pid_t childpid = 0; int i, n; n = atoi ( argv[1] ); for ( i = 1; i < n; i++) if (childpid = fork( ) <= 0 ) break; fprintf(stderr, “i:%d process ID:%ld parent ID: %ld child ID %ld\n”, i, (long)getpid( ), (long)getppid( ), (long)childpid ); return 0; parent process child 3 child 1 child 2 the child breaks out of the loop … the parent continues through the loop creating a new child. This continues until the loop condition is satisfied.

  23. Run the example fan1.c a few times. What do you notice about the output? The order of the output is not in the order expected. This is because the parent just exits when it is done, the children may not have finished at this point. The order of execution depends upon how the processes were scheduled to run. Can we make the parent wait to exit until all of its children have finished?

  24. operating systems The wait( ) System Call • When a fork ( ) occurs, both the parent and the child proceed • with execution at the point of the fork. • If the parent wants to wait for the child to finish before • continuing, it executes a wait( ). wait() causes the caller to • stop until • the child terminates, or • the caller receives a signal • wait( ) returns immediately if there are no children executing • the return value of wait() is: • the pid of the terminating child process, or • -1 if there is no child to wait for or a signal occurred • errno = ECHILD indicates there was no child • errno = EINTR indicates there was a signal

  25. #include <sys/types.h> #include <sys/wait.h> pid_t wait (int *status); operating systems returns -1 or pid of the terminating child. the return status of the child is stored in status. Test with the macros WIFEXITED - true if child terminated normally WIFSIGNALED – true if child terminated abnormally because it failed to catch a signal WIFSTOPPED - true if a child is currently stopped

  26. operating systems Handling a wait that is interrupted by a signal #include <errno.h> #include <sys/wait.h> pid_t r_wait (int* status_loc) { int retval; while ( ( (retval = wait(status_loc) ) == -1 && (errno == EINTR) ); return retval; } if the wait returns because of a signal, stay in this loop

  27. Fixing the fan program . . . n = atoi(argv[1]); for (i = 1; i < n; i++) if ( (childpid = fork( ) ) <= 0) break; while (r_wait(NULL) > 0); fprintf(stderr, ... ) see fan2.c

  28. Fixing the fan program . . . n = atoi(argv[1]); for (i = 1; i < n; i++) if ( (childpid = fork( ) ) <= 0) break; while (r_wait(NULL) > 0); fprintf(stderr, ... ) what happens if you replace the while statement with r_wait(NULL); see fan2.c

  29. How many outputs are possible from this program? int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; }

  30. int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; } 1. The fork fails, the program will output “failed to fork”

  31. child code parent code int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; } 2. The child prints its message, but then the parent catches a signal before the child actually returns. I am a child 3427 a signal may have interrupted this call

  32. child code parent code int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; } 3. The child prints its message and returns. The wait returns normally I am a child 3427 I am a parent 3424

  33. child code parent code int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; } 4. The parent catches a signal and prints its “signal” message before the child prints its message. A signal may have interrupted the call I am child 3427

  34. child code parent code int main ( ) { pid_t childpid; childpid = fork( ); if (childpid == -1) { perror(“failed to fork”); return 1; } if (childpid == 0) fprintf(stderr, I am a child %ld\n”, (long)getpid( ) ); else if (wait(NULL) != childpid) fprintf(stderr, “A signal may have interrupted the wait\n”); else fprintf(stderr, I am a parent %ld\n”, (long)getpid( ) ); return 0; } 5. The parent catches a signal before the child prints its message, but it prints its “signal” message after the child prints. I am child 3427 A signal may have interrupted this call

  35. Status Values The status parameter of the wait( ) system call is an int* If it is not NULL, the return status of the child is stored in the integer variable pointed to. The child status is returned by return n exit (n) A zero value indicates that the child process exited normally.

  36. Keep in mind that the wait( ) system call blocks if there are any child processes executing. What if we want to see if a child process has terminated, but not block?

  37. operating systems waitpid pid_t waitpid (pid_t pid, int *stat_loc, int options); the process to be waited for, or -1 if you want to wait for any child process to finish. the interesting option is WNOHANG which causes waitpid to return even if there is there is no child for which status is available. returns the pid of the child or -1 if there is an error, or 0 if there are children to be waited for, but none of them are done

  38. operating systems #include <sys/types> #include <sys/wait.h> #include <errno.h> int status; pid_t waited_for_pid; … while (waited_for_pid = waitpid (-1, &status, WNOHANG) ) if ((waited_for_pid == -1) && (errno != EINTR) break; this code segment waits for any child, without blocking, if there are no children with status available. It stays in the loop if the waitpid is interrupted by a signal.

  39. Waiting for a Parent to Finish operating systems A parent can wait for a child to finish by using the wait or waitpid calls. However, what does a child do when it wants to wait for the parent to finish? while (getppid( ) != 1) sleep(1); why? this type of code is called polling, and burns up cpu time To avoid race conditions and polling, we use signals

  40. operating systems Zombies If a child process completes before its parent does, some vestige of the process has to hang around so that the parent can determine its termination status with a wait( ). This is called a zombie process.

  41. operating systems Orphans What happens if the parent process exits before its child process does. The child has to have a parent, so it is adopted by the init process.

  42. operating systems Forks Are Used When a process wants to duplicate itself so that the parent and the child can execute different parts of the program simultaneously. This is common for server software. When a process wants to execute a different program. This is common for shells.

  43. operating systems exec( ) fork ( ) – creates a copy of the calling process. exec ( ) – overlays the calling process with a new process. Traditional approach is for the parent to fork( ) a new process, which then does an exec to overlay the process with the new program. The parent then stays around. The exec copies a new executable into the process image. The program text, variables, stack, and the heap are overwritten.

  44. Process B program A fork( ); rhtj,nn vio nlk;jh eahg jkfsdajhfk.ADFSkfdnkZX dfjklA:LDhlADjlkd fakJLc dsakl;naS hlhkasf jghji fhnjkjsdf fdsnjhkjsd fht9 hjfhksa } jkds,n,ds mkfl jmhjsd fhjsdf ‘jkfg { kjl;sdfdsf fdsjklsdf rhtj,nn vio nlk;jh eahg jkfsdajhfk.ADFSkfdnkZX dfjklA:LDhlADjlkd fakJLc dsakl;naS fork( ); { exec( ); ‘ fdsnjhkjsd } hjfhksa } jkds,n,ds mkfl jmhjsd fhjsdf ‘jkfg { kjl;sdfdsf fdsjklsdf exec( ) Process A program A rhtj,nn vio nlk;jh eahg jkfsdajhfk.ADFSkfdnkZX dfjklA:LDhlADjlkd fakJLc dsakl;naS fork( ) { exec( ) ‘ fdsnjhkjsd } hjfhksa } jkds,n,ds mkfl jmhjsd fhjsdf ‘jkfg { kjl;sdfdsf fdsjklsdf program C

  45. operating systems execl( ) This family of functions is useful when the number of command line arguments is known at compile time first command line argument second command line argument #include <unistd.h> int execl(const char *path, const char *arg0, const char *arg1, … const char *argn, NULL); A NULL pointer final command line argument path to the executable

  46. Example int main ( ) { pid_t childpid; int stat; if ((childpid = fork() == -1) { perror(“Error in fork.”); exit(1); } else if (childpid == 0) { if (execl(“/bin/ls”, “ls”, “-l”, NULL) < 0) { perror(“Error in exec.”); exit(1); } } else if (childpid != wait(&stat)) { perror(“A Signal occurred before the child exited.”); exit(1); } return (0); } operating systems This is child code. It replaces the current process with /bin/ls This is parent code. dols.c

  47. operating systems Variations of execl( ) #include <unistd.h> int execlp(const char *file, const char *arg0, const char *arg1, … , const char *argn, NULL); int execle (const char *path, const char *arg0, const char *arg1, …, const char argn, NULL, char *const envp[]); This variation uses the PATH environment variable to locate the executable This variation passes a pointer to an array of strings that holds a new environment for the command.

  48. execv( ) operating systems This family of functions is used to pass command line arguments to the new process #include <unistd.h> int execv(const char *path, char *const argv[]); an argument array, just as if these had come from the command line . You have to build this! path to the executable execv also has execvp and execve variations.

  49. create the executable myexec. Then typing myexec ls –l will result in this function calling ls -l int main (int argc, char *argv[]){ pid_t childpid; int status; if ((childpid = fork()) == -1) { perror("The fork failed"); exit(1); } else if (childpid == 0) { if (execvp(argv[1], &argv[1]) <0) { perror("The exec failed"); exit(1); } } else { while(childpid != wait(&status)) { if ((childpid == -1) && (errno != EINTR)) break; } } return (0);} operating systems argv[0] is the first argument when this command is executed, so &argv[1] points to the two tokens ls and -l execvp constructs the pathname using the PATH environment variable. the parent waits for the child to terminate.

  50. operating systems A Shell is a command interpreter which prompts for commands, reads the commands from standard input, forks children to execute the commands, and waits for the children to finish. When you end a command with &, the shell creates the child process, but does not wait for it to finish. The child is known as a background process.

More Related