|
fork(), exec() und wait()
Diese Systemaufrufe haben mit der Generierung von Kindprozessen zu
tun und erlauben die Synchronisation zwischen Eltern- und Kindprozessen.An dieser Stelle wird nur soweit darauf eingegangen, wie es zum Verständnisder folgenden Abschnitte nötig ist. fork() erzeugt einen Kindprozeß,der ein vollständiges Abbild des Elternprozesses ist und der beimgleichen Stand des Befehlszählers fortgesetzt wird. Eltern- und Kindprozeßwird jedoch die Möglichkeit geboten, festzustellen, ob es sich umEltern- oder Kindprozeß handelt: Der Kindprozeß bekommt alsRückgabewert 0, der Elternprozeß die PID des Kindprozesses.
Durch bedingte Verzweigung nach dem Schema (".. if Elternprozeß then
... else ...") können beide Prozesse dann unterschiedlich weiterarbeiten.
- Etliche Systemprozesse schließen stdin, stdout und stderr, treten
also in den Hintergrund. Solche Prozesse nennt man 'demon' (Daemonprozesse).
- Terminiert der Elternprozeß vor dem Kindprozeß, wird dieser
zum 'Waisenkind'. Normalerweise wird er dann vom Init-Prozeß 'adoptiert'.
- Hat der Kindprozeß dann auch noch den Kontakt zum
Terminal (Standardausgabe und -eingabe) wird er zum 'Zombie'.
Einzelschritte beim Aufruf von fork():
- Prozeßtabelle überprüfen (Platz frei?)
- Speicher für Kindp. allokieren
- Elternprozeß-Speicher --> Kindprozeß-Speicher kopieren
- Prozeßtabelleneintrag es Elternprozesses aktualisieren
- PID für Kindp. wählen, Kindp. in Prozeßtabelle eintragen
- Kernel und Dateisystem über Kindprozeß informieren
- Fertigmeldung an Eltern- und Kindprozeß senden
wait() ermöglicht dem Elternprozeß das Warten auf die Beendigung
des/der Kindprozess(e). Der Elternprozeß wird verdrängt und
erst durch das Ende eines Kindprozesses wieder "aufgeweckt". Zur Unterscheidung
mehrerer Kindprozesse liefert die Funktion wait() die PID des "gestorbenen"
Kindprozesses zurück.
Gibt es keinen Kindprozeß, ist das Ergebnis -1. Beheben des
Waisenkind/Zombie-Problems:
- 1. Elternprozeß ruft wait() zu spät auf:
Beim Wait-Aufruf wird zuerst die Prozeßtabelle nach terminierten
Kindprozessen durchsucht und diese dann gelöscht.
- 2. Elternprozeß ist terminiert:
Beim Terminieren des Elternprozesses werden dessen Kindprozesse zu Kindprozessen
des Systemprozesses Init.
Bei exec() wird der ursprüngliche Prozeß
durch einen neuen Prozeß ersetzt (eine Rückkehr zum aufrufenden
Prozeß ist daher logischerweise nicht möglich). exec() ist der
komplizierteste Aufruf, da der komplette Prozeßadreßraum ersetzt
werden muß. Dieser Aufruf ist auch als Kommando verfügbar (exec
[Programmname]). Der Ablauf im Schema:
- Zugriffsrechte prüfen (Datei ausführbar?)
- Größe der Speichersegmente feststellen
- Aufrufparameter und Umgebung des Aufrufers festhalten
- Speicher des Aufrufers freigeben, neuen Speicher allokieren
- Neues Programm in den Speicher laden
- UID-, GID-Bits bearbeiten
- Prozeßtabelle aktualisieren
- Bereitmeldung an den Kernel senden
Schließlich gibt es noch eine Systemfunktion, welche die zeitweise
Blockierung eines Prozesses erzwingt: Mit sleep() kann ein Prozeß
für eine definierte Zeit "eingeschläfert" werden. Nach Ablauf
der vorgegebenen Zeit, wird der Prozeß wieder auf "bereit" gesetzt
und kann weiterlaufen. Auch sleep() ist als Kommando verfügbar (sleep
[Zeit in Sekunden]).
|
| |