Beispiel 2 - Verwandte Prozesse: fork, exec, wait
Transcription
Beispiel 2 - Verwandte Prozesse: fork, exec, wait
Beispiel 2 Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Beispiel 2 Verwandte Prozesse: fork, exec, wait Interprozesskommunikation mit Unnamed Pipes Programm ersetzen Prozess beenden Kindprozess abwarten Denise Ratasich basierend auf Slides von Daniel Prokesch IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Institut für Technische Informatik Technische Universität Wien 11. April 2016 1 Beispiel 2 Überblick Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Verwandte Prozesse Prozess beenden I Prozess erzeugen (fork) Kindprozess abwarten I Programmabbild ersetzen (exec) I Auf Beendigung eines Prozesses warten (wait) IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten 2 Beispiel 2 Prozessimage im Hauptspeicher Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Quelle: Wilfried Elmenreich - Systemnahes Programmieren; C Programmierung unter Unix und Linux. Reichardt Verlag 2007. p. 55 3 Beispiel 2 Prozesseigenschaften Linux (1) Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Zustand Running, Waiting, ... Scheduling Priorität, CPU-Zeit, ... Identifikation PID, Owner, Gruppe, ... Speicherverwaltung Pointer auf MMU Info Signale Mask, Pending Pipes File Descriptor Table Prozessverwandtschaften Parents, Siblings Ein-/Ausgaben umleiten 4 Beispiel 2 Prozesseigenschaften Linux (2) Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes Process Control Block Register, PC, Statuswort, Segmentregister, Page Table Info Kernelstack Dateideskriptorentabelle Berechtigungen, Accounting Information Timerverwaltung File Descriptor Table Interprozesskommunikation Ein-/Ausgaben umleiten Siehe: struct task_struct in sched.h 5 Beispiel 2 Prozesshierarchie Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen I Jeder Prozess hat Elternprozess I Ausnahme: Init-Prozess (init, systemd) I Jeder Prozess hat eine eindeutige ID (pid_t) I Prozesshierarchie anzeigen: pstree(1) Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten systemd-+-ModemManager---2*[{ModemManager}] |-NetworkManager-+-dhclient | ‘-2*[{NetworkManager}] |-abrt-dbus---{abrt-dbus} |-2*[abrt-watch-log] |-abrtd |-acpid |-agetty |-alsactl |-atd |-auditd-+-audispd-+-sedispatch | | ‘-{audispd} | ‘-{auditd} |-automount---7*[{automount}] |-avahi-daemon---avahi-daemon |-chronyd |-colord---2*[{colord}] |-crond |-cupsd |-dbus-daemon |-dnsmasq---dnsmasq |-firewalld---{firewalld} . . 6 Beispiel 2 Verwandte Prozesse Überblick Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes I Kindprozesse werden üblicherweise mit fork(2) erzeugt I exec(3) überschreibt das aktuelle Prozessimage mit einem neuen Prozessimage I wait(3) wartet auf die Terminierung eines Kindes File Descriptor Table Ein-/Ausgaben umleiten 7 Beispiel 2 Interface fork / exec / exit / wait Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten I fork() – erzeugt neuen (Kind-)Prozess I exec*(¨programm¨) – ersetzt image eines Prozesses durch ein neues I exit(status) – beendet Prozess I wait*(&status) – wartet auf die Beendigung eines Kindprozesses IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten 8 Beispiel 2 Prozess erzeugen fork Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Funktion fork() I Erzeugt einen neuen Prozess I Neuer Prozess ist eine identische Kopie des aufrufenden Prozesses – bis auf PID, pending signals,. . . I Erzeugender Prozess ist Elternprozess des erzeugten Kindprozesses – Prozesse sind verwandt I Beide Prozesse laufen parallel und führen dasselbe Programm aus Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten 9 Beispiel 2 Verwandte Prozesse Prozess erzeugen Vor fork() Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Nach fork() Pipes File Descriptor Table Ein-/Ausgaben umleiten 10 Beispiel 2 Prozess erzeugen fork Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I Programm ersetzen #include <unistd.h> Prozess beenden pid_t fork(void); Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Prozess erzeugen: I Unterscheidung zwischen Eltern- und Kindprozess durch den Rückgabewert -1 im Fehlerfall 0 im Kindprozess (child) >0 im Elternprozess (parent) 11 Beispiel 2 Prozess erzeugen Beispiel Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden pid_t pid = fork(); switch (pid) { case -1: (void) fprintf(stderr, "Cannot fork!\n"); exit(EXIT_FAILURE); Kindprozess abwarten case 0: // child tasks ... break; default: // parent tasks ... break; IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten } 12 Beispiel 2 Prozess erzeugen Kindprozess Eigenschaften Verwandte Prozesse Prozesseigenschaften Kindprozess erbt vom Elternprozess Prozess erzeugen I offene Dateien (gemeinsamer Zugriff!) Programm ersetzen I Dateipuffer Prozess beenden I Signalbehandlung Kindprozess abwarten I momentane Variablenwerte IPC Pipes Jedoch gilt: File Descriptor Table I Variablen sind lokal (keine Beeinflussung) Ein-/Ausgaben umleiten I Signalbehandlung kann rekonfiguriert werden I Kommunikation (IPC) via Pipes, Sockets, Shared Memory,. . . 13 Beispiel 2 Programm ersetzen exec Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Funktion exec() I Erlaubt es einem Prozess, ein anderes Programm auszuführen I Startet ein neues Programm innerhalb eines Prozesses I PID bleibt gleich Pipes File Descriptor Table Ein-/Ausgaben umleiten 14 Beispiel 2 Programm ersetzen Die exec() Familie (1) Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg, ..., char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int fexecve(int fd, char *const argv[], char *const envp[]); 15 Beispiel 2 Programm ersetzen Die exec() Familie (2) Verwandte Prozesse Prozesseigenschaften I Ersetzt aktuelles Programm durch das in der Datei path enthaltene I exec*p – Variante sucht (wie Shell) in $PATH nach Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten Programm mit dem spezifierten Namen I I IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Argumentübergabe beachten! I 1. Argument ist Programmname (argv[0]) Argumentliste muss mit NULL Zeiger enden I Varianten mit variable Argumentanzahl (execl*) und Argumentarray (execv*) I Variante execle: Environment1 kann verändert werden I Variante fexecve: akzeptiert Dateideskriptor 1 FYI: environ(7) 16 Beispiel 2 Programm ersetzen Beispiel: execv(), execvp() Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC #include <unistd.h> char *cmd[] = { "ls", "-l", (char *) 0 }; (void) execv ("/bin/ls", cmd); (void) execvp ("ls", cmd); Pipes File Descriptor Table error_exit("cannot exec") Ein-/Ausgaben umleiten 17 Beispiel 2 Programm ersetzen Beispiel: execl(), execlp() Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen #include <unistd.h> Prozess beenden Kindprozess abwarten IPC (void) execl ( "/bin/ls", "ls", "-l", NULL ); // or (void) execlp ( "ls", "ls", "-l", NULL ); Pipes File Descriptor Table error_exit("cannot exec") Ein-/Ausgaben umleiten 18 Beispiel 2 Prozess beenden Erinnerung: exit Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Funktion exit() I Beendet den aktuellen Prozess I Rückgabewert kann von Elternprozess abgefragt werden I Beim Beenden I Pipes I File Descriptor Table I Ein-/Ausgaben umleiten I Leeren der stdio-Puffer Schließen offener Dateien Löschen von temporären Dateien (tmpfile(3)) Aufrufen von Exit-Handlern (atexit(3)) 19 Beispiel 2 Prozess beenden exit Verwandte Prozesse Prozesseigenschaften I Prozess erzeugen Prozess normal beenden: #include <stdlib.h> Programm ersetzen void exit(int status); Prozess beenden Kindprozess abwarten IPC I Status: 8 bit (0-255) I Im C-Standard definierte Rückgabewerte: Pipes I File Descriptor Table I Ein-/Ausgaben umleiten I exit(EXIT_SUCCESS) – keine Fehler exit(EXIT_FAILURE) – Fehler aufgetreten Weitere Rückgabewerte I I BSD: sysexits.h http://tldp.org/LDP/abs/html/exitcodes.html 20 Beispiel 2 Auf Kindprozess warten wait Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Funktion wait() I Wartet bis ein Kindprozess terminiert I Liefert PID und Status des beendeten Prozesses Ein-/Ausgaben umleiten 21 Beispiel 2 Auf Kindprozess warten wait Verwandte Prozesse Prozesseigenschaften I #include <sys/wait.h> Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Auf Beendigung eines Kindprozesses warten pid_t wait(int *status); I Rückgabewert: PID des terminierten Kindprozesses, bzw. -1 im Fehlerfall (→ errno, u.a. ECHILD) I Status des Kindprozesses beinhaltet Exit-wert und Signalinformation Pipes File Descriptor Table I I Ein-/Ausgaben umleiten I I WIFEXITED(status), WEXITSTATUS(status) WIFSIGNALED(status), WTERMSIG(status) Siehe wait(2) Nach dem Aufruf von wait() wird der Kindprozess aus der Prozesstabelle entfernt 22 Beispiel 2 Auf Kindprozess warten Zombies und Orphans Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten I UNIX: Auch bereits terminierte Prozesse besetzen einen Eintrag in der Prozesstabelle I Falls kein Platz mehr frei ist, kann kein neuer Prozess gestartet werden Zombie Der Kindprozess terminiert und der Elternprozess hat noch nicht wait aufgeführt I Der Kindprozess wird auf den Zustand „Zombie“ gesetzt gestartet werden I Eintrag in der Prozesstabelle bleibt erhalten, bis der Elternprozess wait ausführt Orphan Der Elternprozess terminiert und der Kindprozess wurde noch nicht beendet I Der Kindprozess „verwaist“ und wird dem Init Prozess vererbt I Nach Beendigung eines Orphans entfernt Init den Prozesseintrag 23 Beispiel 2 Auf Kindprozess warten Beispiel: wait Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table #include <sys/wait.h> int status; pid_t child_pid, pid; ... while ((pid = wait(&status)) != child_pid) { if (pid != -1) continue; // other child if (errno == EINTR) continue; // interrupted error_exit("cannot wait"); } Ein-/Ausgaben umleiten if (WEXITSTATUS(status) == EXIT_SUCCESS) { ... wait() stoppt Prozessausführung bis entweder ein Kindprozess terminiert oder ein Fehler auftritt (6= busy waiting) 24 Beispiel 2 Auf Kindprozess warten waitpid() Verwandte Prozesse Prozesseigenschaften I Prozess erzeugen Auf Beendigung eines Kindprozesses mit einer bestimmten PID warten #include <sys/wait.h> Programm ersetzen pid_t waitpid(pid_t pid, int *status, int options); Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten I Beispiele: waitpid(-1, &status, 0); // aequivalent zu wait waitpid(cid, &status, 0); // wartet auf Kind mit PID ’cid’ waitpid(-1, &status, WNOHANG); // blockiert nicht 25 Beispiel 2 Benachrichtigung bei Terminierung eines Kindprozesses Verwandte Prozesse Prozesseigenschaften Falls nicht blockiert werden soll Prozess erzeugen Programm ersetzen I Prozess beenden Synchron I waitpid(-1, &status, WNOHANG) I Kindprozess abwarten I Holt Exit-Status falls ein Kind beendet wurde Wiederholter Aufruf → Polling IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten I Asynchron I I I Wenn ein Kindprozess beendet wurde, wird das Signal SIGCHLD an den Elternprozess gesendet Installieren eines Signalhandlers (sigaction) Aufruf von wait im Signal-Handler 26 Beispiel 2 Fallstricke Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen int main(int argc, char **argv) { (void) fprintf(stdout, "Hallo"); Prozess beenden (void) fork(); return 0; Kindprozess abwarten } IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Ausgabe: „HalloHallo“ Warum? 27 Beispiel 2 Fallstricke Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten int main(int argc, char **argv) { (void) fprintf(stdout, "Hallo"); (void) fflush(stdout); (void) fork(); return 0; } IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Ausgabe: „Hallo“ → gilt für alle geöffneten Streams 28 Beispiel 2 Debugging gdb Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I Bevor fork ausgeführt wird: set follow-fork-mode [child|parent] Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Zum Beispiel (debuggen von forktest): $ gdb (gdb) (gdb) (gdb) (gdb) (gdb) (gdb) (gdb) -tui ./forktest break main set follow-fork-mode child run next : continue quit 29 Beispiel 2 Pipes Überblick Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I (Unnamed) Pipe = Unidirektionaler Interprozesskommunikationskanal I Ermöglicht Kommunikation zwischen verwandten Prozessen I Eigenschaften: Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten I I I I Zugriff auf Lese- und Schreibende mittels Filedeskriptoren „Stream“ von Daten gepuffert implizite Synchronisation 30 Beispiel 2 Pipes Erzeugung Verwandte Prozesse Prozesseigenschaften I #include <unistd.h> Prozess erzeugen int pipe(int pipefd[2]); Programm ersetzen Prozess beenden I Die File-Deskriptoren des Lese- und des Schreibendes werden im übergebenen Integer-Array retourniert I Deskriptor pipefd[0] ist Leseende I Deskriptor pipefd[1] ist Schreibende I Ein danach mit fork() erzeugter Kindprozess erbt die File-Deskriptoren → gemeinsamer Zugriff I Nicht verwendete Enden werden geschlossen I Weitere Nutzung z.B. mittels Stream-IO (fdopen, etc.) Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Erzeugen einer Pipe 31 Beispiel 2 Unnamed Pipes Illustration Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten 32 Beispiel 2 Unnamed Pipes Synchronisation Verwandte Prozesse Implizite Synchronisation Prozesseigenschaften I Lesen von leerer Pipe ist blockierend Prozess erzeugen I Schreiben auf volle Pipe ebenso Prozess beenden I Lesen von Pipe ohne offene Schreibenden liefert EOF Kindprozess abwarten I Schreiben auf Pipe ohne offene Leseenden erzeugt Signal SIGPIPE (bei Signalbehandlung: write() returniert -1 mit errno EPIPE) Programm ersetzen IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten Deshalb. . . . . . immer nicht benötigte Enden schließen, um dieses Verhalten (EOF bzw. SIGPIPE/EPIPE) sicherzustellen. Außerdem: Kernel entfernt Pipe sobald alle Enden geschlossen sind 33 Beispiel 2 Figure 5-2 illustrates the relationship between file descriptors, open file descrip- File Descriptor tions, and i-nodes. Table In this diagram, two processes have a number of open file descriptors. Verwandte Prozesse Process A File descriptor table Prozesseigenschaften fd file flags ptr Prozess erzeugen Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten fd 0 fd 1 fd 2 Open file table (system-wide) file offset inode ptr file file type locks ... 0 224 23 1976 fd 20 Process B File descriptor table fd file flags ptr fd 0 fd 1 fd 2 fd 3 status flags I-node table (system-wide) 73 86 5139 Figure 5-2: Relationship between file descriptors, open file descriptions, and i-nodes Quelle: Michael Kerrisk - The Linux Programming Interface, p. 95 34 Beispiel 2 Ein- und Ausgaben umleiten dup(), dup2() Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I Programm ersetzen dup(oldfd) dupliziert den File-Deskriptor oldfd I Prozess beenden I Kindprozess abwarten Der neue Deskriptor erhält die niedrigste, nicht verwendete ID, = Eintrag in der file descriptor table Duplizierter Deskriptor zeigt auf dieselbe „open file description“ (file offset, status flags) → siehe open(2) IPC Pipes I dup2(oldfd, newfd) File Descriptor Table I Ein-/Ausgaben umleiten I Dupliziert oldfd, der neue Deskriptor erhält ID newfd Schließt vorher ggf. File-Deskriptor newfd 35 Beispiel 2 Ein- und Ausgaben umleiten Anwendung Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I Hauptanwendungsgebiet für Pipes Programm ersetzen I Kommunikation mit Kommandozeilen-Utility über Standardeingabe und Standardausgabe I Umleiten der Standardeingabe (0, STDIN_FILENO) oder Standardausgabe (1, STDOUT_FILENO) in neuem Prozess Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table I I Ein-/Ausgaben umleiten I Schließen des Filedeskriptors für Standard I/O Duplizieren eines offenen Deskriptors (z.B. Pipeende) auf eben geschlossenen Schließen des duplizierten FDs 36 Beispiel 2 Ein- und Ausgaben umleiten Beispiel Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen #include <fcntl.h> #include <sys/types.h> #include <unistd.h> int fd; Prozess beenden Kindprozess abwarten IPC // TODO error handling! fd = open("log.txt", O_WRONLY | O_CREAT); Pipes File Descriptor Table (void) dup2(fd, STDOUT_FILENO); // old descriptor // new descriptor Ein-/Ausgaben umleiten (void) close(fd); (void) execlp("grep", "grep", "max", NULL); 37 Beispiel 2 Unnamed Pipes Fallstricke Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen I Pipes eignen sich gut für unidirektionale Kommunikation Prozess beenden I Bidirektional: Zwei Pipes Kindprozess abwarten IPC Pipes File Descriptor Table I I Fehleranfällige Synchronisation (deadlock) Synchronisation & Puffer I fflush() verwenden I Puffer konfigurieren (setbuf(3), setvbuf(3)) Ein-/Ausgaben umleiten 38 Beispiel 2 Zusammenfassung Verwandte Prozesse Prozesseigenschaften Prozess erzeugen Programm ersetzen I Kindprozess abwarten fork/exec/wait: I Prozess beenden I Unnamed Pipes: I IPC Weitere Programme starten I Kommunikation zwischen verwandten Prozessen Umleiten von Ein- und Ausgabe Pipes File Descriptor Table Ein-/Ausgaben umleiten 39 Beispiel 2 Material Verwandte Prozesse Prozesseigenschaften Prozess erzeugen I Wilfried Elmenreich: Systemnahes Programmieren C Programmierung unter Unix und Linux, Reichardt Verlag, 2007. I Michael Kerrisk: A Linux and UNIX System Programming Handbook, No Starch Press, 2010. I man pages: fork(2), exec(3), wait(3), dup(2) I gdb - Debugging Forks: https://sourceware.org/gdb/onlinedocs/gdb/ Forks.html Programm ersetzen Prozess beenden Kindprozess abwarten IPC Pipes File Descriptor Table Ein-/Ausgaben umleiten 40