Contrôler le processus du démon à partir d'un autre processus en C

Jinku Hu 12 octobre 2023
  1. Utilisez les fonctions fork et setsid pour créer un processus démon
  2. Utilisez la fonction daemon pour créer un processus daemon
Contrôler le processus du démon à partir d'un autre processus en C

Cet article présentera plusieurs méthodes sur la façon de contrôler le processus démon à partir d’un autre processus dans C.

Utilisez les fonctions fork et setsid pour créer un processus démon

Les processus démons ont plusieurs caractéristiques, telles que ce sont des processus de longue durée et les démons peuvent être démarrés au démarrage du système. Le processus démon peut être contrôlé à partir des commandes utilisateur qui le forcent à se terminer ou à mettre en pause ou même à se désactiver au démarrage. Cependant, le scénario courant impliquerait un démon se terminant à l’arrêt du système à l’aide de certains scripts spécifiques au système. Les démons fonctionnent généralement en arrière-plan sans terminal de contrôle, et les programmes qui utilisent de telles fonctionnalités devraient implémenter divers gestionnaires de signaux pour gérer les interruptions externes.

Il existe plusieurs méthodes pour créer un processus démon et le surveiller, mais dans cet exemple, nous démontrons l’étape de création, où nous appelons une fonction fork pour créer un processus enfant. Ensuite, le processus parent se termine, et l’enfant continue l’exécution en devenant l’enfant du processus init (sur les systèmes Linux, le processus init est le premier processus au démarrage). Le processus fils appelle la fonction setsid pour démarrer une nouvelle session et supprimer le processus du terminal de contrôle. Enfin, nous appelons à nouveau fork et sortons du processus parent pour nous assurer que notre démon n’acquiert pas de terminal de contrôle. Nous exécutons maintenant le processus démon; il est important d’enregistrer un gestionnaire de signal SIGTERM pour effectuer tout nettoyage des ressources et sortie gracieuse lorsque le système ou l’utilisateur délivre l’interruption correspondante.

#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);
}

Utilisez la fonction daemon pour créer un processus daemon

Même si l’exemple précédent montre un code apparemment correct, il ne dispose pas des étapes pour garantir que tous les descripteurs de fichiers ouverts hérités du parent sont fermés; le répertoire de travail a changé, redirige l’entrée standard vers /dev/null, et ainsi de suite. Ces étapes garantissent que certaines fonctions n’échoueront pas si le démon les appelle et que certains comportements étranges ne sont pas observés.

Par exemple, si vous avez démarré le programme précédent depuis la fenêtre du terminal et que vous envoyez ensuite le signal SIGTERM au processus démon, la fonction write du gestionnaire de signal cleanupRoutine s’imprimera sur le même terminal même après que la nouvelle invite est affiché. Ainsi, la fonction daemon est fournie par la bibliothèque GNU C. Il prend automatiquement en charge les étapes ci-dessus pour garantir un contexte propre pour le processus démon nouvellement créé. La fonction démon prend deux arguments entiers: le premier (s’il est égal à zéro) spécifiant si le répertoire de travail courant doit être changé en répertoire racine. Le deuxième entier (s’il est égal à zéro) indiquant si les flux d’E/S standard doivent être redirigés vers /dev/null.

#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);
}
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Article connexe - C Process