Steuern Sie den Daemon-Prozess von einem anderen Prozess in C
-
Verwenden Sie die Funktionen
fork
undsetsid
, um einen Daemon-Prozess zu erstellen -
Verwenden Sie die Funktion
daemon
, um einen Daemon-Prozess zu erstellen
In diesem Artikel werden verschiedene Methoden zum Steuern des Daemon-Prozesses von einem anderen Prozess in C aus vorgestellt.
Verwenden Sie die Funktionen fork
und setsid
, um einen Daemon-Prozess zu erstellen
Daemon-Prozesse weisen mehrere Merkmale auf, z. B., dass es sich um Prozesse mit langer Laufzeit handelt, und Daemons können beim Systemstart gestartet werden. Der Daemon-Prozess kann über die Benutzerbefehle gesteuert werden, die ihn zwingen, beim Start zu beenden, anzuhalten oder sogar zu deaktivieren. Das übliche Szenario würde jedoch dazu führen, dass ein Dämon beim Herunterfahren des Systems mithilfe einiger systemspezifischer Skripts beendet wird. Daemons werden im Allgemeinen ohne steuerndes Terminal im Hintergrund ausgeführt, und die Programme, die solche Funktionen verwenden, sollten verschiedene Signalhandler implementieren, um externe Interrupts zu verarbeiten.
Es gibt mehrere Methoden, um einen Dämonprozess zu erstellen und zu überwachen. In diesem Beispiel wird jedoch die Erstellungsphase demonstriert, in der wir eine fork
-Funktion aufrufen, um einen untergeordneten Prozess zu erstellen. Dann wird der übergeordnete Prozess beendet und das untergeordnete Element setzt die Ausführung fort, da es das untergeordnete Element des init
-Prozesses wird (auf Linux-Systemen ist der init
-Prozess der erste Prozess beim Start). Der untergeordnete Prozess ruft die Funktion setsid
auf, um eine neue Sitzung zu starten und den Prozess vom steuernden Terminal zu entfernen. Schließlich rufen wir noch einmal fork
auf und verlassen den übergeordneten Prozess, um sicherzustellen, dass unser Daemon kein steuerndes Terminal erhält. Jetzt führen wir den Daemon-Prozess aus. Es ist wichtig, einen SIGTERM
-Signal-Handler zu registrieren, um eine Bereinigung der Ressourcen und einen ordnungsgemäßen Exit durchzuführen, wenn das System oder der Benutzer den entsprechenden Interrupt liefert.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
void cleanupRoutine(int signal_number) {
write(STDERR_FILENO, "hello", 5);
_exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
fprintf(stderr, "[pid - %d] running...\n", getpid());
switch (fork()) {
case -1:
errExit("fork");
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
fprintf(stderr, "[pid - %d] running...\n", getpid());
if (setsid() == -1) errExit("setsid");
switch (fork()) {
case -1:
errExit("fork");
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
fprintf(stderr, "[pid - %d] running...\n", getpid());
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (1) {
getpid();
}
exit(EXIT_SUCCESS);
}
Verwenden Sie die Funktion daemon
, um einen Daemon-Prozess zu erstellen
Obwohl das vorherige Beispiel scheinbar korrekten Code zeigt, fehlen die Schritte, um sicherzustellen, dass alle vom übergeordneten Element geerbten offenen Dateideskriptoren geschlossen sind. Das Arbeitsverzeichnis wurde geändert, die Standardeingabe nach /dev/null
umgeleitet und so weiter. Diese Schritte garantieren, dass bestimmte Funktionen nicht fehlschlagen, wenn der Dämon sie aufruft, und dass auch ein seltsames Verhalten nicht beobachtet wird.
Wenn Sie beispielsweise das vorherige Programm über das Terminalfenster gestartet und dann das Signal SIGTERM
an den Daemon-Prozess gesendet haben, wird die Funktion write
vom Signalhandler cleanupRoutine
auch nach der neuen Eingabeaufforderung auf demselben Terminal gedruckt angezeigt. Somit wird die Funktion daemon
von der GNU C-Bibliothek bereitgestellt. Die oben genannten Schritte werden automatisch ausgeführt, um einen sauberen Kontext für den neu erstellten Daemon-Prozess sicherzustellen. Die Funktion daemon
akzeptiert zwei ganzzahlige Argumente: das erste (wenn gleich Null), das angibt, ob das aktuelle Arbeitsverzeichnis in das Stammverzeichnis geändert werden soll. Die zweite Ganzzahl (falls gleich Null) gibt an, ob die Standard-E/A-Streams nach /dev/null
umgeleitet werden sollen.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
void cleanupRoutine(int signal_number) {
write(STDERR_FILENO, "hello", 5);
_exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
fprintf(stderr, "[pid - %d] running...\n", getpid());
if (daemon(0, 0) == -1) errExit("daemon");
fprintf(stderr, "[pid - %d] running...\n", getpid());
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) errExit("sigfillset");
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) errExit("sigaction");
while (1) {
getpid();
}
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook