[Linux] Remplacement du programme de processus

[Linux] Remplacement du programme de processus

La signification du remplacement du programme de processus

Après avoir utilisé la fonction système fork pour créer un processus enfant sous le système Linux, le processus enfant ne peut exécuter qu'une partie du code hérité du processus parent. Si vous souhaitez que le processus enfant exécute un code séparé, vous devez remplacer le programme de processus .

Remplacement du programme de processus Meet

Les fichiers d'en-tête et les fonctions remplacés par le programme de traitement sont les suivants :

image-20230831104800830

Écrivez le code suivant pour voir le remplacement du programme de processus :

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  printf("进程程序替换前\n");
  printf("进程程序替换前\n");
  execl("/bin/ls", "ls", "-a", "-l", NULL);
  printf("进程程序替换后\n");
  printf("进程程序替换后\n");
  printf("进程程序替换后\n");
  return 0;
}

Compilez le code et exécutez-le pour voir les résultats :

image-20230831104439925

On peut voir qu'une fois le programme de processus remplacé, le processus n'exécute plus le code d'origine mais exécute à la place le code remplacé. Le code après la fonction de remplacement du processus n'est plus exécuté.Par conséquent, on peut voir que le remplacement du programme est un remplacement global.Après le remplacement, le code et les données d'origine n'existent plus.

Le principe du remplacement du programme de processus

Le remplacement du programme de processus consiste à transférer le code et les données du programme exécutable du disque vers la mémoire sans modifier l'ID dans la carte de processus, à remplacer le code et les données d'origine du processus et à modifier le mappage de la table de pages pour terminer le programme de processus. .remplacement, le schéma de principe est le suivant :

image-20230831104507648

  • Du point de vue du processus : le code et les données sont remplacés par le système d'exploitation.
  • Du point de vue du programme : son propre code et ses données sont chargés en mémoire.

Le principe de chargement du programme : Sous le système d'exploitation Linux, tout processus démarré est un processus enfant du processus shell. Pour démarrer le processus, le processus shell crée d'abord un PCB du processus enfant, puis utilise le code et les données du processus que nous avons écrit. Remplacez le processus enfant de ce processus shell pour terminer le chargement et le démarrage du processus.

Remplacement du programme de copie sur écriture en cours

Afin de faire l'expérience du remplacement du programme de copie sur écriture en cours, écrivez le code suivant :

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    printf("我是子进程,我的pid:%d\n", getpid());
    execl("/bin/ls", "ls", "-a", "-l", NULL);
  }
  waitpid(id, NULL, 0);
  printf("我是父进程,我的pid:%d\n", getpid());
  return 0;
}

Compilez le code, exécutez-le et affichez les résultats :

image-20230831104608439

On peut voir que le remplacement du programme de processus n'affecte pas le code et les données du processus parent, car lors du remplacement du code et des données du processus enfant, une copie sur écriture se produit. De plus, on peut voir que les données dans la zone de code peut en fait être modifiée.

Présentation de l'interface de remplacement du programme de processus

valeur de retour

La fonction de remplacement du programme de processus ne renverra une valeur qu'en cas d'échec de l'exécution. Si le remplacement du programme de processus échoue, elle renverra -1 et définira un code d'erreur. Étant donné que la fonction de remplacement du programme de processus est remplacée avec succès, le code de retour à l'intérieur de la fonction est également remplacé, il n'y aura donc aucune valeur de retour une fois l'exécution réussie. Une fois le remplacement échoué, puisque le remplacement du programme de processus ne modifiera pas la carte PCB, cela n'affectera pas le processus parent recevant le code de sortie du processus enfant.

Écrivez le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    int n = execl("/bin/lsss", "lsss", "-a", "-l", NULL);
    printf("我是子进程,我的id:%d, 程序替换失败,n: %d\n", getpid(), n);
    exit(1);
  }
  int status = 0;
  waitpid(id, &status, 0);
  printf("我是父进程,子进程退出码:%d\n", WEXITSTATUS(status));
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831104523903

Étant donné que le programme de remplacement que nous avons transmis était erroné, le remplacement du programme de processus a échoué, une valeur de retour de -1 a été reçue et le processus parent a également reçu le code de sortie -1 normalement.

Écrivez ensuite le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    int n = execl("/bin/ls", "ls", "hello.txt", NULL);//该文件不存在
    printf("我是子进程,我的id:%d, 程序替换失败,n: %d\n", getpid(), n);
    exit(1);
  }
  int status = 0;
  waitpid(id, &status, 0);
  printf("我是父进程,子进程退出码:%d\n", WEXITSTATUS(status));
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831102532182

On peut voir que même si le remplacement du programme réussit, cela n'affectera pas la réception du code de sortie du processus enfant.

fonction d'exécution

//execl函数声明
int execl(const char *path, const char *arg, ...);
  • paramètre path – le chemin du programme à remplacer
  • paramètre arg – paramètre variable, recevant les paramètres de ligne de commande du programme de remplacement, terminé par NULL

Écrivez le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  execl("/bin/ls", "ls", "-a", "-l", NULL);
  printf("进程程序替换失败\n");
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831102536883

fonction exécutive

//execv函数声明
int execv(const char *path, char *const argv[]);
  • paramètre path – le chemin du programme à remplacer
  • Paramètre argv – reçoit les arguments de ligne de commande du programme à remplacer, terminés par NULL

Écrivez le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  //execl("/bin/ls", "ls", "-a", "-l", NULL);
  char * const argv[] = {
    
    
    "ls",
    "-a",
    "-l",
    "-n",
    NULL
  };
  execv("/bin/ls", argv);
  printf("进程程序替换失败\n");
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831104539226

fonction execlp

//execlp函数声明
int execlp(const char *file, const char *arg, ...);
  • paramètre de fichier – le nom du programme à remplacer, le programme sera automatiquement trouvé dans le chemin de la variable d’environnement
  • paramètre arg – paramètre variable, recevant les paramètres de ligne de commande du programme de remplacement, terminé par NULL

Écrivez le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  execlp("ls", "ls", "-l", "-n", NULL);
  printf("进程程序替换失败\n");
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831104738842

fonction exécutable

//execvp函数声明
int execvp(const char *file, char *const argv[]);
  • paramètre de fichier – le nom du programme à remplacer, le programme sera automatiquement trouvé dans le chemin de la variable d’environnement
  • Paramètre argv – reçoit les arguments de ligne de commande du programme à remplacer, terminés par NULL

Écrivez le code suivant pour tester :

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  char * const argv[] = {
    
    
    "ls",
    "-l",
    "-n",
    NULL
  };
  execvp("ls", argv);
  printf("进程程序替换失败\n");
  return 0;
}

Compilez le code, exécutez-le et voyez les résultats :

image-20230831093047903

fonction exécutable

//execle函数声明
int execle(const char *path, const char *arg, ..., char * const envp[]);
  • paramètre path – le chemin du programme à remplacer
  • paramètre arg – paramètre variable, recevant les paramètres de ligne de commande du programme de remplacement, terminé par NULL
  • Paramètre envp - reçoit les variables d'environnement transmises au programme de remplacement, se termine par NULL et est transmis en écrasement. Le processus de réception ne recevra que les variables d'environnement transmises.

Écrivez la structure de répertoires de fichiers suivante :

image-20230831100637858

Utilisez le programme myproc et le programme otherproc pour les tests. Le contenu du code est le suivant

//myproc
#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  char * const envp[] = {
    
    
    "MYENV=YOUCANSEEME",
    NULL 
  };
  execle("../otherproc/otherproc", "otherproc", NULL, envp);
  printf("进程程序替换失败\n");
  return 0;
}
//otherproc
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{
    
    
  cout << " MYENV: " << (getenv("MYENV")==NULL?"NULL":getenv("MYENV")) << endl;
  cout << " PATH: " << (getenv("PATH")==NULL?"NULL":getenv("PATH")) << endl;
  return 0;
}

Utilisez le programme otherproc pour remplacer le programme myproc et transmettez uniquement le paramètre envp qui ne contient qu'une seule variable d'environnement.

Compilez le code, exécutez-le et voyez les résultats :

image-20230831101123814

Étant donné que la fonction execle utilise l'écrasement pour transmettre les variables d'environnement, le programme de remplacement ne transmet qu'une seule variable d'environnement.

Remplir:

  • Vous pouvez utiliser des variables globales environpour permettre au programme de remplacement d'obtenir toutes les variables d'environnement du processus parent.
  • Lorsque le processus shell crée un processus enfant, il appelle également une telle interface système pour transmettre des variables d'environnement.

fonction d'exécution

int execvpe(const char *file, char *const argv[], char *const envp[]);
  • paramètre de fichier – le nom du programme à remplacer, le programme sera automatiquement trouvé dans le chemin de la variable d’environnement
  • Paramètre argv – reçoit les arguments de ligne de commande du programme à remplacer, terminés par NULL
  • Paramètre envp - reçoit les variables d'environnement transmises au programme de remplacement, se termine par NULL et est transmis en écrasement. Le processus de réception ne recevra que les variables d'environnement transmises.

Connaissances supplémentaires

Règles de dénomination des fonctions de remplacement de programme :

  • l suffixe – reçoit les arguments de ligne de commande vers le programme de remplacement sous forme d’arguments variadiques
  • v suffixe – reçoit les arguments de ligne de commande du programme de remplacement sous forme de tableau de pointeurs
  • suffixe p – transmettez le nom du programme de remplacement et il sera automatiquement recherché dans le chemin de la variable d’environnement
  • e suffixe – reçoit les variables d’environnement du programme de remplacement sous forme d’un tableau de pointeurs

Tous les appels système de remplacement de programme de processus ci-dessus sont execvedes encapsulations de fonctions d'appel système. Différentes encapsulations doivent être plus adaptées à différents scénarios d'application.

Je suppose que tu aimes

Origine blog.csdn.net/csdn_myhome/article/details/132598332
conseillé
Classement