User Tools

Site Tools


progsys:index

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
progsys:index [2017/09/28 15:09] orelprogsys:index [2024/03/18 15:06] (current) – external edit 127.0.0.1
Line 181: Line 181:
 </code> </code>
  
 +
 +==== Une chaîne de commandes  ====
 +
 +On souhaite écrire un programme //./chaine cmd0 cmd1 cmd2 ... cmdN// qui exécute une chaîne de commandes de la façon suivante :
 +
 +  ./cmd1 | ./cmd2 | ./cmd3 | ... | cmdN
 +
 +Dans cette première version, chaque fils crée un nouveau fils en cascade :
 +
 +  Père ==> Fils0 ==> Fils1 ==> ... ==> FilsN-1
 +  (cmd0)   (cmd1)   (cmdN-1)           cmdN
 +
 +Le pipe est partagé naturellement entre FilsK-1 et FilsK.
 +
 +
 +<code C chaine1.c>
 +#include <unistd.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +int main(int argc, char *argv[])
 +{
 +  int nb = argc-1;
 +  int tube[2];
 +  int i;
 +  
 +  for(i=0; i < nb-1; i++) {
 +    pipe(tube);
 +    if(fork() != 0) { /* père */
 +      dup2(tube[1],1);
 +      close(tube[0]); 
 +      close(tube[1]);
 +      break; 
 +      
 +    } else { /* fils */
 +      dup2(tube[0],0);
 +      close(tube[0]); 
 +      close(tube[1]);
 +    }
 +  }  
 +
 +  execlp(argv[i+1], argv[i+1], NULL); 
 +  perror("execlp"); 
 +
 +  return EXIT_SUCCESS;
 +}
 +</code>
 +
 +Pour tester ce programme, nous pouvons exécuter les commandes suivantes :
 +
 +  $ echo bbb > file.txt
 +  $ echo aaa >> file.txt
 +  $ echo aaa >> file.txt
 +  $ echo ccc >> file.txt
 +  $ ./chaine cat sort uniq < file.txt
 +  aaa
 +  bbb
 +  ccc
 +
 +
 +Examinons maintenant une autre version... Nous allons juste inverser le code du père et du fils dans la boucle for ! Expliquer par quel miracle ce code peut marcher ?
 +
 +<code C chaine2.c>
 +#include <unistd.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +int main(int argc, char *argv[])
 +{
 +  int nb = argc-1;
 +  int tube[2];
 +  int i;
 +  
 +  for(i=0; i < nb-1; i++) {
 +    pipe(tube);
 +    if(fork() == 0) { /* fils */
 +      dup2(tube[1],1);
 +      close(tube[0]); 
 +      close(tube[1]);
 +      break; 
 +      
 +    } else { /* père */
 +      dup2(tube[0],0);
 +      close(tube[0]); 
 +      close(tube[1]);
 +    }
 +  }  
 +
 +  execlp(argv[i+1], argv[i+1], NULL); 
 +  perror("execlp"); 
 +
 +  return EXIT_SUCCESS;
 +}
 +</code>
 +
 +__Indice__ :  Dans ce cas, un même père crée tous les fils de la façon suivante... mais cela n'explique pas tout !
 +  
 +  Père             (cmdN)
 +       ==> Fils0   (cmd0)
 +       ==> Fils1   (cmd1) 
 +       ==> 
 +       ... 
 +       ==> FilsN-1 (cmdN-1)
 +
 +
 +
 +==== Calculer en Pipeline ====
  
 ==Générer/afficher un fichier de k double== ==Générer/afficher un fichier de k double==
Line 265: Line 372:
   /* création de N fils */   /* création de N fils */
   for(int i = 0 ; i < N ; i++) {    for(int i = 0 ; i < N ; i++) { 
-    /* fils i qui utilise tubes[i-1] et tubes[i] */+    /* fils i qui utilise tubes[i] et tubes[i+1] */
     if(fork() == 0) {      if(fork() == 0) { 
       /* TODO: redirection tube */       /* TODO: redirection tube */
Line 683: Line 790:
     int k = atoi(argv[1]);     int k = atoi(argv[1]);
  
-    for(int s = ; s < argc ; s++)+    for(int s = ; s < argc ; s++)
       for(int i = 0 ; i < k ; i++) {       for(int i = 0 ; i < k ; i++) {
  kill(ppid, atoi(argv[s])); // envoi signal  kill(ppid, atoi(argv[s])); // envoi signal
Line 702: Line 809:
     sigemptyset(&act.sa_mask);     sigemptyset(&act.sa_mask);
      
-    for(int sig = ; sig < NSIGNORT ; sig++) {+    for(int sig = ; sig < NSIGNORT ; sig++) {
       sigaction(sig, &act, NULL);       sigaction(sig, &act, NULL);
       tab[sig] = 0;       tab[sig] = 0;
Line 810: Line 917:
      
   return 0;   return 0;
 +}
 +</code>
 +
 +==== Open Pipe Command (exo 3, DS 2017-2018) ====
 +
 +On souhaite disposer d’une fonction //open_pipe_command// dont le profil est :
 +
 +  int open_pipe_command (int *fd, char *cmd, char **argv)
 +
 +Cette fonction crée un processus chargé d’exécuter la commande //cmd// avec les arguments //argv//, et renvoie deux descripteurs (dans le tableau fd) permettant respectivement d’écrire vers l’entrée standard de la commande (descripteur fd[1]) et de lire depuis la sortie standard de la commande (descripteur fd[0]). On utilisera pour cela deux tubes permettant d’établir une connexion bidirectionnelle avec le processus exécutant la commande. La fonction retournera le //pid// du processus fils exécutant la commande.
 +
 +<code C open_pipe_command.c>
 +/* gcc -Wall -std=c99 open_pipe_command.c && ./a.out */
 +
 +#include <stdio.h>
 +#include <unistd.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <sys/types.h>
 +#include <sys/wait.h>
 +
 +#define HELLO "hello world!" // 12 
 +
 +int open_pipe_command(int * fd, char * cmd, char **argv)
 +{
 +  int pr[2]; pipe(pr); 
 +  int pw[2]; pipe(pw); 
 +  /* user reads in fd[0]=pr[0] & writes in fd[1]=pw[1] */
 +  fd[0] = pr[0]; fd[1] = pw[1];   
 +  int pid = fork();
 +  if(pid == 0) { /* child */        
 +    close(pw[1]); close(pr[0]); /* useless */
 +    /* cmd writes in pr[1]=1 & reads in pw[0]=0 */
 +    dup2(pw[0],0); dup2(pr[1],1); 
 +    close(pw[0]); close(pr[1]); 
 +    execvp(cmd, argv); 
 +    perror("Error execvp");
 +    exit(EXIT_FAILURE);
 +  }
 +  close(pw[0]); close(pr[1]); /* useless */
 +  return pid; /* success > 0*/
 +}
 +
 +int main(int argc, char * argv[])
 +{
 +  int fd[2];
 +  char* cmd[] = {"tr", "a-z", "A-Z", NULL};
 +  int pid = open_pipe_command(fd, *cmd, cmd);
 +  if(pid <= 0) return EXIT_FAILURE;
 +  write(fd[1], HELLO, strlen(HELLO)+1);
 +  close(fd[1]);
 +  char msg[128];
 +  int r = read(fd[0], msg, 128);  
 +  printf("msg[%d]: %s -> %s\n", r, HELLO, msg);
 +  close(fd[0]);
 +  waitpid(pid, NULL, 0);
 +  return EXIT_SUCCESS;
 +}
 +</code>
 +
 +==== Ctrl-C ====
 +
 +Un processus fils est dans le même PGID (process group ID) que son père par defaut (pgid père = pgid fils = pid père). Un kill sur -pid du père envoie le signal à tous le groupe, donc au fils également...
 +
 +<code C sigint.c>
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <unistd.h>
 +#include <signal.h>
 +#include <sys/types.h>
 +
 +void handler(int sig)
 +{
 +    printf("paf\n");
 +}
 +
 +int main(void)
 +{
 +    signal(SIGINT, handler); // TODO: utiliser sigaction() plutôt que signal() !
 +
 +    if (fork() == 0)
 +    {
 +        printf("child: %d %d\n", getpid(), getpgid(0));
 +        pause();
 +        printf("child: bye bye!\n");
 +        exit(EXIT_SUCCESS);
 +    }
 +
 +    printf("father: %d %d\n", getpid(), getpgid(0));
 +    pause();
 +    printf("father: bye bye!\n");
 +    return EXIT_SUCCESS;
 +}
 +</code>
 +
 +
 +==== Timeout ====
 +
 +<code C executer-avant-delai.c>
 +
 +#define _GNU_SOURCE
 +#include <unistd.h>
 +#include <signal.h>
 +#include <stdio.h>
 +#include <setjmp.h>
 +
 +static struct sigaction sa, old;
 +static sigjmp_buf env;
 +
 +static void myalarm(int sig)
 +{
 +  printf("alarm!\n");
 +  siglongjmp(env,1);
 +}
 +
 +int executer_avant_delai( void (*fun)(void *), void *parametre, int delai_en_seconde)
 +{
 +  int ret = 1;
 +  sa.sa_handler = myalarm;
 +  sa.sa_flags = 0; // SA_RESETHAND;
 +  sigemptyset(&sa.sa_mask);
 +  sigaction(SIGALRM, &sa, &old);
 +
 +  alarm(delai_en_seconde);
 +  if(sigsetjmp(env,1) == 0)
 +    fun(parametre);
 +  else
 +    ret = 0; // alarm
 +  alarm(0);
 +  sigaction(SIGALRM, &old, NULL);
 +  return ret;
 } }
 </code> </code>
progsys/index.1506611341.txt.gz · Last modified: 2024/03/18 15:05 (external edit)