progsys:index
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
progsys:index [2016/03/05 05:47] – [Programmation Système] orel | progsys:index [2024/03/18 15:06] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 4: | Line 4: | ||
//Quelques exemples et corrections des TP de Programmation Système en L3 Info...// | //Quelques exemples et corrections des TP de Programmation Système en L3 Info...// | ||
+ | |||
+ | |||
+ | ==== Redirection de la sortie d' | ||
+ | |||
+ | <code c redir.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | int fd = open(" | ||
+ | dup2(fd, 2); close(fd); | ||
+ | printf(" | ||
+ | fprintf(stderr, | ||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
==== Commande ls ==== | ==== Commande ls ==== | ||
Line 159: | Line 181: | ||
</ | </ | ||
+ | |||
+ | ==== 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) | ||
+ | |||
+ | Le pipe est partagé naturellement entre FilsK-1 et FilsK. | ||
+ | |||
+ | |||
+ | <code C chaine1.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | 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], | ||
+ | close(tube[0]); | ||
+ | close(tube[1]); | ||
+ | break; | ||
+ | | ||
+ | } else { /* fils */ | ||
+ | dup2(tube[0], | ||
+ | close(tube[0]); | ||
+ | close(tube[1]); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | execlp(argv[i+1], | ||
+ | perror(" | ||
+ | |||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 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 < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | 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], | ||
+ | close(tube[0]); | ||
+ | close(tube[1]); | ||
+ | break; | ||
+ | | ||
+ | } else { /* père */ | ||
+ | dup2(tube[0], | ||
+ | close(tube[0]); | ||
+ | close(tube[1]); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | execlp(argv[i+1], | ||
+ | perror(" | ||
+ | |||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | __Indice__ : Dans ce cas, un même père crée tous les fils de la façon suivante... mais cela n' | ||
+ | | ||
+ | Père | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | ==== Calculer en Pipeline ==== | ||
==Générer/ | ==Générer/ | ||
Line 243: | 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 661: | Line 790: | ||
int k = atoi(argv[1]); | int k = atoi(argv[1]); | ||
- | for(int s = 1 ; s < argc ; s++) | + | for(int s = 2 ; s < argc ; s++) |
for(int i = 0 ; i < k ; i++) { | for(int i = 0 ; i < k ; i++) { | ||
kill(ppid, atoi(argv[s])); | kill(ppid, atoi(argv[s])); | ||
Line 680: | Line 809: | ||
sigemptyset(& | sigemptyset(& | ||
| | ||
- | for(int sig = 2 ; sig < NSIGNORT ; sig++) { | + | for(int sig = 1 ; sig < NSIGNORT ; sig++) { |
sigaction(sig, | sigaction(sig, | ||
tab[sig] = 0; | tab[sig] = 0; | ||
Line 788: | Line 917: | ||
| | ||
return 0; | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Open Pipe Command (exo 3, DS 2017-2018) ==== | ||
+ | |||
+ | On souhaite disposer d’une fonction // | ||
+ | |||
+ | 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 < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define HELLO "hello world!" | ||
+ | |||
+ | 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]); | ||
+ | /* cmd writes in pr[1]=1 & reads in pw[0]=0 */ | ||
+ | dup2(pw[0], | ||
+ | close(pw[0]); | ||
+ | execvp(cmd, argv); | ||
+ | perror(" | ||
+ | exit(EXIT_FAILURE); | ||
+ | } | ||
+ | close(pw[0]); | ||
+ | return pid; /* success > 0*/ | ||
+ | } | ||
+ | |||
+ | int main(int argc, char * argv[]) | ||
+ | { | ||
+ | int fd[2]; | ||
+ | char* cmd[] = {" | ||
+ | int pid = open_pipe_command(fd, | ||
+ | if(pid <= 0) return EXIT_FAILURE; | ||
+ | write(fd[1], | ||
+ | close(fd[1]); | ||
+ | char msg[128]; | ||
+ | int r = read(fd[0], msg, 128); | ||
+ | printf(" | ||
+ | close(fd[0]); | ||
+ | waitpid(pid, | ||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== 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 < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | void handler(int sig) | ||
+ | { | ||
+ | printf(" | ||
+ | } | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | signal(SIGINT, | ||
+ | |||
+ | if (fork() == 0) | ||
+ | { | ||
+ | printf(" | ||
+ | pause(); | ||
+ | printf(" | ||
+ | exit(EXIT_SUCCESS); | ||
+ | } | ||
+ | |||
+ | printf(" | ||
+ | pause(); | ||
+ | printf(" | ||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Timeout ==== | ||
+ | |||
+ | <code C executer-avant-delai.c> | ||
+ | |||
+ | #define _GNU_SOURCE | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | static struct sigaction sa, old; | ||
+ | static sigjmp_buf env; | ||
+ | |||
+ | static void myalarm(int sig) | ||
+ | { | ||
+ | printf(" | ||
+ | siglongjmp(env, | ||
+ | } | ||
+ | |||
+ | 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(& | ||
+ | sigaction(SIGALRM, | ||
+ | |||
+ | alarm(delai_en_seconde); | ||
+ | if(sigsetjmp(env, | ||
+ | fun(parametre); | ||
+ | else | ||
+ | ret = 0; // alarm | ||
+ | alarm(0); | ||
+ | sigaction(SIGALRM, | ||
+ | return ret; | ||
} | } | ||
</ | </ |
progsys/index.1457156874.txt.gz · Last modified: 2024/03/18 15:05 (external edit)