# Funktionen für Betriebssystemaufrufe

Allgemeines zu diesen Funktionen
qx(...) - Andere Programme/Scripts ausführen und STDOUT auffangen
alarm - SIGALARM in n Sekunden zustellen
exec - Fremdprogramm aufrufen und eigenen Prozess beenden
fork - Kindprozess erzeugen
getpgrp - Prozessgruppe einer Prozessnummer (pid) ermitteln
getppid - Prozessnummer (pid) des Elternprozesses ermitteln
getpriority - Priorität eines Prozesses oder Benutzers ermitteln
kill - Signal an Prozess senden
pipe - Pipe erzeugen
setpgrp - Prozessgruppe für Prozess bestimmen
setpriority - Priorität eines Prozesses oder Benutzers setzen
sleep - aktuellen Prozess anhalten
system - Fremdprogramm aufrufen und eigenen Prozess erhalten
times - Laufzeit des aktuellen Prozesses ermitteln
wait - auf das Ende eines Kindprozesses warten
waitpid - auf das Ende eines Kindprozesses mit bestimmter Prozessnummer (pid) warten

## Allgemeines zu diesen Funktionen

Unter "Betriebssystemaufrufe" sind hier Funktionen versammelt, die sich vor allem eng am Konzept der Unix-Betriebssysteme orientieren. Nur wenige der Funktionen sind auf andere Systeme portierbar.

Unix-Systeme verwalten laufende "Programme" in so genannten Prozessen. Jeder Prozess hat eine Prozessnummer (PID). Außerdem gibt es Prozessgruppen. Jeder Prozess gehört zu einer Prozessgruppe. Prozessgruppen haben ebenfalls Nummern. Auch Ihr Perl-Script stellt, wenn es ausgeführt wird, einen solchen Prozess dar, der einer Prozessgruppe angehört. Bei vielen der hier beschriebenen Funktionen können Sie den aktuellen Prozess, also den Ihres Perl-Scripts, durch die "virtuelle" Prozessnummer `0` ansprechen. Über vordefinierte Variablen können Sie jedoch auch die tatsächliche Prozessnummer herausfinden und benutzen. Das folgende Beispielscript zeigt die entsprechenden Variablen im Einsatz:

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    print "Prozessnummer (PID): <strong>$$</strong><br>\n";
    print "Reale Benutzergruppe (GID) des Prozesses: <strong>$(</strong><br>\n";
    print "Effektive Benutzergruppe (GID) des Prozesses: <strong>$)</strong>\n";
    print "</body></html>\n";

### Erläuterung:

Mit `$$` sprechen Sie die Nummer des aktuellen Prozesses an. Der Prozess läuft unter einer bestimmten User-ID, die wiederum einer oder mehreren Gruppen angehört. Wenn das Script beispielsweise mit `setgid` gestartet wurde, enthält die reale Gruppen-ID die Gruppe(n), von der aus gestartet wurde, die effektive Gruppen-ID enthält die Gruppe(n), in die gewechselt wurde (die aktuelle also). Das Beispiel-CGI-Script gibt die entsprechenden Daten aus.

Weitere wichtige Konzepte der Unix-Betriebssysteme, auf die Sie mit Perl-Funktionen Zugriff haben, sind Alarme, Kindprozesse und die so genannten Pipes. Nähere Informationen dazu finden Sie in der Unix-Fachliteratur.

## qx(...) - Andere Programme/Scripts ausführen und STDOUT auffangen

Hierbei handelt es sich eigentlich nicht um eine Perl-Funktion, sondern um eine besondere Form des Notierens von Zeichenketten. Das `qx` steht für quoted executable. Die darin eingeschlossene Zeichenkette wird von Perl einfach in einen Kommandozeilenaufruf umgesetzt. Die Standardausgabe des aufgerufenen Kommandos, Fremdprogramms oder Scripts wird aufgefangen und kann in einer Variablen gespeichert werden. Eine andere Möglichkeit, diese Art von ausführbaren Zeichenketten zu notieren, sind die so genannten Backticks. Dabei arbeiten Sie anstelle von `qx(irgendein Kommando)` mit dem rückwärts gerichteten Accent-Zeichen ``` und notieren ``irgendein Kommando``.

Die Funktionalität der ausführbaren Zeichenketten ist für CGI-Scripts extrem nützlich, um die Ausgaben anderer Prozesse auffangen und an den Browser senden lassen zu können. So lassen sich beispielsweise XML-Daten mit XSLT und einem XSLT-Prozessor in HTML übersetzen. Wenn dieser Prozessor seine Ergebnisse auf den Standardausgabekanal `STDOUT` schreibt, kann das CGI-Script die Ausgabe auffangen und an den Webserver zur Weiterleitung übergeben. Das folgende Beispiel zeigt dies.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    my $Output = qx(/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl);
    print "$Output";

### Erläuterung:

Mehr als dieses winzige Script ist nicht nötig, um XML-Daten in HTML-Form an den Webserver zur Übergabe an einen aufrufenden Browser zu senden - sofern ein XSLT-Prozessor die Übersetzungsarbeit leistet. Das Beispiel führt folgendes Kommando aus:
`/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl`
Dabei ist `saxon` der Name eines XSLT-Prozessors, also eines ausführbaren Programms. Dieses Programm erwartet im Normalfall zwei Aufrufparameter: erstens die Angabe einer XML-Datei, und zweitens die Angabe einer dazu passenden XSL-Datei mit XSLT-Anweisungen. Saxon übersetzt die XML-Auszeichnungen aufgrund der XSLT-Angaben in HTML-Konstrukte und gibt das Ergebnis, eine vollständige HTML-Datei, auf die Standardausgabe aus. Das Script fängt diese Standardausgabe auf, indem es sie in der Variablen `$Output` speichert. In dieser Variablen steht also nach dem Saxon-Aufruf der gesamte Inhalt der HTML-Daten. Ein einfacher print-Befehl genügt anschließend, um die gesamten HTML-Daten auszugeben.

### Beachten Sie:

Die Art der Klammerung bei Verwendung von `qx` ist egal. Sie können auch eckige oder geschweifte Klammern oder Schrägstriche verwenden - von letzteren ist allerdings abzuraten, weil viele Kommandos Pfadangaben benötigen und Sie in diesem Fall alle Schrägstriche bei Pfadangaben maskieren müssten.

Bei Pfadangaben sollten Sie auch bei `qx(...)` stets die einfachen Schrägstriche verwenden - auch wenn das Perl-Script unter Windows ausgeführt wird.

Mit Backticks würde der Aufruf des obigen Beispiels lauten:
`my $Output = `/usr/bin/saxon /daten/xml/kunden.xml /daten/xml/kunden.xsl`;`
Um die Backticks zu erzeugen, halten Sie auf den meisten Systemen die Shift-Taste gedrückt, tippen einmal auf die Taste mit den französischen Accent-Zeichen und anschließend die Leertaste.

Im Link-Verzeichnis des Online-Angebots von SELFHTML aktuell finden Sie Links zu XML-Software. Dort finden Sie ebenso Verweise zu Produkten wie Saxon.

Die hier beschriebene Möglichkeit ist auf alle Kommandos anwendbar, die etwas auf die Standardausgabe `STDOUT` schreiben, also z.B. auch auf Betriebssystem-Kommandos wie `ls` (bzw. `dir`), oder auch auf andere Perl-Scripts. Einige solcher Programme oder Kommandos schreiben ihren Output bei fehlerhaften Aufrufen jedoch nicht auf `STDOUT`, sondern auf `STDERR`. Solche Ausgaben werden von den hier beschriebenen ausführbaren Zeichenketten nicht aufgefangen.

## alarm - SIGALARM in n Sekunden zustellen

Unix-spezifischer Befehl. Bewirkt, dass der Prozess einen SIGALARM nach einer bestimmten Anzahl Sekunden erhält, wenn z.B. ein kritischer Befehl nicht funktioniert.

Erwartet als Parameter:
1. die Anzahl Sekunden, bis der Alarm aktiv wird.

Gibt die Anzahl Sekunden zurück, die verstrichen sind.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body><pre>\n";

    eval {
      local $SIG{ALRM} = sub { die "Alarm" };
      alarm(2);
      system("/usr/bin/perl -c /usr/web/myhome/cgi-bin/freelink.pl");
      alarm(0);
    };
    if ($@ and $@ !~ /Alarm/) {
      print "Problem! 2 Sekunden vergangen!\n";
    }
    else {
      print "Alles klar!\n";
    }
    print "</pre></body></html>\n";

### Erläuterung:

Das Beispiel zeigt, wie Sie einen "kritischen Systemaufruf" mit Hilfe eines Timeout-Alarms behandeln können. Dazu wird in dem Script zunächst ein für solche Behandlung typischer eval-Block notiert. Darin wird mit der typischen Anweisung:
`local $SIG{ALRM} = sub { die "Alarm" };`
eine Behandlungsroutine für SIGALARM definiert. Anschließend wird mit `alarm(2)` ein Timeout von 2 Sekunden definiert, bevor der Alarm aktiv wird. Mit `alarm(0)` wird der Alarm wieder zurückgesetzt.
Danach wird versucht, mit system den Perl-Interpreter aufzurufen, und zwar so, dass er ein bestimmtes Script auf die Gültigkeit seiner Syntax überprüft. Sollte dieser Vorgang mehr als 2 Sekunden dauern, wird der Alarm aktiv.
Mit der Abfrage `if ($@ and $@ !~ /Alarm/)` wird überprüft, ob der Alarm aktiv wurde. Wenn ja, wird eine entsprechende Meldung ausgegeben. Im `else`-Zweig kann der Code stehen, der ausgeführt wird, wenn alles in Ordnung war. Im Beispiel wird einfach ebenfalls eine entsprechende Meldung ausgegeben.

### Beachten Sie

Aufrufe mit system oder qx(...) in Verbindung mit `alarm` können zu sogenannten Zombies führen. Möglicherweise müssen Sie sie für solche Zwecke mit Hilfe von fork und exec selbst implementieren.

## exec - Fremdprogramm aufrufen und eigenen Prozess beenden

Startet einen anderen Prozess und beendet das aktuelle Script. Der aktuelle Prozess wird dabei durch den neuen Prozess vollständig ersetzt. Wenn Sie das aktuelle Script nicht beenden wollen, benutzen Sie system, qx(...) oder open mit dem Pipe-Zeichen `|`.

Erwartet als Parameter:
1. Kommandozeilenaufruf des gewünschten Programms,
2. bis n. (optional) Liste mit Aufrufparametern.

### Beispiel:

    #!/usr/bin/perl -w

    exec("/usr/bin/perl","mystats.pl") if -e "mystats.pl";

### Erläuterung:

Das Beispiel fragt mit Hilfe des Dateitestoperators `-e` ab, ob eine Datei namens `mystats.pl` im aktuellen Verzeichnis existiert. Wenn ja, wird der Perl-Interpreter (in einem eigenen neuen Prozess) gestartet und führt `mystats.pl` aus.

## fork - Kindprozess erzeugen

Unix-spezifischer Befehl. Erzeugt eine Kopie des aktuellen Prozesses, die dem aktuellen erzeugenden Prozess untergeordnet ist. Ein Perl-Script kann sich auf diese Weise gabeln (engl. fork) und Daten in zwei getrennten Prozessen verarbeiten. Auf geöffnete Dateien können dabei beide Prozesse zugreifen. Alles übrige, wie Variablen usw., wird vom Elternprozess in den Kindprozess kopiert. Die Variable, die den Rückgabewert von `fork` speichert, hat jedoch im Elternprozess einen Wert, nämlich die Prozessnummer des Kindprozesses, während sie im Kindprozess den Wert `0` hat.
Obwohl `fork` eigentlich aus der Unix-Welt stammt, lässt sich diese Funktion mittlerweile auch unter ActivePerl für Windows nutzen.

Erwartet keine Parameter.

Gibt die vom Betriebssystem zugewiesene Prozessnummer des Kindprozesses zurück.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    $| = 1;
    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    my $Eltern_pid = $$;
    my $Kind_pid = fork();

    if($Kind_pid) {
      print "<p>Hier ist der Elternprozess. Der Kindprozess hat die PID <strong>$Kind_pid</strong></p>\n";
      wait;
    }
    else {
      my $Eltern_pid = getppid();
      print "<p>Hier ist der Kindprozess. Der Elternprozess hat die PID <strong>$Eltern_pid</strong></p>\n";
      exit(0);
    }
    print "</body></html>\n";

### Erläuterung:

Das Beispiel erzeugt mit `fork` einen Kindprozess. Der Rückgabewert der Funktion, die Prozessnummer des Kindprozesses, wird in dem Skalar `$Kind_pid` gespeichert. Im Beispiel ist daraufhin eine `if`-Abfrage notiert. Mit `if($Kind_pid)` wird abgefragt, ob der Skalar `$Kind_pid` einen Wert ungleich `0` hat. Ist das der Fall, werden Anweisungen ausgeführt, die zum Elternprozess gehören. Im Beispiel wird eine Meldung ausgegeben, dass sich das Script im Elternprozess befindet. Außerdem wird die Prozessnummer des Kindprozesses ausgegeben. Danach wird mit der Anweisung wait gewartet, bis der Kindprozess beendet ist. Im `else`-Zweig, in den das Script gelangt, wenn `Kind_pid` den Wert `0` hat, wird dagegen ausgegeben, dass der Kindprozess aktiv ist. Außerdem wird die Prozessnummer des Elternprozesses ausgegeben. Danach wird der Kindprozess mit der Anweisung `exit(0);` beendet. Der Elternprozess, der darauf nur gewartet hat, gibt dann noch die letzte Zeile HTML-Code aus.
Das besondere Verhalten des Scripts, das in zwei Prozessen läuft, zeigt sich im Beispiel darin, dass sowohl der `if`-Zweig als auch der `else`-Zweig ausgeführt werden. Das erklärt sich daraus, dass die `if`-Bedingung für den Elternprozess wahr ist, die `else`-Alternative dagegen für den Kindprozess.

## getpgrp - Prozessgruppe einer Prozessnummer (pid) ermitteln

Unix-spezifischer Befehl.

Erwartet als Parameter:
1. eine Prozessnummer, zu der die zugehörige Prozessgruppe ermittelt werden soll. Um die Prozessgruppe des aktuellen Prozesses zu ermitteln, müssen Sie `0` übergeben.

Gibt die Gruppennummer zurück.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";

    my $Gruppennummer = getpgrp(0);
    print "Die Prozessgruppe des aktuellen Prozesses ist <strong>$Gruppennummer</strong>\n";

    print "</body></html>\n";

### Erläuterung:

Das Beispiel ermittelt die Gruppennummer des aktuellen Prozesses mit `getpgrp` und gibt HTML-Code mit der ermittelten Nummer aus.

## getppid - Prozessnummer (pid) des Elternprozesses ermitteln

Unix-spezifischer Befehl.

Erwartet keine Parameter.

Gibt die Prozessnummer (PID) des Elternprozesses des aktuellen Scripts zurück.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";

    my $Eltern_pid = getppid();
    print "Die PID des Elternprozesses lautet <strong>$Eltern_pid</strong>\n";

    print "</body></html>\n";

### Erläuterung:

Das Beispiel ermittelt die PID des Elternprozesses mit `getppid` und gibt HTML-Code mit der ermittelten Nummer aus.

## getpriority - Text

Unix-spezifischer Befehl. Ermittelt die aktuelle Priorität eines Prozesses, einer Prozessgruppe oder eines Benutzers. Prozesse mit höherer Priorität erhalten unter den aktuell laufenden Prozessen mehr Systemressourcen zur Ausführung.

Erwartet als Parameter:
1. eine Angabe dazu, ob Sie die Priorität für einen bestimmten Prozess, eine Prozessgruppe oder einen Benutzer ermitteln wollen. Dazu übergeben Sie am besten eine der Konstanten, die in `resource.ph` definiert sind (siehe unten).
2. die Nummer des Prozesses, der Prozessgruppe oder des Benutzers.

Gibt die Priorität des Prozesses, der Prozessgruppe oder des Benutzers als Zahl zurück. Der mögliche Wertebereich ist abhängig vom System.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";

    require "resource.ph";
    my $Prio = getpriority(&PRIO_PROCESS,0);
    print "Prioritaet des aktuellen Prozesses: $Prio\n";

    print "</body></html>\n";

### Erläuterung:

Das Beispiel ermittelt mit `getpriority` die Priorität des aktuellen Prozesses und gibt diese aus. Dazu wird mit `require "resource.ph"` die Kopfdatei eingebunden, die die Definition der folgenden Konstanten enthält:

Konstante: | Bedeutung:
--- | ---
`PRIO_PROCESS` | Die Priorität eines bestimmten Prozesses ermitteln, dessen Prozessnummer (oder 0 für den aktuellen Prozess) im zweiten Parameter von `getpriority` angegeben wird.
`PRIO_PGRP` | Die Priorität einer Prozessgruppe ermitteln, deren Nummer (oder 0 für die aktuelle Prozessgruppe) im zweiten Parameter angegeben wird.
`PRIO_USER` | Die Priorität eines Benutzers ermitteln, dessen Benutzernummer (UID - oder 0 für den aktuelle Benutzer) im zweiten Parameter angegeben wird.

Durch Voranstellen eines `&`-Zeichens können Sie eine der Konstanten wie im Beispiel gezeigt als ersten Parameter übergeben.

### Beachten Sie:

Diese Funktion führt zu einem schweren Fehler, wenn das System keine Prozess- bzw. Benutzerverwaltung im Sinne von Unix kennt.

## kill - Signal an Prozess senden

Unix-spezifischer Befehl. Damit können Sie aus einem Perl-Script heraus Signale an andere laufende Prozesse auf dem Rechner senden und diese dadurch beeinflussen. Interessant ist dies vor allem, wenn Sie in Ihrem Perl-Script eigene Kindprozesse erzeugen (siehe fork). Eltern- und Kindprozess können dann durch Signale kommunizieren.

Erwartet als Parameter:
1. Nummer oder Name einer Konstante (siehe Tabelle weiter unten) des gewünschten Signals (oder Sie übergeben `0`, um herauszufinden, ob der Prozess mit der nachfolgend übergebenen Prozessnummer noch "am Leben" ist),
2. bis n. einer oder mehrere Prozesse, an die das Signal gesendet werden soll.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    $| = 1;
    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";

    my $Kind_pid = fork();

    if(kill(0,$Kind_pid)) {
      print "<p>Hier meldet sich ein Prozess</p>\n";
      kill("KILL",$Kind_pid);
    }
    print "</body></html>\n";

### Erläuterung:

Das Beispiel erzeugt mit fork einen Kindprozess. Mit `if(kill(0,$Kind_pid))` wird abgefragt, ob dieser Prozess am Leben ist. Wenn ja, wird ausgegeben, dass sich ein Prozess meldet. Da im Beispiel für den Kindprozess kein eigener Perl-Code notiert ist und Kindprozesse einfach erst mal alles vom Elternprozess kopieren, würden beide Prozesse sich melden und `Hier meldet sich ein Prozess` ausgeben. Doch im Beispiel wird das verhindert, indem der Elternprozess den Kindprozess mit `kill("KILL",$Kind_pid)` tötet, bevor dieser die Anweisung mit der Ausgabe der Meldung ausführen kann. Die Meldung wird also insgesamt nur einmal ausgegeben.

Die folgende Tabelle enthält typische Signale mit Namen, wie Sie sie als ersten Parameter an `kill` übergeben können. Eine Garantie, dass alle hier aufgelisteten Signale auf jedem Rechner in Perl funktionieren, besteht nicht. Auch die entsprechenden Nummern wurden hier weggelassen, da sie von System zu System schwanken können. Maßgeblich ist letztendlich immer, was auf dem jeweiligen Rechner in der Datei `/usr/include/signal.h` definiert ist.

Name: | Bedeutung:
--- | ---
`"HUP"` | Ereignis: Verbindung beendet
`"INT"` | Ereignis: allgemeine Unterbrechung
`"QUIT"` | Ereignis: Endekennzeichen
`"ILL"` | Anweisung ist illegal
`"TRAP"` | Anweisung ist eine "Falle"
`"ABRT"` | Abbruch
`"FPE"` | Fehler bei Fließkommaberechnung
`"KILL"` | Prozess "abschießen" (Unix: kill -9)
`"BUS"` | Bus-Übertragungsfehler
`"SEGV"` | Segment-Schutzverletzung im Speicher
`"PIPE"` | Fehler bei Pipe-Kommunikation
`"ALARM"` | Allgemeiner Alarm
`"TERM"` | Beendigung
`"USR1"` | Benutzerdefiniert 1
`"USR2"` | Benutzerdefiniert 2
`"CHLD"` | Signal vom Kindprozess
`"PWR"` | Stromausfall
`"WINCH"` | Fenstergröße wurde von einem Hintergrundprozess geändert
`"URG"` | Dringende Bedingung
`"IO"` | Asynchrone Ein-/Ausgabe
`"STOP"` | Prozess anhalten
`"TSTP"` | Prozess vom Terminal aus anhalten
`"CONT"` | Angehaltenen Prozess fortführen
`"TTIN"` | Prozess anhalten durch Lesen vom kontrollierenden Terminal
`"TTOU"` | Prozess anhalten durch Schreiben auf kontrollierendes Terminal
`"VTALARM"` | Virtueller Zeittaktgeber abgelaufen
`"PROF"` | Profil-Zeittaktgeber abgelaufen
`"XCPU"` | CPU-Belastungsgrenze erreicht
`"XSFZ"` | Dateigrößengrenze erreicht

### Beachten Sie:

Mit dem folgenden Script können Sie abfragen, welche Signale unter welchen Signalnummern auf Ihrem Server-Rechner konfiguriert sind:

    #!/usr/bin/perl

    use Config;

    defined $Config{sig_name} || die "Kein Konfigmodul?";
    foreach $name (split(' ', $Config{sig_name})) {
      $i++;
      printf "%3d) %s \t", $i, $name;
      if (($i % 5) == 0) { print "\n";  }
    }
    print "\n";

## pipe - Pipe erzeugen

Unix-spezifischer Befehl. Ermöglicht zwei Prozessen, miteinander zu kommunizieren. Eine "Pipe" (Pfeife, Röhre) ist dabei der Kommunikationskanal für die beiden Prozesse. Es gibt einen Kanal zum Schreiben von Daten und einen zum Lesen von Daten. Für beide Kanäle gibt es jeweils ein "Handle". Diese Lese- und Schreib-Handles sind ganz ähnlich den Datei-Handles. Typischerweise wird eine Pipe eröffnet, bevor mit fork ein Kindprozess erzeugt wird. Eltern- und Kindprozess können dann über die geöffnete Pipe Daten austauschen.

Erwartet als Parameter:
1. den Namen eines Lese-Handles (frei vergebbar),
2. den Namen eines Schreib-Handles (frei vergebbar)

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    $| = 1;
    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body><pre>\n";

    pipe(LESE_HANDLE, SCHREIB_HANDLE);
    my $Kind_pid = fork();

    if ($Kind_pid) {
     close(LESE_HANDLE);
     my $old_handle = select(SCHREIB_HANDLE);
     $| = 1;
     for (my $i=1;$i<=5;$i++) {
       sleep(1);
       print SCHREIB_HANDLE "$i (gesendet vom Elternprozess)\n";
     }
     close(SCHREIB_HANDLE);
     wait;
     select($old_handle);
    }
    else {
     close(SCHREIB_HANDLE);
    my $Speicher;
     while(defined($Speicher = <LESE_HANDLE>)) {
       print "Empfangen: $Speicher \n";
     }
     exit(0);
    }
    print "</pre></body></html>\n";

### Erläuterung:

Das Beispiel erzeugt mit `pipe` eine Pipe. Über die beiden übergebenen Handle-Namen `LESE_HANDLE` und `SCHREIB_HANDLE` ist anschließend der Nachrichtenaustausch zwischen zwei Prozessen möglich. Mit Hilfe von fork erzeugt das Script einen Kindprozess. Der Elternprozess läuft im `if`-Zweig des nachfolgenden Codes, der Kindprozess im `else`-Zweig. Beim Erzeugen des Kindprozesses wird alles kopiert - außer den beiden Handles aus der Pipe. Diese werden nicht kopiert, bleiben allerdings für beide Prozesse verfügbar. Deshalb muss jeder Prozess erst mal das nicht benötigte Handle mit close schließen. Um die Pufferung der Daten abschalten zu können, muss im `if`-Zweig außerdem mit select das Schreib-Handle ausgewählt werden. Alle Anweisungen sowohl des `if`- als auch des `else`-Zweiges werden insgesamt fünf mal ausgeführt. Denn in einer for-Schleife, die von 1 bis 5 zählt, schreibt der Elternprozess, nachdem er zu Testzwecken eine Sekunde lang anhält (siehe sleep), den aktuellen Zählerstand in das Schreib-Handle. Der Kindprozess im `else`-Zweig kann diese Daten lesen, indem er eine while-Schleife verwendet und darin das Lese-Handle ausliest. Zur Kontrolle gibt der Kindprozess aus, was er eingelesen hat.

## setpgrp - Prozessgruppe für Prozess bestimmen

Unix-spezifischer Befehl. Ordnet einen Prozess einer Prozessgruppe zu.

Erwartet als Parameter:
1. die Prozessnummer (PID) des gewünschten Prozesses (`0` für aktuellen Prozess übergeben),
2. die Nummer der Prozessgruppe, der dieser Prozess zugeordnet werden soll (`0` für aktuelle Prozessgruppe übergeben).

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    my $gruppe_alt = getpgrp(0);
    print "Prozessgruppe alt: <strong>$gruppe_alt</strong><br>\n";

    setpgrp(0,0);

    my $gruppe_neu = getpgrp(0);
    print "Prozessgruppe neu: <strong>$gruppe_neu</strong>\n";

    print "</body></html>\n";

### Erläuterung:

Das Beispiel ordnet den aktuellen Prozess der aktuellen Prozessgruppe zu und erzeugt so seine eigene Prozessgruppe. Zum Vergleich wird die aktuelle Prozessgruppe vorher und hinterher ausgelesen und jeweils ausgegeben.

## setpriority - Priorität eines Prozesses oder Benutzers setzen

Unix-spezifischer Befehl. Setzt die aktuelle Priorität eines Prozesses, einer Prozessgruppe oder eines Benutzers. Prozesse mit höherer Priorität erhalten unter den aktuell laufenden Prozessen mehr Systemressourcen zur Ausführung.
Da diese Funktion "systemkritisch" ist, steht sie auf den meisten Unix-Systemen nur Benutzern mit root-Kennung zur Verfügung.

Parameter wie bei getpriority

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";

    require "resource.ph";
    my $Prio = getpriority(&PRIO_PROCESS,0);
    $Prio += 1;
    setpriority (&PRIO_PROCESS, 0, $Prio);
    print "Neue Prioritaet des aktuellen Prozesses: $Prio\n";

    print "</body></html>\n";

### Erläuterung:

Das Beispiel liest mit `getpriority` die Priorität des aktuellen Prozesses ein, erhöht sie anschließend um 1 und setzt dann mit `setpriority` den neuen Wert. Zur Kontrolle gibt das Script den aktuellen Wert der Priorität aus.

### Beachten Sie:

Diese Funktion führt zu einem schweren Fehler, wenn das System keine Prozess- bzw. Benutzerverwaltung im Sinne von Unix kennt.

## sleep - aktuellen Prozess anhalten

Hält die Ausführung des Scripts für eine bestimmte Anzahl Sekunden an und fährt dann fort.

Erwartet als Parameter:
1. die Anzahl Sekunden, die angehalten werden soll. Wenn nichts übergeben wird, wird "für ewig" angehalten.

### Beispiel:

    #!/usr/bin/perl -w

    use strict;

    sleep(10);
    exec("/usr/bin/perl","aufwachen.pl");

### Erläuterung:

Das Beispiel wartet nach Aufruf von `sleep(10)` 10 Sekunden und führt dann mit exec ein anderes Script aus.

## system - Fremdprogramm aufrufen und eigenen Prozess erhalten

Ruft ein anderes Programm auf und ermittelt dessen Rückgabewert. Wenn Sie daran interessiert sind, welche Ausgaben das andere Programm erzeugt, sollten Sie die Funktion open mit dem Zeichen `|` oder qx(...) bzw. ``...`` (Backticks) benutzen.

Erwartet als Parameter:
1. eine Zeichenkette oder eine Liste. Werden mehrere Parameter, also eine Liste, übergeben, wird der erste Parameter als das auszuführende Programm bzw. Kommando interpretiert, und die übrigen Parameter als Übergabeparameter für das Programm bzw. Kommando.

Gibt den Rückgabewert des ausgeführten Programms oder Kommandos zurück.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    (my $Datei_1, my $Datei_2) = split(/&/,$ENV{'QUERY_STRING'});
    my $Pfaddatei_1 = "/usr/web/daten/alt/".$Datei_1;
    my $Pfaddatei_2 = "/usr/web/daten/neu/".$Datei_2;
    my $Vergleich = system("cmp $Pfaddatei_1 $Pfaddatei_2 >/dev/null");

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Test-Ausgabe</title></head><body>\n";
    if($Vergleich == 0) {
      print "<tt>$Pfaddatei_1</tt><br>und<br><tt>$Pfaddatei_2</tt><br><strong>sind gleich!</strong>!\n";
    }
    else {
      print "<tt>$Pfaddatei_1</tt><br>und<br><tt>$Pfaddatei_2</tt><br><strong>sind verschieden!</strong>!\n";
    }
    print "</body></html>\n";

### Erläuterung:

Das Beispielscript ermittelt den Inhalt der CGI-Umgebungsvariablen `QUERY_STRING`, erwartet in dem übergebenen Parameter ein kaufmännisches Und (`&`) und trennt den Teil davor und den dahinter in die Skalare `$Datei_1` und `$Datei_2`. Die beiden Daten werden als Dateien interpretiert. Ein Beispielaufruf des Scripts könnte lauten:
/cgi-bin/script.pl?news.htm&news.htm
Das Script hängt die beiden gleichnamigen Dateien an unterschiedliche Pfadnamen auf dem Server und erzeugt damit zwei unterschiedliche Dateipfadangaben in den Skalaren `$Pfaddatei_1` und `$Pfaddatei_2`. Mit `system` wird nun der Shell-Befehl `cmp` (unter Unix) gestartet, der zwei Dateien daraufhin überprüft, ob sie gleich sind. Dem Befehl werden die beiden Skalare mit den Pfadangaben übergeben. Eine Ausgabe soll der Befehl in diesem Fall nicht erzeugen. Deshalb wird seine Ausgabe nach `/dev/null` umgeleitet. Der Rückgabewert des `system`-Aufrufs und damit des `cmp`-Befehls wird jedoch gespeichert, nämlich im Skalar `$Vergleich`. Wenn der Wert `0` ist, sind die verglichenen Dateien gleich, andernfalls unterschiedlich. Diese Information wird zurückgegeben.

## times - Laufzeit des aktuellen Prozesses ermitteln

Ermittelt die Laufzeit eines Prozesses (und, wenn vorhanden, seiner Kindprozesse) von der Erzeugung bis zum Ausführen dieses `times`-Aufrufs. Ermittelt werden für jeden Prozess jeweils zwei Werte: "user time" und "system time". Während "user time" bezeichnet, wie lange der Prozess selber gelaufen ist, gibt "system time" die Zeit an, wie lange der Prozess das Betriebssystem beschäftigt hat. Die Summe beider Zeiten ist die gesamte verbrauchte CPU-Zeit.
Die gemessenen Zeiten basieren auf so genannten Uhrenticks. Die Anzahl der Uhrenticks pro Sekunde ist auf Unix-Systemen einstellbar (`TICKSPERSEC` in der Datei `conf.h`).

Erwartet keine Parameter.

Gibt eine Liste mit Laufzeiten in Sekunden (Fließkommazahlen mit Angaben zu Sekundenbruchteilen) zurück. Schema:
`($user_time,$system_time[,$user_time_Kind,$system_time_Kind,...])`

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    my $x;
    for(my $i = 0; $i < 1000; $i++) {
      for(my $k = 0; $k < 100; $k++) {
        $x = $i * $k / time();
      }
    }

    my ($Systemzeit, $Userzeit) = times();
    my $CPU_Zeit = $Systemzeit + $Userzeit;

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    print "verbrauchte Systemzeit: <strong>$Systemzeit</strong> Sekunden<br>\n";
    print "verbrauchte Userzeit: <strong>$Userzeit</strong> Sekunden<br>\n";
    print "verbrauchte CPU-Zeit: <strong>$CPU_Zeit</strong> Sekunden\n";
    print "</body></html>\n";

### Erläuterung:

Das Beispiel enthält zwei verschachtelte for-Schleifen, in denen sehr viel zu rechnen ist (es werden insgesamt 100.000 Funktionsaufrufe von time und Bruchzahlrechnungen durchgeführt). Anschließend ermittelt das Beispiel die benötigten Zeiten. Vom Aufruf der Funktion `times` werden die ersten beiden Listenelemente, also die für den aktuellen Prozess, in den Skalaren `$Systemzeit` und `$Userzeit` festgehalten. Aus der Summe dieser beiden wird noch die CPU-Zeit ermittelt und in `$CPU_Zeit` gespeichert. Zur Kontrolle gibt das Script die ermittelten Zeiten aus.

## wait - auf das Ende eines Kindprozesses warten

Unix-spezifischer Befehl.

Erwartet keine Parameter.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    #use strict;
    use CGI::Carp qw(fatalsToBrowser);

    $| = 1;
    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    my $Kind_pid = fork();

    if($Kind_pid) {
      print "<p>Hier ist der Elternprozess.</p>\n";
      wait();
      print "<p>Der Kindprozess ist zuende.</p>\n";
    }
    else {
      print "<p>Hier ist der Kindprozess.</p>\n";
      exit(0);
    }
    print "</body></html>\n";

### Erläuterung:

Das Beispiel erzeugt mit fork einen Kindprozess. Mit `if($Kind_pid)` wird abgefragt, ob der Skalar `$Kind_pid` einen Wert ungleich `0` hat. Ist das der Fall, werden Anweisungen ausgeführt, die zum Elternprozess gehören. Im Beispiel wird eine Meldung ausgegeben, dass sich das Script im Elternprozess befindet. Im `else`-Zweig, in den das Script gelangt, wenn `Kind_pid` den Wert `0` hat, wird dagegen ausgegeben, dass der Kindprozess aktiv ist.
Normalerweise würde erst der `if`-Zweig abgearbeitet, dann der `else`-Zweig. Durch die Anweisung `wait()` im `if`-Zweig wartet jedoch der Elternprozess auf das Ende des Kindprozesses, bevor er fortfährt. So wird vorher der `else`-Zweig abgearbeitet, und anschließend die letzte Meldung im `if`-Zweig ausgegeben.

## waitpid - auf das Ende eines Kindprozesses mit bestimmter Prozessnummer (pid) warten

Unix-spezifischer Befehl. Ruft im Gegensatz zu wait direkt das Betriebssystem auf.

Erwartet als Parameter:
1. Die Prozessnummer (PID) des gewünschten Kindprozesses.
2. Schalter (Flags - siehe Tabelle weiter unten)

Gibt die Prozessnummer (PID) des beendeten Prozesses zurück, oder `-1`, wenn der gewünschte Kindprozess nicht oder nicht mehr existiert. Auf manchen Systemen ist auch der Rückgabewert `0` möglich - er bedeutet, dass der Kindprozess noch immer läuft (d.h. ein Timeout beim Warten überschritten wurde).

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/usr/bin/perl -w

    #use strict;
    use CGI::Carp qw(fatalsToBrowser);
    use POSIX;

    $| = 1;
    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    my $Kind_pid = fork();

    if($Kind_pid) {
      print "<p>Hier ist der Elternprozess.</p>\n";

      use POSIX ":sys_wait_h";
      do {
        my $Kind_pid = waitpid(-1,&WNOHANG);
      } until $Kind_pid == -1;

      print "<p>Der Kindprozess ist zuende.</p>\n";
    }
    else {
      print "<p>Hier ist der Kindprozess.</p>\n";
      exit(0);
    }
    print "</body></html>\n";

### Erläuterung:

Das Beispiel tut das gleiche wie jenes bei wait. In diesem Fall wird jedoch mit einer do-until-Schleife gewartet, bis der Kindprozess zuende ist. Das ist der Fall, wenn die Funktion `waitpid` den Rückgabewert `-1` liefert, der Kindprozess also nicht mehr existiert.

Der Funktion `waitpid` wird im Beispiel das Flag `&WNOHANG` übergeben. Die Konstanten dazu werden im Standardmodul `POSIX` definiert. Daher ist es erforderlich, dieses Modul so wie im Beispiel mit `use POSIX ":sys_wait_h"` einzubinden.
Die folgende Tabelle listet die Flags auf, die Sie an der Stelle übergeben können.

Flag: | Bedeutung:
--- | ---
`&WEXITSTATUS` | Enthält den Rückgabewert des Kindprozesses (genauer: die untersten 8 Bit, also einen Wert bis maximal 255).
`&WIFEXITED` | Hat den Wert `true` oder `1`, wenn der Kindprozess normal beendet wurde.
`&WIFSIGNALED` | Hat den Wert `true` oder `1`, wenn der Kindprozess durch ein unbeantwortetes Signal beendet wurde.
`&WIFSTOPPED` | Hat den Wert `true` oder `1`, wenn der Kindprozess angehalten wurde.
`&WNOHANG` | Der aufrufende Prozess wird nicht blockiert, falls der Kindprozess nicht sofort reagiert. In einem solchen Fall wird `waitpid()` sofort beendet und liefert 0 zurück.
`&WSTOPSIG` | Die Nummer des Signals, das zum Anhalten des Kindprozesses führte (das Anhalten des Kindprozesses) kann mit `&WIFSTOPPED` ermittelt werden.
`&WTERMSIG` | Die Nummer des Signals, das vom Kindprozess nicht beantwortet wurde und deshalb zu dessen Beenden führte (ob dies der Fall ist, kann mit `&WIFSIGNALED` ermittelt werden.
`&WUNTRACED` | `waitpid()` kehrt mit dem Status eines bereits gestoppten Kindprozesses zurück, dessen exit-Rückgabewert aber noch nicht abgefragt wurde.

| Funktionen für Informationen aus Konfigurationsdateien
| Funktionen für Datei- und Verzeichnis-Management

© 2007 Impressum