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
Last revisionBoth sides next revision
progsys:index [2015/12/10 14:37] – [Programmation Système] orelprogsys:index [2020/11/06 11:14] – [Ctrl-C] orel
Line 3: Line 3:
 __Site Web__ : http://dept-info.labri.fr/ENSEIGNEMENT/prs __Site Web__ : http://dept-info.labri.fr/ENSEIGNEMENT/prs
  
-//Quelques exemples et corrections sur les TPs seront bientôt ajoutés sur cette page.//+//Quelques exemples et corrections des TP de Programmation Système en L3 Info...// 
 + 
 + 
 +==== Redirection de la sortie d'erreur ==== 
 + 
 +<code c redir.c> 
 +#include <stdlib.h> 
 +#include <stdio.h> 
 +#include <unistd.h> 
 +#include <sys/types.h> 
 +#include <sys/stat.h> 
 +#include <fcntl.h> 
 +        
 +int main(int argc, char *argv[])  
 +{   
 +  int fd = open("error", O_WRONLY|O_CREAT|O_APPEND, 0644); 
 +  dup2(fd, 2); close(fd); 
 +  printf("hello on stdout\n"); 
 +  fprintf(stderr, "hello on stderr\n");   
 +  return EXIT_SUCCESS; 
 +
 +</code> 
  
-<html> 
-<iframe width="800" height="500" frameborder="0" 
-        src="http://pythontutor.com/iframe-embed.html#code=x+%3D+5%0Ay+%3D+10%0Az+%3D+x+%2B+y&cumulative=false&py=2&curInstr=3"> 
-</iframe> 
-</html> 
 ==== Commande ls ==== ==== Commande ls ====
  
Line 164: 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 248: 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 666: 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 685: 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 793: 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.txt · Last modified: 2024/03/18 15:06 by 127.0.0.1