0% ont trouvé ce document utile (0 vote)
70 vues192 pages

Cours

Ce document présente un cours sur la programmation système sous Unix en C, destiné aux étudiants de Licence 2 en informatique à l'Université Paris-Saclay. Il aborde les raisons de l'utilisation d'Unix et du langage C, les objectifs du cours, les attentes en matière de travail et d'évaluation, ainsi que des concepts fondamentaux d'Unix tels que les fichiers, les processus et les permissions. Le document inclut également des informations sur l'utilisation d'Unix sur différents systèmes d'exploitation et les origines d'Unix.

Transféré par

rayantch7
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
70 vues192 pages

Cours

Ce document présente un cours sur la programmation système sous Unix en C, destiné aux étudiants de Licence 2 en informatique à l'Université Paris-Saclay. Il aborde les raisons de l'utilisation d'Unix et du langage C, les objectifs du cours, les attentes en matière de travail et d'évaluation, ainsi que des concepts fondamentaux d'Unix tels que les fichiers, les processus et les permissions. Le document inclut également des informations sur l'utilisation d'Unix sur différents systèmes d'exploitation et les origines d'Unix.

Transféré par

rayantch7
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Franck Pommereau • 1 / 172

Programmation système
sous Unix en C

Franck Pommereau

Université Paris-Saclay / Évry—Val d’Essonne

Licence 2 informatique
Franck Pommereau Introduction • À propos du cours 2 / 172

Objectif : comprendre comment programmer avec Unix


Pourquoi Unix ? others
iOS/MacOS

▶ le plus répandu / standard industriel Systèmes


Windows

sur les
Android, iOS, MacOS, Web, IoT, HPC, . . .

Gartner, 2015
▶ équipements

Windows se cantonne aux PC


vendus

▶ nombreuses versions libres / conception ouverte et documentée Android

Pourquoi C ?
▶ Unix est programmé en C
▶ C a été développé pour Unix
Objectifs : comprendre les mécanismes de base
▶ système de fichiers
▶ entrées/sorties
▶ processus
Franck Pommereau Introduction • À propos du cours 3 / 172

Travail attendu
▶ prendre des notes en cours ce qui est dit et qui n’est pas sur les diapos
▶ comprendre et connaître le cours
☞ le par-cœur n’est ni nécessaire ni suffisant
▶ préparer et réaliser les travaux pratiques
☞ assister au séances est nécessaire mais pas suffisant
▶ chercher des informations/explications supplémentaires :
▶ les livres de la bibliothèque universitaire
▶ sites Web
▶ sur les appels système : les pages de manuel (man)
▶ sur le langage C : beaucoup de tutoriels/cours en ligne
recoupez les informations
▶ vos enseignant·e·s
▶ posez des questions
▶ demandez des précisions
▶ vérifiez que vous comprenez
▶ ...
Franck Pommereau Introduction • À propos du cours 4 / 172

Travaux pratiques et évaluation

1. L’énoncé donne des exercices pour la fois suivante.


▶ première séance : prise en main et instructions
2. Vous préparez les exercices à la maison.
▶ http://cow.ibisc.univ-evry.fr
3. Vous soumettez votre solution en ligne.
▶ http://badass.ibisc.univ-evry.fr
▶ diagnostic automatique immédiat
▶ autant de soumissions que vous le souhaitez
4. En séance, l’enseignant·e vous interroge sur vos solutions.
5. Toutes ces évaluations cumulées forment votre note.
▶ contrôle continu intégral
▶ pas d’examen
▶ seconde chance ≃ séance de TD
Franck Pommereau Introduction • À propos du cours 5 / 172
kill 1
Les pages de manuel kill 2

▶ Unix embarque sa propre documentation


▶ pages organisée en sections
1. Executable programs or shell commands 6. Games
2. System calls 7. Miscellaneous
3. Library calls 8. System administration commands
4. Special files 9. Kernel routines (GNU/Linux)
5. File formats and conventions

▶ chaque page contient des parties standards


NAME OPTIONS ENVIRONMENT NOTES SEE ALSO
SYNOPSIS EXIT STATUS FILES BUGS
CONFIGURATION RETURN VALUE VERSIONS EXAMPLE
DESCRIPTION ERRORS CONFORMING TO AUTHORS

▶ consultable avec la commande man


man kill ⇒ première page s’appelant kill ⇒ section 1
man 2 kill ⇒ appel système kill de la section 2
☞ fonctionne aussi dans un moteur de recherche Web
Franck Pommereau Introduction • À propos du cours 5 / 172
kill 1
Les pages de manuel kill 2

▶ Unix embarque sa propre documentation


▶ pages organisée en sections
1. Executable programs or shell commands 6. Games
2. System calls 7. Miscellaneous
3. Library calls 8. System administration commands
4. Special files 9. Kernel routines (GNU/Linux)
5. File formats and conventions

▶ chaque page contient des parties standards


NAME OPTIONS ENVIRONMENT NOTES SEE ALSO
SYNOPSIS EXIT STATUS FILES BUGS
CONFIGURATION RETURN VALUE VERSIONS EXAMPLE
DESCRIPTION ERRORS CONFORMING TO AUTHORS

▶ consultable avec la commande man


man kill ⇒ première page s’appelant kill ⇒ section 1
man 2 kill ⇒ appel système kill de la section 2
☞ fonctionne aussi dans un moteur de recherche Web
Franck Pommereau Introduction • Unix 6 / 172

Utiliser Unix sur son ordinateur


▶ avec MacOS
▶ c’est un Unix, rien à faire
▶ avec Windows 10+
▶ installer Windows Subsystem for Linux (WSL)
▶ “vraie” distribution Ubuntu
▶ avec GNU/Linux (ou Free-/Open-/Net-BSD)
▶ dans une machine virtuelle (VirtualBox par exemple)
▶ dans une partition en “double-boot”
▶ en remplacement de Windows (et installer Windows dans une VM)
▶ choisir une distribution
▶ “rustique” ⇒ on apprend plus (Debian, Arch, Gentoo, . . .)
▶ “policée” ⇒ plus facile et rapide (Mint, Ubuntu, Fedora, . . .)
▶ il en existe des milliers
▶ pour le travail ⇒ utiliser une distribution “majeure”
http://distrowatch.com/dwres.php?resource=major
▶ sinon ⇒ on essaye, on change, on s’amuse. . .
▶ installer les outil de développement
Franck Pommereau Introduction • Unix 7 / 172

Origines d’Unix

auteur inconnu, domaine public


▶ créé dans les années 70 par Ken Thompson et Dennis Ritchie
▶ initialement écrit en assembleur
▶ C est créé dès 1971 pour réécrire Unix
▶ adopté par la DARPA Defense Advanced Research Projects Agency
▶ sert de base au développement de TCP/IP puis d’Internet
▶ 1988 : POSIX normalise les API Thompson et Ritchie en 1973
▶ 1991 : Linux est développé indépendemment par Linus Torvalds
▶ fonctionne sur PC
▶ fédère une communauté
▶ complète le projet GNU
▶ 1998 : MacOS X d’Apple
▶ 2007 :
▶ Android de Google (Linux)
▶ iOS d’Apple (Darwin)
Franck Pommereau Introduction • Unix 8 / 172

Unix et ∗nix
1970 1980 1990 2000 2010 Time

FreeBSD 12.0

Guillem, Wereon, Hotmocha (domaine public, via Wikimedia Commons)


DragonFly BSD 5.6
Matthew Dillon

NetBSD 8.1
BSD family
OpenBSD 6.6
Theo de Raadt
BSD (Berkeley Software Distribution) 4.4
Bill Joy
SunOS 4.1.4
Darwin 19.0
NextStep 3.3
macOS 10.15
Xenix OS Apple
Microsoft/SCO
GNU/Hurd 0.9
GNU
Richard Stallman Linux 5.3
Minix Linus Torvalds
3.4
Andrew S. Tanenbaum

Research UNIX 10.5


Bell Labs: Ken Thompson,
Dennis Ritchie, et al. CommercialUNIX UnixWare
AT&T Univel/SCO
Solaris 11.4
Sun/Oracle
System III & V family HP-UX 11i v 3

AIX 7.2
IBM
IRIX 6.5.30
SGI
Franck Pommereau Introduction • Unix 9 / 172

POSIX
Portable Operating System Interface/UniX (IEEE 1003)

▶ famille de normes techniques


▶ définit :
▶ les API (Application Programming Interface)
▶ l’interface utilisateur : Bourne shell
▶ les commandes de base : awk, echo, . . .
▶ les services de base
▶ les fonctionnalités du système de fichiers
▶ etc.
▶ objectif : garantir la portabilité des applications entre versions d’Unix
▶ norme payante ⇒ alternatives
▶ Single Unix Specification
▶ Linux Standard Base
Franck Pommereau Introduction • Unix 10 / 172

Structure générale

applications
shell
appels systèmes

noyau

bibliothèques
Franck Pommereau Introduction • Unix 11 / 172

Concepts fondamentaux •◦◦


▶ fichier : des données stockées (généralement) sur un disque
▶ “tout est fichier” ⇒ il existe des fichiers spéciaux sans disque associé
▶ répertoire : catalogue de fichiers, accessibles par leurs noms
▶ / est la racine
▶ il y a aussi des sous-répertoires ⇒ arborescence
▶ tout répertoire contient . (lui-même) et .. (son parent)
▶ système de fichiers : organisation des fichiers issus de différents disques en une
arborescence unifiée
▶ mais aussi : “format” d’un disque pour y organiser un arborescence
▶ processus : un programme en train de s’exécuter
▶ avec ses propres données et instructions
▶ isolé des autres processus
▶ accède à une abstraction privée de la machine (mémoire, fichiers, CPU, . . .)
▶ au sein d’une hiérarchie (parents/enfants)
il y a des zombies et des démons
Franck Pommereau Introduction • Unix 12 / 172

Concepts fondamentaux ••◦

▶ utilisateurs et groupes : les identités des processus


▶ juste des numéros : uid et gid
▶ /etc/password et /etc/group ⇒ associés à d’autres informations
▶ les comptes utilisateurs ne sont que des cas particuliers
▶ uid = 0 ⇒ root (administrateur)
▶ permissions : droits d’accès associés aux fichiers
▶ vérifiés en fonction de l’identité du processus qui tente l’accès
▶ noyau : le cœur du système d’exploitation
▶ par exemple Linux, Hurd, XNU, . . .
▶ gère l’accès au matériel (mémoire, périphériques, CPU)
et aux ressources (fichiers, processus)
▶ gère les processus (isolation, partage du temps CPU)
▶ physiquement isolé des processus
▶ le noyau a sa zone de mémoire dédiée
▶ les processus partagent le reste (mais la mémoire virtuelle les isole)
Franck Pommereau Introduction • Unix 13 / 172

Concepts fondamentaux •••

▶ appel systèmes : service demandé au noyau par un processus


▶ par exemple : ouvrir un fichier, créer un processus, etc.
▶ Linux/x86 ⇒ une interruption ⇒ bascule dans le noyau (trappe)
▶ le noyau exécute du code pour le compte du processus
▶ bibliothèque système : ensemble des fonctions C chargées de réaliser les appels systèmes
(portabilité + facilité d’utilisation)
▶ en complément de la libc
▶ sous GNU/Linux : regroupés dans la glibc
▶ concrétisées par des fichiers de header (.h)
▶ environnement de développement : un compilateur C, la libc, et les bibliothèques
système
▶ sous GNU/Linux : GCC et les headers Linux
▶ on peut faire de la programmation système dans d’autres langages
▶ proposent des adaptateurs de la bibliothèque système
▶ savent communiquer avec C
Franck Pommereau Introduction • Unix 14 / 172

Identités et privilèges

▶ identité vs permissions ⇒ autorisations


▶ compte root ⇒ privilégié
▶ certains appels systèmes. . . (setuid 2 )
▶ certaines actions. . . (ouvrir un port réseau < 1024)
▶ certaines commandes. . . (su 1 )
▶ certains fichiers. . . (/etc/shadow)
. . . sont réservés à root
▶ capacités POSIX
▶ permissions détaillées
▶ évitent “le tout ou rien”
▶ groupes secondaires ⇒ propriétaires de. . .
▶ . . . fichiers spéciaux (/dev/audio)
▶ . . . programmes
⇒ les membres du groupe peuvent accéder à ces ressources
Franck Pommereau Introduction • Structure du cours 15 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • 16 / 172

Sommaire

Rappels de C
Compilation
Contrôle de flot
Types et constructeurs de types
Erreurs
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • Compilation 17 / 172

Sommaire

Rappels de C
Compilation
Contrôle de flot
Types et constructeurs de types
Erreurs
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • Compilation 18 / 172
printf 3
Hello world !

hello.c
1 #include <stdio.h>
2
3 int main (void) { // commentaire
4 printf("Hello world!\n"); /* commentaire aussi */
5 }

$ gcc -o hello hello.c


$ ./hello
Hello world!
$

dans ce cours
▶ on utilise GCC et Bash sous GNU/Linux
▶ autre compilateur/shell ⇒ autre commandes (mais mêmes principes)
Franck Pommereau Rappels de C • Compilation 19 / 172
scanf 3
Compilation séparée free 3

hello-read.c hello.h
1 #include <stdio.h> 1 char* readname (char*);
2 char *readname (char *msg) { 2 void printhello (char*);
3 char *txt; hello-main.c
4 printf("%s ", msg); 1 #include <stdlib.h>
5 scanf("%ms", &txt); 2 #include "hello.h"
6 return txt; 3 int main (void) {
7 } 4 char *name = readname("Tki?");
hello-print.c 5 printhello(name);
1 #include <stdio.h> 6 free(name);
2 void printhello (char *name) { 7 }
3 printf("Hello %s!\n", name);
4 }
$ gcc -c hello-read.c
$ gcc -c hello-print.c
$ gcc -c hello-main.c
$ gcc -o hello hello-read.o hello-print.o hello-main.o
$ ./hello
Tki? Bélix
Hello Bélix!
$
Franck Pommereau Rappels de C • Compilation 20 / 172

CoW : développer en ligne


Franck Pommereau Rappels de C • Compilation 20 / 172

CoW : développer en ligne


Franck Pommereau Rappels de C • Compilation 20 / 172

CoW : développer en ligne


Franck Pommereau Rappels de C • Contrôle de flot 21 / 172

Sommaire

Rappels de C
Compilation
Contrôle de flot
Types et constructeurs de types
Erreurs
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • Contrôle de flot 22 / 172

Contrôle de flot

▶ conditionnelle ▶ boucle while


1 if (CONDITION) { 1 while (CONDITION) {
2 INSTRUCTIONS; 2 INSTRUCTIONS;
3 } else if (CONDITION) { 3 }
4 INSTRUCTIONS;
5 } else { ▶ boucle do/while
6 INSTRUCTIONS; 1 do {
7 } 2 INSTRUCTIONS;
▶ sélection 3 } while (CONDITION);
switch (EXPRESSION) {
boucle for
1

2 case VALEUR:
3 INSTRUCTIONS; 1 for (INIT; COND; NEXT) {
4 case VALEUR: 2 INSTRUCTIONS;
5 INSTRUCTIONS; 3 }
6 default: ▶ break termine une boucle ou un switch
7 INSTRUCTIONS;
8 } ▶ continue reprend une boucle
Franck Pommereau Rappels de C • Contrôle de flot 23 / 172

Fonctions
▶ prototype ⇒ dans les fichiers .h
1 int max (int, int); // max a le type int(int,int)
2 void swap (int*, int*); // swap a le type void(int*,int*)
▶ déclaration ⇒ avec le nom des paramètres et le corps
1 int max (int a, int b) {
2 if (a > b) {
3 return a;
4 } else {
5 return b;
6 }
7 }
▶ passage “par valeur” des paramètres ⇒ copiés sur la pile
▶ passage “par adresse” ⇒ explicite par des pointeurs
1 void swap (int *a, int *b) {
2 int t = *a;
3 *a = *b;
4 *b = t;
5 }
▶ pas de fonctions imbriquées
Franck Pommereau Rappels de C • Contrôle de flot 24 / 172

Variables locales, globales, paramètres


vars.c
1 #include <stdio.h>
2
la pile
3 int sum = 0;

next(2)
int n = 2
4
5 int next (int n) {
6 sum += n;
▶7 return n+1; int n = ?

main
8 }
9 int i = 1
10 int main (void) {
int i, n; int sum = 2

runtime
11
12 for (i=1; i<10; i++) {
13 n = next(i+1); ...
14 printf("%i+1 => %i\n", i, n);
15 } pendant l’appel à
16 printf("sum = %i\n", sum); next(i+1), pour i=1, juste
17 // ... avant le return ligne 7
18 }
Franck Pommereau Rappels de C • Types et constructeurs de types 25 / 172

Sommaire

Rappels de C
Compilation
Contrôle de flot
Types et constructeurs de types
Erreurs
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • Types et constructeurs de types 26 / 172

Pointeurs
▶ déclaration d’un type pointeur
1 int *p; // p est un pointeur sur une valeur de type int
▶ accès à la valeur pointé (déréférencement)
1 *p = 5; // affectation de 5 à la valeur pointée par p
2 int q = (*p) / 2;
▶ opérateur “adresse de”
1 p = &q; // p pointe sur la variable q
2 *p == q; // vrai puisque c'est le même int en mémoire
▶ pointeur sur fonction
1 int (*cmp)(int, int); // cmp est un pointeur sur int(int,int)
2 cmp = max; // si on a défini: int max(int,int)
▶ “int* nom” ou “int *nom” ?
▶ les programmeuses issues du C préfèrent “int *nom” car “*nom est de type int”
▶ les programmeurs issus d’autres langages préfèrent “int* nom” car “nom est de type int*”
▶ les deux sont équivalents et corrects ⇒ moyen mnémotechnique pour la position de *
Franck Pommereau Rappels de C • Types et constructeurs de types 27 / 172

Construction de types et types alias


▶ nommer un type existant
1 typedef unsigned int uint;
▶ nommer de nouveaux types
1 // pointeur
2 typedef char *string;
3 // type énuméré
4 typedef enum cmode { ... } colormode;
5 // structure
6 typedef struct rgbpxl { ... } rgbpixel;
7 // union
8 typedef union anypxl { ... } anypixel;
9 // pointeur sur fonction int(int,int)
10 typedef int(*comparison)(int, int);
▶ attention, on a deux noms pour certains type :
▶ enum cmode est équivalent à colormode
▶ struct rgbpxl est équivalent à rgbpixel
▶ union anypxl est équivalent à anypixel
▶ le nom après enum, struct, ou union est facultatif dans un typedef
Franck Pommereau Rappels de C • Types et constructeurs de types 28 / 172

Types énumérés

▶ définition d’un type colormode avec trois valeurs


1 typedef enum {
2 RGB, // red/green/blue
3 HSL, // hue/saturation/lightness
4 CYMK // cyan/yellow/magenta/black
5 } colormode;
▶ pas de nom après enum ⇒ uniquement disponible par colormode
▶ dans la suite ⇒ valeurs comme les autres
1 colormode cm = RGB;
2 // ...
3 if (cm == CYMK) {
4 // ...
Franck Pommereau Rappels de C • Types et constructeurs de types 29 / 172

Structures

▶ définition d’un type pixel en mode RGB


1 typedef struct {
2 unsigned char r;
3 unsigned char g;
4 unsigned char b;
5 } rgbpixel;
▶ pas de nom après struct ⇒ rgbpixel uniquement
▶ dans la suite
1 // variable initialisée
2 rgbpixel p = {.r = 0, .g = 127, .b = 255};
3 // accès aux champs
4 void pixelcopy (rgbpixel a, rgbpixel *b) {
5 b->r = a.r; // b->r est comme (*b).r
6 b->g = a.g;
7 b->b = a.b;
8 }
Franck Pommereau Rappels de C • Types et constructeurs de types 30 / 172

Champs de bits (bitfields)


▶ comme struct
▶ on spécifie en plus la taille des champs (en nombre de bits)
1 typedef enum { 17 JUN = 6,
2 MON = 1, 18 JUL = 7,
3 TUE = 2, 19 AUG = 8,
4 WED = 3, 20 SEP = 9,
5 THU = 4, 21 OCT = 10,
6 FRI = 5, 22 NOV = 11,
7 SAT = 6, 23 DEC = 12
8 SUN = 7 24 } monthname;
9 } dayname; 25
10 26 typedef struct {
11 typedef enum { 27 dayname weekday : 3;
12 JAN = 1, 28 unsigned int day : 5;
13 FEB = 2, 29 monthname month : 4;
14 MAR = 3, 30 int year : 20;
15 APR = 4, 31 } date; // sizeof(date) == 4
16 MAY = 5, 32 // sizeof(int) == 4
Franck Pommereau Rappels de C • Types et constructeurs de types 31 / 172

Types unions
▶ définition d’un type anypixel pour différents modes de couleurs
1 typedef union { 12 float s;
2 colormode mode; 13 float l;
3 struct { 14 } hsl;
4 colormode mode; 15 struct {
5 unsigned char r; 16 colormode mode;
6 unsigned char g; 17 unsigned char c;
7 unsigned char b; 18 unsigned char y;
8 } rgb; 19 unsigned char m;
9 struct { 20 unsigned char k;
10 colormode mode; 21 } cymk;
11 float h; 22 } anypixel;
▶ pas de nom après union ⇒ anypixel uniquement
▶ utilisation comme des struct imbriqués
1 anypixel p; p.mode = RGB; p.rgb.r = 0;
▶ superposition en mémoire
⇒ &(p.mode) == &(p.rgb.mode) == &(p.hls.mode)
Franck Pommereau Rappels de C • Types et constructeurs de types 32 / 172

Tableaux
▶ tableau = suite de valeurs de même type consécutives en mémoire
67 98 78 73 85 38 29 6 9 47
0 1 2 3 4 5 6 7 8 9
▶ un tableau se définit donc par :
▶ le type des valeurs ⇒ la taille des cases
▶ l’adresse de la première valeur
▶ le nombre de valeurs
▶ C n’a pas de type tableaux
▶ on utilise des pointeurs
▶ il manque le nombre de valeurs
▶ on peut écrire hors des bornes
d’un “tableau”
▶ solution partielle : utiliser un marqueur de fin
▶ comme dans les chaînes char*
▶ on “sacrifie” une valeur (pas toujours possible)
▶ attention à la “vraie” taille des chaînes
Franck Pommereau Rappels de C • Types et constructeurs de types 32 / 172

Tableaux
▶ tableau = suite de valeurs de même type consécutives en mémoire
67 98 78 73 85 38 29 6 9 47
0 1 2 3 4 5 6 7 8 9
▶ un tableau se définit donc par :
▶ le type des valeurs ⇒ la taille des cases
▶ l’adresse de la première valeur
▶ le nombre de valeurs
▶ C n’a pas de type tableaux
▶ on utilise des pointeurs
▶ il manque le nombre de valeurs
▶ on peut écrire hors des bornes
d’un “tableau”
▶ solution partielle : utiliser un marqueur de fin
▶ comme dans les chaînes char*
▶ on “sacrifie” une valeur (pas toujours possible)
▶ attention à la “vraie” taille des chaînes
Franck Pommereau Rappels de C • Types et constructeurs de types 33 / 172
memset 3
“Tableaux” statiques sur la pile
▶ taille fixée à la compilation
▶ mémoire allouée et libérée automatiquement sur la pile
▶ pointeur “constant”
sieve.c
1 #include <stdio.h>
2 #include <string.h>
3
4 void sieve () {
5 unsigned char prime[500]; // taille figée à la compilation
6 int i, p;
7 memset(prime, 1, sizeof(prime)); // sizeof = taille en octets
8 for (p=2; p<500; p++) {
9 if (prime[p]) {
10 printf("%u\n", p);
11 for (i=p; i<500; i+=p) {
12 prime[i] = 0;
13 }
14 }
15 }
16 }
Franck Pommereau Rappels de C • Types et constructeurs de types 34 / 172

“Tableaux” semi-dynamiques sur la pile


Variable-Length Arrays — VLA (à partir de C99)

▶ taille définie à l’exécution (gros problème si trop grand)


▶ alloué et libéré automatiquement sur la pile, pointeur “constant”
▶ ne peut être redimensionné
sieve-vla.c
1 #include <stdio.h>
2 #include <string.h>
3
4 void sieve (unsigned int n) {
5 unsigned char prime[n]; // n n'est pas statique
6 int i, p;
7 memset(prime, 1, sizeof(prime)); // sizeof est disponible dans le bloc
8 for (p=2; p<n; p++) {
9 if (prime[p]) {
10 printf("%u\n", p);
11 for (i=p; i<n; i+=p) {
12 prime[i] = 0;
13 }
14 }
15 }
16 }
Franck Pommereau Rappels de C • Types et constructeurs de types 35 / 172
malloc 3
“Tableaux” dynamiques sur le tas free 3

▶ taille définie à l’exécution, redimentionnable avec realloc 3


▶ mémoire allouée et libérée explicitement sur le tas
sieve-dyn.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 void sieve (unsigned int n) {
6 unsigned char *prime = malloc(n * sizeof(unsigned char));
7 int i, p;
8 if (prime == NULL) return; // malloc peut échouer
9 memset(prime, 1, n * sizeof(unsigned char)); // surtout pas sizeof(prime)
10 for (p=2; p<n; p++) {
11 if (prime[p]) {
12 printf("%u\n", p);
13 for (i=p; i<n; i+=p) {
14 prime[i] = 0;
15 }
16 }
17 }
18 free(prime); // penser à libérer la mémoire
19 }
Franck Pommereau Rappels de C • Erreurs 36 / 172

Sommaire

Rappels de C
Compilation
Contrôle de flot
Types et constructeurs de types
Erreurs
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Rappels de C • Erreurs 37 / 172
errno 3
Gestion des erreurs perror 3
strerror 3

▶ les fonctions standard de C et de l’API Unix


retournent un code d’erreur en cas de problème
1 void *malloc(size_t size); // renvoie NULL en cas d'échec
▶ pour plus d’information sur l’erreur :
1 #include <errno.h>
2 extern int errno; // peut être changé par tout appel
3
4 #include <stdio.h>
5 void perror(const char *msg);
6 // affiche la description de l'erreur correspondant à errno
7 // préfixée de msg si elle n'est pas NULL ou vide
8 char *strerror(int errnum);
9 // renvoie une chaîne avec la description d'une erreur
▶ il est très important de tester si les fonctions échouent
⇒ gestion des erreurs entrelacée à l’algorithme
⇒ le code devient moins lisible
Franck Pommereau Environnement du programme • 38 / 172

Sommaire

Rappels de C
Environnement du programme
Invocation
Terminaison
stdio
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Environnement du programme • Invocation 39 / 172

Sommaire

Rappels de C
Environnement du programme
Invocation
Terminaison
stdio
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Environnement du programme • Invocation 40 / 172

La ligne de commande
▶ dans le shell, on tape une ligne de commande
$ ./monprog -a -l --print hello world
▶ le shell interprète certains caractères (*, $, . . .)
▶ le shell découpe cette ligne en tableau de chaînes (selon les espaces)
./monprog -a -l --print hello world
▶ ce tableau est passé au programme (qui doit se débrouiller avec)
▶ int main(void) ⇒ le programme ignore les paramètres
▶ sinon, on doit avoir :
1 #include <stdio.h>
2
3 int main (int argc, char *argv[]) { // ou char **argv
4 // argc = 6
5 // argv = {"./monprog", "-a", "-l", "--print", "hello", "world"}
6 for (int i=0; i<argc; i++) {
7 printf("%s\n", argv[i]);
8 }
9 }
Franck Pommereau Environnement du programme • Invocation 41 / 172

Les variables d’environnement


▶ en plus des paramètres, le shell définit des variables d’environnement
$ export FOO=spam
$ echo $FOO
spam
$
▶ aussi accessibles à un programme qu’on lance
(héritées du processus parent)
arge.c
1 #include <stdio.h>
2
3 int main (int argc, char *argv[], char *arge[]) {
4 for (int i=0; arge[i]; i++) {
5 printf("%s\n", arge[i]);
6 }
7 }
▶ chaque variable sous la forme "NOM=valeur de la variable"
▶ fin de arge marquée par une chaîne NULL
Franck Pommereau Environnement du programme • Invocation 42 / 172
getenv 3
API pour les variables d’environnement setenv 3
unsetenv 3

▶ dans la bibliothèque standard


▶ plus pratiques que la manipulation de arge
⇒ arge rarement utilisé
1 #include <stdlib.h>
2
3 char *getenv(const char *name);
4 // renvoie la valeur d'une variable
5 // ou NULL si elle n'est pas définie
6
7 int setenv(const char *name, const char *value, int overwrite);
8 // assigne une variable
9 // écrase ou pas une variable existante
10 // renvoie 0 si OK, -1 si erreur (+ errno)
11
12 int unsetenv(const char *name);
13 // supprime une variable (si elle existe)
14 // renvoie 0 si OK, -1 si erreur (+ errno)
Franck Pommereau Environnement du programme • Terminaison 43 / 172

Sommaire

Rappels de C
Environnement du programme
Invocation
Terminaison
stdio
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Environnement du programme • Terminaison 44 / 172

Code de retour
▶ main retourne toujours un int
1 int main(void);
2 int main(int, char*[]);
3 int main(int, char*[], char*[]);
▶ la valeur retournée est passée au shell (qui la met dans $?)
int-main.c
1 int main (void) {
2 return 123;
3 }
$ gcc int-main.c
$ ./a.out
$ echo $?
123
$
▶ exit(123) aurait le même effet
▶ partout dans le programme (return code ne fonctionne que pour main)
▶ termine le processus
Franck Pommereau Environnement du programme • stdio 45 / 172

Sommaire

Rappels de C
Environnement du programme
Invocation
Terminaison
stdio
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Environnement du programme • stdio 46 / 172
fscanf 3
Les entrées/sorties standards fprintf 3

▶ chaque processus est connecté à un terminal par :


▶ une entrée standard stdin ⇒ clavier
▶ une sortie standard stdout ⇒ écran texte
▶ une sortie d’erreur stderr ⇒ écran texte (mélangé à stdout)
▶ on peut les rediriger
$ echo hello | prog # stdout de echo => stdin de prog
$ prog < FILE # contenu de FILE => stdin de prog
$ prog > FILE # stdout de prog => écrase FILE
$ prog >> FILE # stdout de prog => s'ajoute à FILE
$ prog 2> FILE # stderr de prog => écrase FILE
$ prog 2>&1 # stderr de prog => stdout de prog

▶ dans le programme : fichiers prédéfinis


stdio.c
1 #include <stdio.h>
2 int main (void) {
3 char *txt;
4 fscanf(stdin, "%ms", &txt); // comme scanf("...
5 fprintf(stdout, "stdout: %s\n", txt); // comme printf("...
6 fprintf(stderr, "stderr: %s\n", txt);
7 } // on a oublié de libérer la mémoire de txt !
Franck Pommereau Le système de fichiers • 47 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • Concepts 48 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • Concepts 49 / 172

Une arborescence unifiée


▶ tous les fichiers sont disponibles à partir du répertoire racine /
▶ chaque répertoire contient :
▶ des sous-répertoires /dev, /bin, /usr/bin
▶ les sous-répertoires . (lui-même) et .. (le répertoire parent)
▶ des fichiers /dev/urandom, /bin/sh, /usr/bin/bash
▶ un chemin = liste de répertoires séparés par des /
▶ /usr/bin/bash est un chemin absolu
▶ ../../foo/bar est un chemin relatif
▶ les différents disques (volumes) sont montés sur des répertoires
leur contenu est greffé sur un répertoire et intègre l’arborescence unifiée
▶ différents types de fichiers :
▶ répertoires ⇒ liste de paires nom 7→ fichier
▶ fichiers “normaux” ⇒ des données dans un volume
▶ liens symboliques ⇒ chemin vers un autre fichier
▶ fichiers “spéciaux” ⇒ périphérique ou interface noyau
▶ fichiers “cachés” dont le nom commence par “.”
▶ juste une convention des applications ⇒ ils n’ont rien de particulier
Franck Pommereau Le système de fichiers • Concepts 50 / 172
ln 1
Liens ls 1

▶ un fichier n’a pas de nom ⇒ des données et des attributs


▶ le nom est donné par une entrée de répertoire
⇒ une entrée = nom + numéro du fichier = un lien (hard link)
▶ il peut exister plusieurs liens pour un même fichier
(pas de liens vers les répertoires)
▶ lien symbolique = chemin d’un autre fichier/répertoire
▶ dans le shell :
$ ln fichier un-lien # crée un lien dur
$ ln -s fichier autre-lien # crée un lien symbolique
$ ls -l # liste le tout avec les infos détaillées
total 2344
lrwxrwxrwx 1 franck franck 7 Nov 15 14:26 autre-lien -> fichier
-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 un-lien
Franck Pommereau Le système de fichiers • Méta-données 51 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 52 / 172

Les attributs de fichiers


-rw-rw-r-- 2 franck franck 1197060 Nov 15 14:25 fichier
▶ taille en octets
▶ utilisateur propriétaire (uid)
▶ groupe propriétaire (gid)
▶ nombre de liens
▶ permissions d’accès
▶ de l’utilisateur propriétaire (user)
▶ read
▶ write
▶ execute / explore
▶ du groupe propriétaire (group)
▶ de tous les autres (other)
▶ dates de
▶ dernier accès
▶ dernière modification du contenu
▶ dernière modification des attributs
Franck Pommereau Le système de fichiers • Méta-données 53 / 172

Attributs spéciaux
▶ sur un fichier :
▶ bit setuid : -rwsrwxrwx
▶ le fichier est un programme exécutable
▶ le processus aura l’uid de l’utilisateur propriétaire du fichier
▶ bit setgid : -rwxrwsrwx
▶ le fichier est un programme exécutable
▶ le processus aura le gid du groupe propriétaire du fichier
▶ sur un répertoire :
▶ bit setuid : drwsrwxrwx
▶ un fichier ajouté aura comme utilisateur propriétaire celui du répertoire
▶ hérité par les sous-répertoires
▶ bit setgid : drwxrwsrwx
▶ un fichier ajouté aura comme groupe propriétaire celui du répertoire
▶ hérité par les sous-répertoires
▶ sticky bit : drwxrwxrwt
▶ un fichier ne pourra être supprimé que par son propriétaire
Franck Pommereau Le système de fichiers • Méta-données 54 / 172

Notation octale des permissions

▶ 3 mots (ugo) de 3 bits (rwx)


▶ 3 bits = 1 chiffre octal
8 7 6 5 4 3 2 1 0

u:r u:w u:x g:r g:w g:x o:r o:w o:x


=4 =2 =1 =4 =2 =1 =4 =2 =1

▶ par exemple : (octal ⇒ noté avec un 0 au début)


▶ rwxrw-r-- ⇒ 0764
▶ r-xrw--w- ⇒ 0562
▶ r---w---x ⇒ 0421
Franck Pommereau Le système de fichiers • Méta-données 55 / 172
umask 2
Masque de permissions
▶ chaque processus a un umask
⇒ 3 × 3 bits de masque de permissions
▶ création d’un fichier/répertoire avec les permissions mode
⇒ permissions effectivement données : mode & ~umask
▶ exemple :
umask = 0022 = ----w--w-
mode = 0666 = rw-rw-rw-
résultat = 0644 = rw-r--r--
▶ commande shell : umask commande interne
▶ appel système : umask 2
▶ change umask et renvoie sa valeur avant le changement
1 #include <sys/types.h>
2 #include <sys/stat.h>
3
4 mode_t umask(mode_t mask);
Franck Pommereau Le système de fichiers • inodes 56 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • inodes 57 / 172

Représentation interne
▶ les disques physiques sont partitionnés
▶ les partitions sont formatées
▶ chacune = un volume avec un identifiant
▶ les volumes sont montés dans l’arborescence
▶ chaque objet d’un volume est représenté par un inode
▶ chacun a son numéro
▶ contient les métadonnées du fichier (sauf son nom)
▶ type de fichier
▶ les attributs (permissions, propriétaire, taille, dates, etc.)
▶ position dans le volume (selon formatage/technologie du disque physique)
▶ nombre de liens
▶ nombre d’utilisations (fichiers ouverts)
▶ ...
▶ un fichier ou répertoire est identifié de façon unique par son identifiant de volume et son
numéro d’inode
▶ un répertoire est un fichier particulier contenant une liste de :
nom 7→ n° inode
Franck Pommereau Le système de fichiers • inodes 58 / 172
stat 1
Visualiser les inodes dans le shell
$ stat *
File: autre-lien -> fichier
Size: 7 Blocks: 0 IO Block: 4096 symbolic link
Device: fd01h/64769d Inode: 8913103 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1000/ franck) Gid: ( 1000/ franck)
Access: 2021-11-15 14:26:06.888014343 +0100
Modify: 2021-11-15 14:26:04.180040375 +0100
Change: 2021-11-15 14:26:04.180040375 +0100
Birth: -
File: fichier
Size: 1197060 Blocks: 2344 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 8913100 Links: 2
Access: (0664/-rw-rw-r--) Uid: ( 1000/ franck) Gid: ( 1000/ franck)
Access: 2021-11-15 14:25:50.760169942 +0100
Modify: 2021-11-15 14:25:50.760169942 +0100
Change: 2021-11-15 14:25:56.296116377 +0100
Birth: -
File: un-lien
Size: 1197060 Blocks: 2344 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 8913100 Links: 2
Access: (0664/-rw-rw-r--) Uid: ( 1000/ franck) Gid: ( 1000/ franck)
Access: 2021-11-15 14:25:50.760169942 +0100
Modify: 2021-11-15 14:25:50.760169942 +0100
Change: 2021-11-15 14:25:56.296116377 +0100
Birth: -
Franck Pommereau Le système de fichiers • Navigation et répertoires 59 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • Navigation et répertoires 60 / 172
getcwd 3
Le répertoire de travail actuel chdir 3

▶ chaque processus a son cwd : current working directory


▶ les chemins relatifs sont résolus à partir de ce répertoire
1 #include <unistd.h>
2
3 char *getcwd(char *buf, size_t size);
4 int chdir(const char *path);
▶ getcwd renvoie le nom du cwd
▶ sous Linux : getcwd(NULL, 0) alloue une chaîne de la bonne taille
⇒ il faut la libérer
▶ ailleurs : il faut anticiper la taille
▶ chdir change le cwd
▶ équivalent à la commande cd du shell
▶ un processus ne peut changer le cwd que pour lui-même
Franck Pommereau Le système de fichiers • Navigation et répertoires 61 / 172
opendir 3
Lister les répertoires readdir 3
closedir 3
rewinddir 3
▶ structure séquentielle, on doit lire les liens un par un
▶ opendir() ⇒ ouvre une répertoire
▶ readdir() ⇒ lit le prochain lien
▶ closedir() ⇒ ferme le répertoire
▶ rewinddir() ⇒ revient au début
▶ répertoire ouvert ⇒ DIR* (type opaque)
▶ lien ⇒ (POSIX ne normalise que d_name)
1 struct dirent {
2 ino_t d_ino; // inode number
3 off_t d_off; // not an offset => do not use
4 unsigned short d_reclen; // record length => do not use
5 unsigned char d_type; // type of file => read the doc
6 char d_name[256]; // null-terminated filename
7 };
▶ historiquement : d_off et d_reclen position et taille du lien
aujourd’hui : valeurs internes au système de fichier
▶ d_type ne fonctionne pas avec tous les systèmes de fichiers
⇒ utiliser les macros dédiées et prendre en compte l’échec
Franck Pommereau Le système de fichiers • Navigation et répertoires 62 / 172
opendir 3
opendir(), closedir(), rewinddir() closedir 3
rewinddir 3

1 #include <sys/types.h>
2 #include <dirent.h>
3
4 DIR *opendir(const char *name);
5 int closedir(DIR *dirp);
6 void rewinddir(DIR *dirp);

▶ opendir ouvre un répertoire


▶ renvoie un pointeur sur un descripteur opaque en cas de succès
renvoie NULL en cas d’échec (avec errno)
▶ closedir ferme un répertoire ouvert
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ rewinddir redémarre au début le parcours du répertoire
▶ ne renvoie rien, une erreur sera vue à l’appel d’une autre fonction
Franck Pommereau Le système de fichiers • Navigation et répertoires 63 / 172
readdir 3
readdir()

1 #include <sys/types.h>
2 #include <dirent.h>
3
4 struct dirent *readdir(DIR *dirp);

▶ lit le prochain lien du répertoire


▶ renvoie un pointeur sur struct dirent en cas de succès
▶ ne pas utiliser free sur le pointeur renvoyé
▶ renvoie NULL si on a lu le dernier lien ou si erreur
▶ pour différencier les deux cas, il faut tester errno
1 errno = 0; // obligatoire car errno peut toujours avoir changé
2 if (ent = readdir(dir)) {
3 // on a lu un lien
4 } else if (errno) {
5 // il y a eu une erreur
6 } else {
7 // on a fini de parcourir le répertoire
8 }
Franck Pommereau Le système de fichiers • Navigation et répertoires 64 / 172
mkdir 3
mkdir(), rmdir() rmdir 3

1 #include <sys/stat.h>
2 #include <sys/types.h>
3 #include <unistd.h>
4
5 int mkdir(const char *pathname, mode_t mode);
6 int rmdir(const char *pathname);

▶ mkdir crée un répertoire pathname


▶ pathname peut être absolu ou relatif
▶ le répertoire parent doit exister
▶ il ne doit pas déjà contenir un lien avec ce nom
▶ le répertoire créé a les permissions spécifiées par mode
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ rmdir efface le répertoire pathname
▶ il doit être vide (aucun fichier ni sous-répertoire)
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
Franck Pommereau Le système de fichiers • API méta-données 65 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • API méta-données 66 / 172
stat 2
struct stat

▶ regroupe les (méta)informations sur un fichier


1 struct stat {
2 dev_t st_dev; // ID of device containing file
3 ino_t st_ino; // inode number
4 mode_t st_mode; // file type and mode
5 nlink_t st_nlink; // number of hard links
6 uid_t st_uid; // user ID of owner
7 gid_t st_gid; // group ID of owner
8 dev_t st_rdev; // device ID (if special file)
9 off_t st_size; // total size, in bytes
10 blksize_t st_blksize; // block size for filesystem I/O
11 blkcnt_t st_blocks; // number of 512B blocks allocated
12 // ... // implementation dependent
13 }
▶ remarquons la convention type_t st_field
Franck Pommereau Le système de fichiers • API méta-données 67 / 172
inode 7
stat.st_mode

▶ stocke les permissions dans un champ de bits 0


S_IFSOCK : socket
S_IFLNK : lien symbolique
(variable selon noyau/archi) 1 S_IFREG : fichier normal
type de fichier S_IFMT S_IFBLK : périphérique bloc
▶ macros pour tester S_IFMT : 2 S_IFDIR : répertoire
S_IFCHR : périphérique caractère
S_ISREG, S_ISDIR, S_ISCHR, 3 S_IFFIFO : tube nommé
4 S_ISUID : bit setuid
S_ISBLK, S_ISFIFO, S_ISLNK, attributs spéciaux 5 S_ISGID : bit setgid
S_ISSOCK 6 S_ISVTX : sticky bit
7 S_IRUSR
permissions user 8 S_IWUSR S_IRWXU
9 S_IXUSR
10 S_IRGRP
permissions group 11 S_IWGRP S_IRWXG
12 S_IXGRP
13 S_IROTH
permissions others 14 S_IWOTH S_IRWXO
15 S_IXOTH
Franck Pommereau Le système de fichiers • API méta-données 68 / 172
stat 2
stat() •◦ lstat 2
fstat 2

1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4
5 int stat(const char *pathname, struct stat *statbuf);
6 int lstat(const char *pathname, struct stat *statbuf);
7 int fstat(int fd, struct stat *statbuf);

▶ remplit statbuf avec les attributs du fichier pathname


▶ stat suit les liens symboliques
▶ lstat ne suit pas les liens et donne les infos des liens
▶ fstat travaille sur un fichier déjà ouvert
▶ renvoient 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Le système de fichiers • API méta-données 69 / 172
stat 2
stat() •• inode 7

▶ lire et afficher la taille de fichiers


stat.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 int main (int argc, char *argv[]) {
7 struct stat sb;
8 for (int i=1; i<argc; i++) {
9 if (stat(argv[i], &sb) == -1) {
10 perror("stat");
11 exit(EXIT_FAILURE);
12 }
13 printf("%s: %li bytes\n", argv[i], sb.st_size);
14 }
15 }
Franck Pommereau Le système de fichiers • API méta-données 70 / 172
chmod 2
chmod() et fchmod() fchmod 2

1 #include <sys/stat.h>
2
3 int chmod(const char *pathname, mode_t mode);
4 int fchmod(int fd, mode_t mode);

▶ change les permissions d’un inode


▶ chmod travaille à partir d’un chemin
▶ fchmod travaille sur un fichier ouvert
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ pour mode_t mode :
▶ | entre les macros vues avec stat.st_mode
▶ rwxr-x--- ⇒ S_IRWXU|S_IRGRP|S_IXGRP
▶ directement en octal
▶ rwxr-x--- ⇒ 0750
Franck Pommereau Le système de fichiers • API méta-données 71 / 172

Les “variantes f”

▶ on a vu chmod 2 et fchmod 2
▶ il existe beaucoup d’autres cas similaires
▶ on ne les verra pas systématiquement
▶ RTFM (read the f. . .ine manual)
▶ la “variante f” est :
▶ plus rapide
(une seul résolution du chemin à l’ouverture du fichier)
▶ plus sûre en environnement concurrent
(le chemin peut être changé par un autre processus)
▶ inutile pour une modification ponctuelle
Franck Pommereau Le système de fichiers • API méta-données 72 / 172
chown 2
chown(), fchown(), et lchown() fchown 2
lchown 2

1 #include <unistd.h>
2
3 int chown(const char *pathname, uid_t owner, gid_t group);
4 int fchown(int fd, uid_t owner, gid_t group);
5 int lchown(const char *pathname, uid_t owner, gid_t group);

▶ change l’utilisateur et le groupe propriétaire d’un inode


▶ chown travaille à partir du chemin
▶ fchown travaille à partir d’un fichier ouvert
▶ lchown fait comme chown mais ne suit pas les liens symboliques
▶ owner ou group à -1 ⇒ ne change pas
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ nécessite des privilèges
▶ changer l’utilisateur propriétaire ⇒ root (ou capacité CAP_CHOWN)
▶ changer le groupe propriétaire ⇒ idem, ou membre du groupe cible
Franck Pommereau Le système de fichiers • API méta-données 73 / 172
getpwnam 3
getpwnam()
1 #include <sys/types.h>
2 #include <pwd.h>
3
4 struct passwd *getpwnam(const char *name);
5
6 struct passwd {
7 char *pw_name; // username
8 char *pw_passwd; // user password => "x"
9 uid_t pw_uid; // user ID
10 gid_t pw_gid; // group ID
11 char *pw_gecos; // user information
12 char *pw_dir; // home directory
13 char *pw_shell; // shell program
14 };
▶ récupère les informations sur un utilisateur
▶ à partir de son nom de login name
▶ en particulier ⇒ uid et gid pour chown 2
▶ informations issues de /etc/password
Franck Pommereau Le système de fichiers • API liens 74 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Concepts
Méta-données
inodes
Navigation et répertoires
API méta-données
API liens
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Le système de fichiers • API liens 75 / 172
link 2
link() et symlink() symlink 2

1 #include <unistd.h>
2
3 int link(const char *oldpath, const char *newpath);
4 int symlink(const char *target, const char *linkpath);

▶ link crée un lien newpath vers le même inode que oldpath


▶ ce qu’on appelle un “lien dur”
▶ équivalent à la commande shell ln oldpath newpath
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ symlink crée un lien symbolique linkpath pointant vers target
▶ équivalent à la commande shell ln -s target linkpath
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ attention à l’ordre des paramètres
Franck Pommereau Le système de fichiers • API liens 76 / 172
readlink 2
readlink()

1 #include <unistd.h>
2
3 ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

▶ écrit la destination du lien symbolique pathname dans buf qui doit avoir la taille bufsiz
▶ n’ajoute pas '\0' à la fin de buf
▶ si buf est trop petit, la destination sera tronquée
▶ renvoie le nombre de char lus en cas de succès, -1 sinon (avec errno)
▶ si bufsize est renvoyé, la destination peut-être tronquée
▶ la taille requise peut-être obtenue avec lstat 2 dans le champ st_size du struct stat
utilisé
(à condition que le lien symbolique ne change pas entre les deux appels)
Franck Pommereau Le système de fichiers • API liens 77 / 172
unlink 2
unlink()

1 #include <unistd.h>
2
3 int unlink(const char *pathname);

▶ supprime un lien
▶ l’inode correspondant a un lien de moins
▶ si c’était le dernier, l’inode est libéré ⇒ peut servir à d’autres fichiers
▶ équivalent à la commande shell rm pathname
▶ pathname est un lien symbolique
⇒ supprimé sans affecter sa cible
▶ fichier ouvert par des processus
⇒ sera vraiment effacé lorsque tous les processus l’auront fermé
▶ ne fonctionne pas sur les répertoires (voir rmdir 3 plus tard)
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
Franck Pommereau Le système de fichiers • API liens 78 / 172
rename 2
rename()

1 #include <stdio.h>
2
3 int rename(const char *oldpath, const char *newpath);

▶ renomme un lien oldpath en newpath


▶ les autres liens sur le même inode ne sont pas affectés
▶ newpath peut être dans un autre répertoire,
mais sur le même volume
▶ si newpath existe, il est remplacé
▶ si newpath est déjà un lien vers le même inode que oldpath,
l’appel n’a pas d’effet et réussit
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
Franck Pommereau Le système de fichiers • API liens 79 / 172

Copier et déplacer des fichiers

▶ Unix ne propose aucune façon de copier un fichier


⇒ il faut le programmer soi-même
▶ lire le fichier source
▶ le recopier dans le fichier cible
▶ par morceaux de taille raisonnables
▶ grands ⇒ plus rapide mais plus de mémoire mobilisée
▶ petits ⇒ plus lent mais mémoire épargnée
▶ recopier les permissions, dates, etc.
▶ pour déplacer un fichier
▶ sur le même volume ⇒ rename 2 (très rapide)
▶ entre volumes ⇒ copie puis suppression de la source
▶ pour des répertoires
▶ rename 2 marche au sein d’un même volume
▶ la copie est encore plus compliquée (recopier récursivement tout le contenu)
▶ l’effacement aussi
Franck Pommereau Entrées/sorties • 80 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
API
Représentation interne
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Entrées/sorties • API 81 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
API
Représentation interne
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Entrées/sorties • API 82 / 172

Fichiers

▶ le contenu d’un fichier est une séquence d’octets


▶ il faut ouvrir un fichier afin d’accéder à son contenu
▶ renvoie un numéro de fichier (numéro de descripteur de fichier ouvert)
▶ toutes les opérations se font par ce numéro
▶ ce numéro est arbitraire (même si on sait qu’il est alloué séquentiellement)
▶ Unix mémorise un curseur de lecture/écriture
▶ à partir de zéro (premier octet du fichier)
▶ les lectures/écritures se font toujours à partir de ce curseur
▶ le curseur peut être déplacé arbitrairement
▶ sauf avant le début du fichier
▶ mais possiblement après la fin (voir lseek 2 )
▶ il est mis à jour après chaque lecture/écriture
▶ il faut fermer un fichier quand on n’en a plus besoin
▶ plus aucune opération n’est autorisée sur un fichier fermé
Franck Pommereau Entrées/sorties • API 83 / 172
open 2
open()
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4
5 int open(const char *pathname, int flags);
6 int open(const char *pathname, int flags, mode_t mode);
▶ ouvre le fichier pathname pour donner accès à son contenu
▶ flags est un | entre
▶ O_RDONLY ⇒ lecture seule
▶ O_WRONLY ⇒ écriture seule
▶ O_RDWR ⇒ lecture et écriture
▶ et aussi
▶ O_APPEND ⇒ ajout (avant chaque écriture, le curseur est positionné à la fin)
▶ O_CREAT ⇒ crée le fichier s’il n’existe pas déjà
▶ O_EXCL ⇒ avec O_CREAT, garantit que le fichier a été créé
▶ O_TRUNC ⇒ avec O_WRONLY ou O_RDWR, vide le fichier s’il existe déjà
▶ O_CREAT ⇒ mode = permissions du fichier (cf. umask 2 )
▶ renvoie un numéro de fichier ≥ 0 en cas de succès, -1 sinon (avec errno)
Franck Pommereau Entrées/sorties • API 84 / 172
read 2
read()

1 #include <unistd.h>
2
3 ssize_t read(int fd, void *buf, size_t count);

▶ lit ≤ count octets dans le fichier fd


▶ les recopie dans buf
▶ doit avoir la capacité suffisante (au moins count octets)
▶ renvoie le nombre d’octets lus en cas de succès, -1 sinon (avec errno)
▶ 0 ⇒ on a atteint la fin du fichier
▶ < count mais > 0 ⇒ pas forcément la fin du fichier
▶ lecture dans un fichier spécial borné (pipe, socket, . . .)
▶ processus interrompu pendant la lecture (par un signal)
▶ les octets lus débutent à la position du curseur
▶ elle est mise à jour après la lecture
Franck Pommereau Entrées/sorties • API 85 / 172
write 2
write()

1 #include <unistd.h>
2
3 ssize_t write(int fd, const void *buf, size_t count);

▶ écrit ≤ count octets depuis buf dans le fichier fd


▶ renvoie le nombre d’octets écrits en cas de succès, -1 sinon
(avec errno)
▶ < count ⇒ pas forcément une erreur
▶ volume plein temporairement
▶ écriture dans un fichier spécial borné (pipe, socket, . . .)
▶ processus interrompu pendant l’écriture (par un signal)
▶ les octets sont écrits à partir de la position du curseur
▶ elle est mise à jour après l’écriture
Franck Pommereau Entrées/sorties • API 86 / 172
fsync 2
Écritures différées sync 2

▶ le noyau ne réalise pas immédiatement les écritures demandées


▶ regroupées et ordonnancées pour plus d’efficacité disque
▶ appel système plus rapide
▶ cohérence des écritures (mode ligne de stdout)
▶ ouverture d’un fichier avec O_SYNC ⇒ écritures synchrones
▶ write termine ⇒ données écrites (sur le disque)

1 #include <unistd.h>
2
3 int fsync(int fd);
4 void sync(void);

▶ fsync réalise les écritures en attente sur fd


▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ sync réalise toutes les écritures en attente sur le système
▶ ne fait jamais d’erreur (le noyau gère les erreurs globalement)
Franck Pommereau Entrées/sorties • API 87 / 172
lseek 2
lseek()

1 #include <sys/types.h>
2 #include <unistd.h>
3
4 off_t lseek(int fd, off_t offset, int whence);

▶ déplace le curseur de lecture/écriture


▶ whence == SEEK_SET ⇒ l’affecte à offset
▶ whence == SEEK_CUR ⇒ ajoute offset à la valeur courante
▶ whence == SEEK_END ⇒ l’affecte à la taille du fichier + offset
▶ offset peut être < 0 dans le deux derniers cas
▶ le curseur peut être positionné après la fin du fichier
▶ si une écriture a lieu à cet endroit, le “trou” sera rempli par des '\0'
▶ renvoie la nouvelle position du curseur en cas de succès, -1 sinon
(avec errno)
Franck Pommereau Entrées/sorties • API 88 / 172
ftruncate 2
ftruncate()

1 #include <unistd.h>
2 #include <sys/types.h>
3
4 int ftruncate(int fd, off_t length);

▶ tronque le fichier à la taille length


▶ le fichier doit être ouvert en écriture
▶ la position du curseur n’est pas changée
⇒ peut se retrouver après la fin du fichier
⇒ comme lseek 2
▶ si le fichier devient plus grand, le trou est rempli par des '\0'
▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
Franck Pommereau Entrées/sorties • API 89 / 172
close 2
close()

1 #include <unistd.h>
2
3 int close(int fd);

▶ ferme un fichier précédemment ouvert


▶ renvoie 0 en cas de succès, -1 sinon (avec errno)
▶ peut faire une erreur causée par une opération précédente
▶ exemple : une écriture différée
▶ libération des ressources associées
▶ exemple : fichier “effacé” ⇒ espace disque libéré au close
Franck Pommereau Entrées/sorties • API 90 / 172

Les entrées/sorties standard d’un processus

▶ chaque processus démarre avec trois fichiers


▶ 0 ⇒ entrée standard
▶ 1 ⇒ sortie standard
▶ 2 ⇒ sortie d’erreur
▶ ces valeurs sont donnée par des macros
1 #include <unistd.h>
2
3 #define STDIN_FILENO 0
4 #define STDOUT_FILENO 1
5 #define STDERR_FILENO 2
▶ généralement connectés au terminal
▶ mais peuvent être
▶ fermés
▶ redirigés ⇒ ouverts sur d’autres fichiers
Franck Pommereau Entrées/sorties • Représentation interne 91 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
API
Représentation interne
Les processus
Communications entre processus
Threads POSIX
Franck Pommereau Entrées/sorties • Représentation interne 92 / 172

Tables des processus/fichiers/inodes •◦


espace utilisateur espace noyau
table des table des table des
processus fichiers ouverts inodes
processus 1421

int fd 4
pid: 1215
file descriptors: status: W
0 offset: 10
stdin < foo.txt 1 inode ptr: type: reg file
2 inode nbr: …
4 > bar.log 3 refcount: 1
4 ref count: 2
5
6

status: R
processus 1215
offset: 8
pid: 1421 inode ptr:
int fd 4 refcount: 1
file descriptors: type: reg file
0 inode nbr: …
1 ref count: 1
2
3
4
status: W
4 > foo.txt 5 offset: 51
6
… inode ptr:
refcount: 1

ý back
Franck Pommereau Entrées/sorties • Représentation interne 93 / 172

Tables des processus/fichiers/inodes ••


▶ chaque processus
▶ fichier ouvert ⇒ un numéro fd (file descriptor)
▶ table des processus
▶ pour chaque ⇒ une table de ses fd
▶ le fd utilisé par le processus = index dans cette table
▶ table des fichiers ouverts
▶ comment le fichier a été ouvert (R/W/RW/A)
▶ position courante par rapport au début
▶ pointeur sur un inode en mémoire
▶ compteur de références (close ⇒ -1, 0 ⇒ destruction)
▶ plusieurs processus peuvent partager un même fichier ouvert
▶ table des inodes en mémoire
▶ copie des inodes du volume
⇒ type de fichier, permissions, etc.
▶ numéro d’inode
▶ compteur de références
Franck Pommereau Les processus • 94 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Concepts
API infos
API cycle de vie
Identités
Communications entre processus
Threads POSIX
Franck Pommereau Les processus • Concepts 95 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Concepts
API infos
API cycle de vie
Identités
Communications entre processus
Threads POSIX
Franck Pommereau Les processus • Concepts 96 / 172

Naissance, vie, et mort des processus

▶ chaque processus est identifié par un numéro > 0 de type pid_t (généralement un int)
▶ à chaque instant, le pid de chaque processus est unique
▶ mais un même pid peut être réutilisé plus tard pour un autre processus
▶ une seule façon de créer un nouveau processus : fork 2
▶ duplique le processus qui l’appelle
⇒ un processus parent et un enfant (arbre des processus)
▶ l’enfant peut se remplacer par un autre programme avec exec 2
▶ la séquence fork(); exec() permet de lancer un programme
▶ le premier processus init est créé de façon spéciale
(init a le pid 1 et démarre tout le système)
▶ un processus qui termine devient un zombie
▶ état mort-vivant permettant de consulter son statut de terminaison
▶ un autre processus peut consulter cet état avec wait 2
⇒ le zombie est éliminé
▶ si un parent termine avant ses enfants, ils sont rattachés à init
Franck Pommereau Les processus • Concepts 97 / 172

États d’un processus


syscall
/intr
kernel exit
user running zombie
return running
/ret to user

elected preempted sleep

ready to run sleeping


memory in memory wakeup in memory
fork
available

created swap out swap in swap out

no memory
available
ready to run wakeup sleeping
swapped swapped
Franck Pommereau Les processus • API infos 98 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Concepts
API infos
API cycle de vie
Identités
Communications entre processus
Threads POSIX
Franck Pommereau Les processus • API infos 99 / 172
getpid 2
getpid() et getppid() getppid 2

1 #include <sys/types.h>
2 #include <unistd.h>
3
4 pid_t getpid(void);
5 pid_t getppid(void);

▶ getpid() renvoie le pid du processus qui l’exécute


▶ getppid() renvoie le pid du processus parent
▶ peut être celui de init si le parent a déjà terminé
(ou d’un processus à qui ce rôle a été délégué)
▶ ces appels systèmes ne font jamais d’erreur
▶ un pid pid_t est un simple numéro > 0
Franck Pommereau Les processus • API infos 100 / 172
getcwd 2
getcwd() et chdir() chdir 2

1 #include <unistd.h>
2
3 char *getcwd(char *buf, size_t size);

▶ getcwd(NULL, 0) renvoie le chemin de travail courant


▶ alloué par malloc 3 ⇒ à libérer par free 3
▶ extension GNU (l’original getwd oblige à prévoir un tampon de taille suffisante)
▶ renvoie NULL en cas d’erreur (avec errno)

1 #include <unistd.h>
2
3 int chdir(const char *path);

▶ change le répertoire de travail courant


▶ équivalent à la commande shell cd path
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Les processus • API infos 101 / 172
times 2
times()
1 #include <sys/times.h>
2
3 clock_t times(struct tms *buf);
4
5 struct tms {
6 clock_t tms_utime; // user time
7 clock_t tms_stime; // system time
8 clock_t tms_cutime; // user time of children
9 clock_t tms_cstime; // system time of children
10 };

▶ écrit les temps d’exécution du processus et des ses enfants dans buf
▶ distingue temps utilisateur et temps système (état user/kernel running)
▶ uniquement les enfants dont le processus a collecté l’état (wait 2 )
▶ temps comptés en tics d’horloge
sysconf(_SC_CLK_TCK) ⇒ nombre de tics par seconde
▶ renvoie une valeur arbitraire en cas de succès, -1 sinon (avec errno)
Franck Pommereau Les processus • API infos 102 / 172
setpgid 2
Sessions et groupes de processus getpgid 2
setsid 2
getsid 2
▶ groupe : pgid ⇒ ensemble de processus qui travaillent ensemble
▶ session : sid ⇒ ensemble de processus issus d’un même terminal (session utilisateur)
▶ ces identifiants sont des pids
▶ certains appels systèmes agissent sur un groupe ou une session
1 #include <sys/types.h>
2 #include <unistd.h>
3
4 int setpgid(pid_t pid, pid_t pgid);
5 pid_t getpgid(pid_t pid);
6
7 pid_t setsid(void);
8 pid_t getsid(pid_t pid);

▶ positionnent/récupèrent le pgid/sid d’un processus


▶ renvoient 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Les processus • API cycle de vie 103 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Concepts
API infos
API cycle de vie
Identités
Communications entre processus
Threads POSIX
Franck Pommereau Les processus • API cycle de vie 104 / 172
exit 2
exit()

1 #include <stdlib.h>
2
3 void exit(int status);

▶ termine le processus avec le code de retour status & 0xFF


▶ on peut utiliser les constantes EXIT_SUCCESS et EXIT_FAILURE
▶ ou toute autre valeur entre 0 et 255
▶ cet appel ne termine pas (et donc ne renvoie rien)
▶ équivalent à return status dans main
Franck Pommereau Les processus • API cycle de vie 105 / 172
fork 2
fork()
1 #include <sys/types.h>
2 #include <unistd.h>
3
4 pid_t fork(void);
▶ duplique le processus et renvoie :
▶ 0 dans l’enfant
▶ le pid de l’enfant dans le parent, ou -1 en cas d’erreur (avec errno)
▶ les deux processus reprennent leur exécution au return de fork()
▶ dans un ordre quelconque
▶ même état des variables, fichiers ouverts, pile d’appels, etc.
▶ seule différence : la valeur de retour de fork() (et le pid)
1 pid_t p = fork();
2 if (p == -1) {
3 // dans le parent, en erreur
4 } else if (p) {
5 // dans le parent, l'enfant a le pid p
6 } else {
7 // dans l'enfant
8 }
Franck Pommereau Les processus • API cycle de vie 106 / 172
wait 2
wait()
1 #include <sys/types.h>
2 #include <sys/wait.h>
3
4 pid_t wait(int *wstatus);

▶ wait() attend la terminaison d’un processus enfant et


collecte son statut
▶ le processus enfant doit être zombie ⇒ complètement éliminé
▶ le processus appelant est suspendu
▶ renvoie le pid du processus collecté, ou -1 en cas d’erreur (avec errno)
▶ si wstatus n’est pas NULL, il reçoit le statut de terminaison
⇒ à inspecter avec des macros dédiées
▶ WIFEXITED(wstatus) ⇒ vrai si l’enfant a terminé normalement
(avec exit ou un return depuis main)
▶ WEXITSTATUS(wstatus) ⇒ statut passé à exit ou retourné par main
▶ WIFSIGNALED(wstatus) ⇒ vrai si l’enfant a été tué par un signal
▶ WTERMSIG(wstatus) > numéro du signal dans ce cas
Franck Pommereau Les processus • API cycle de vie 107 / 172
waitpid 2
waitpid()
1 #include <sys/types.h>
2 #include <sys/wait.h>
3
4 pid_t waitpid(pid_t pid, int *wstatus, int options);
▶ wait(&ws) est équivalent à waitpid(-1,&ws,0)
▶ l’argument pid indique quel processus enfant on attend :
▶ -1 ⇒ n’importe lequel
▶ >0 ⇒ celui avec ce pid
▶ 0 ⇒ n’importe lequel dans le même groupe que l’appelant
▶ <-1 ⇒ n’importe lequel dans le groupe numéro -pid
▶ options == WNOHANG ⇒ appel non bloquant
⇒ termine immédiatement (même s’il n’y a aucun enfant zombie)
▶ renvoie :
▶ le pid de l’enfant dont le statut a été collecté
▶ -1 en cas d’erreur (avec errno)
▶ 0 si on a utilisé l’option WNOHANG et qu’aucun enfant n’a terminé
Franck Pommereau Les processus • API cycle de vie 108 / 172

Recouvrement

▶ lancer un programme ⇒ remplacement du processus


▶ programme et arguments ⇒ argv du main qui sera exécuté
▶ toute une famille de fonctions exec :
▶ “l” ⇒ argv passés à la fonction (execl 3 , execlp 3 , execle 3 )
▶ “v” ⇒ argv passés comme un tableau (execv 3 , execvp 3 , execve 2 )
▶ “e” ⇒ définition d’un nouvel environnement (execle 3 , execve 2 )
▶ “p” ⇒ recherche du programme selon PATH (execlp 3 , execvp 3 )
▶ le processus est remplacé ⇒ la fonction ne termine pas
▶ sauf si exec impossible ⇒ renvoie -1 (avec errno)
▶ l’appel système est execve 2
▶ le reste : fonctions de la libc pour faciliter l’usage
▶ glibc fournit aussi execvpe 3
Franck Pommereau Les processus • API cycle de vie 109 / 172

La variable d’environnement PATH

▶ liste de répertoires séparés par des “:”


☞ PATH=/bin:/usr/bin:/usr/local/bin
▶ commande shell “foo -a -v bar spam” cherchée comme
1. /bin/foo
2. /usr/bin/foo
3. /usr/local/bin/foo
le premier chemin trouvé qui est un fichier exécutable est lancé avec
argv = {"foo", "-a", "-v", "bar", "spam"}
▶ même mécanisme avec execlp 3 et execvp 3
▶ voir aussi
▶ which 1 ⇒ affiche quel exécutable sera lancé
▶ whereis 1 ⇒ recherche un exécutable même en dehors de PATH
Franck Pommereau Les processus • API cycle de vie 110 / 172
execl 3
execl(), execlp(), et execle() execlp 3
execle 3

1 #include <unistd.h>
2
3 int execl(const char *pathname, const char *arg, ...
4 /* (char*) NULL */);
5 int execlp(const char *file, const char *arg, ...
6 /* (char*) NULL */);
7 int execle(const char *pathname, const char *arg, ...
8 /* (char*) NULL, char *const envp[] */);
▶ commande à lancer
▶ chemin (execl, execle) ou nom (exclp) du programme
▶ les arguments y compris argv[0]
▶ fin des arguments marquée par NULL
▶ par exemple :
1 ret = execl("/usr/bin/gcc", "gcc", "-c", "monprog.c", NULL);
2 ret = execlp("gcc", "gcc", "-c", "monprog.c", NULL);
3
4 char *env[] = {"TMPDIR=.", NULL};
5 ret = execle("/usr/bin/gcc", "gcc", "-c", "monprog.c", NULL, env);
Franck Pommereau Les processus • API cycle de vie 111 / 172
execv 3
execv(), execvp(), et execve() execvp 3
execve 2

1 #include <unistd.h>
2
3 int execv(const char *pathname, char *const argv[]);
4 int execvp(const char *file, char *const argv[]);
5 int execve(const char *pathname, char *const argv[],
6 char *const envp[]);

▶ similaire à la famille execl, sauf pour les arguments


▶ permet de construire argv dynamiquement
▶ fin des tableaux marquée par NULL
▶ par exemple :
1 char *args[] = {"gcc", "-c", "monprog.c", NULL};
2 ret = execv("/usr/bin/gcc", args);
3 ret = execvp(args[0], args); // pas obligatoirement comme ça
4
5 char *env[] = {"TMPDIR=.", NULL};
6 ret = execve("/usr/bin/gcc", args, env);
Franck Pommereau Les processus • Identités 112 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Concepts
API infos
API cycle de vie
Identités
Communications entre processus
Threads POSIX
Franck Pommereau Les processus • Identités 113 / 172
setuid 2
Les identités d’un processus
▶ chaque processus est identifié par
▶ real user id : ruid (programmes setuid)
▶ effective user id : euid ⇒ contrôle des permissions
▶ saved user id : suid
▶ changement d’identité avec setuid(id) ⇒ autorisé si
▶ euid == 0 ou euid == id (ou la capacité CAP_SETUID)
▶ ou si suid == id (suid permet le retour en arrière)
et alors : suid = euid = ruid = id
▶ programme setuid ⇒ affecte euid du processus

ruid = 0 setuid(42) ruid = 42 setuid(42) ruid = 42


euid = 0 euid = 42 euid = 42
suid = 0 setuid(0) suid = 0 suid = 42

Franck Pommereau Les processus • Identités 114 / 172
getuid 2
getuid(), geteuid(), et setuid() geteuid 2
setuid 2

1 #include <unistd.h>
2 #include <sys/types.h>
3
4 uid_t getuid(void);
5 uid_t geteuid(void);
6 int setuid(uid_t uid);

▶ getuid() ⇒ renvoie le ruid du processus


▶ geteuid() ⇒ renvoie le euid du processus
▶ setuid(id) ⇒ change le euid du processus (et ruid et suid)
▶ inutile pour les processus non privilégié (mais autorisé)
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
▶ peut échouer même si les conditions sont respectées
⇒ toujours vérifier le retour
Franck Pommereau Les processus • Identités 115 / 172

Démons
▶ processus qui s’exécute en tâche de fond
▶ fork() et rattachement à init
▶ positionne divers paramètres
▶ condamne ses entrées-sorties standards
1 pid_t pid = fork();
2 if (pid == -1) {
3 exit (EXIT_FAILURE); // fork() a échoué => tout échoue
4 } else if (pid != 0) {
5 exit (EXIT_SUCCESS); // fork a réussi => le parent termine
6 } // => l'enfant est rattaché à init
7 /* - setsid()
8 - chdir()
9 - setuid()
10 - ... */
11 // ferme les entrées-sorties standards
12 // d'autres techniques les condamnent: dup2()
13 close(STDIN_FILENO);
14 close(STDOUT_FILENO);
15 close(STDERR_FILENO);
Franck Pommereau Communications entre processus • 116 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • Fichiers 117 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • Fichiers 118 / 172

Lire/écrire dans les mêmes fichiers


▶ méthode la plus simple pour échanger des données. . .
▶ . . . mais pas la plus fiable
▶ terminaison incertaine
▶ cohérence difficile à maintenir
▶ rappel sur read 2
1 #include <unistd.h>
2 ssize_t read(int fd, void *buf, size_t count);
▶ renvoie 0 si on atteint la fin du fichier
▶ mais si un autre processus écrit ensuite, on peut lire de nouveau
▶ il faut définir un protocole pour détecter la “vraie” fin du fichier
(par exemple : séquence d’octets prédéterminé, terminaison des écrivains)
▶ verrous d’enregistrements (plages d’octets)
▶ éviter d’écrire les mêmes zones d’un fichier
▶ éviter de lire pendant une écriture
▶ portabilité compliquée :
▶ mode coopératif sur certains Unix ⇒ n’empêche pas les e/s
▶ mode impératif sur d’autres ⇒ empêche les e/s
Franck Pommereau Communications entre processus • Fichiers 119 / 172
fcntl 2
struct flock
1 #include <unistd.h>
2
3 struct flock {
4 short l_type; // type de verrou: F_RDLCK, F_WRLCK, F_UNLCK
5 short l_whence; // sens de l_start: SEEK_SET, SEEK_CUR, SEEK_END
6 off_t l_start; // début de la plage
7 off_t l_len; // nombre d'octets de la plage
8 pid_t l_pid; // processus propriétaire du verrou
9 };
▶ l_type
▶ F_RDLCK ⇒ lecture : non exclusif d’autres lectures, exclusif d’écritures
▶ F_WRLCK ⇒ écriture : exclusif de tout autre accès
▶ F_UNLCK ⇒ déverrouillage
▶ l_whence et l_start ⇒ début de la plage (comme pour lseek 2 )
▶ l_len ⇒ nombre d’octets de la plage (0 ⇒ maximum, même après la fin)
▶ l_pid ⇒ chaque verrou est associé à
▶ un processus propriétaire ⇒ exit() / fork() / execve()
▶ un fichier ⇒ close() / open() avec O_CLOEXEC
Franck Pommereau Communications entre processus • Fichiers 120 / 172
fcntl 2
fcntl()
1 #include <unistd.h>
2 #include <fcntl.h>
3
4 int fcntl(int fd, int cmd, struct flock *flockptr);
▶ fcntl 2 a beaucoup d’usages, ici : trois valeurs pour cmd
▶ F_GETLK ⇒ teste si un autre processus a verrouillé cette plage
▶ à l’appel flockptr ⇒ verrou à tester (fcntl “simule la pose”)
▶ au retour flockptr ⇒ verrou trouvé
▶ F_SETLK ⇒ verrouille une plage
▶ flockptr ⇒ verrou à poser
▶ remplace tout autre verrou de ce processus sur ce fichier
▶ non bloquant ⇒ renvoie une erreur si un verrou incompatible existe
▶ F_SETLKW ⇒ comme F_SETLK mais bloquant
▶ attention aux deadlocks
▶ attention aussi à la non atomicité de plusieurs appels successifs
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • Fichiers 121 / 172

Tester un verrou
getlock.c
1 #include <sys/types.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4
5 pid_t get_lock (int fd, short type, short whence, off_t start, off_t len) {
6 struct flock lock = {.l_type = type, .l_whence = whence,
7 .l_start = start, .l_len = len};
8 if (fcntl(fd, F_GETLK, &lock) < 0) {
9 return -1; // error => caller will check errno
10 }
11 if (lock.l_type == F_UNLCK) {
12 return 0; // no conflicting lock found
13 } else {
14 return lock.l_pid; // lock found => return owner's pid
15 }
16 }

▶ aucun verrou incompatible trouvé ⇒ 0 (ignore les verrous du processus, ou d’autres en lecture)
▶ verrou incompatible trouvé ⇒ pid du processus propriétaire
▶ erreur ⇒ -1 (avec errno)
Franck Pommereau Communications entre processus • Fichiers 122 / 172

Verrouiller/déverrouiller une plage


setlock.c
1 #include <sys/types.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4
5 pid_t set_lock (int fd, short type, short whence, off_t start, off_t len) {
6 struct flock lock = {.l_type = type, .l_whence = whence,
7 .l_start = start, .l_len = len};
8 return fcntl(fd, F_SETLK, &lock);
9 }

▶ set_lock(f, F_RDLCK, ...) ⇒ pose un verrou en lecture


▶ set_lock(f, F_WRLCK, ...) ⇒ pose un verrou en écriture
▶ set_lock(f, F_UNLCK, ...) ⇒ supprime tout verrou sur la plage
▶ renvoient 0 en cas de succès, -1 en cas d’erreur (avec errno)
▶ un verrou en écrase un autre du même processus
▶ plusieurs processus peuvent verrouiller de mêmes plages en lecture
Franck Pommereau Communications entre processus • Signaux 123 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • Signaux 124 / 172

Signaux
▶ signal = évènement
▶ envoyé à un ou plusieurs processus
▶ ne transporte pas de données
▶ mais plusieurs signaux possibles
▶ un signal tue le processus s’il n’est pas prêt à le recevoir
▶ envoyer un signal dans le shell :
$ xeyes &
[1] 143967
$ kill -ALRM 143967
[1]+ Alarm clock xeyes
$
▶ xeyes est lancé avec le pid 143967
▶ kill envoie le signal ALARM à ce processus
▶ xeyes meurt car il ne s’attendait pas à recevoir un signal
▶ le shell sait qu’il a été tué par le signal Alarm clock
▶ touches spéciales dans le terminal :
Ctrl + Z ⇒ STOP Ctrl + C ⇒ INT Ctrl + \ ⇒ QUIT
Franck Pommereau Communications entre processus • Signaux 125 / 172
kill 2
kill() signal 7

1 #include <sys/types.h>
2 #include <signal.h>
3
4 int kill(pid_t pid, int sig);
▶ envoie un signal sig au processus pid
▶ pid est un numéro de processus (>0) ou bien :
▶ 0 ⇒ tous les processus du même groupe
▶ -1 ⇒ tous les processus (pour lesquels c’est autorisé, et sauf init)
▶ <-1 ⇒ tous les processus du groupe -pid
▶ autorisé vers les processus de même uid
(ou tous les processus si privilégié)
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
▶ signal.h définit des noms de signaux :
SIGALRM, SIGINT, SIGKILL, . . . (voir la liste dans signal 7 )
▶ SIGKILL et SIGSTOP ne peuvent pas être interceptés
Franck Pommereau Communications entre processus • Signaux 126 / 172
sigaction 2
Recevoir un signal signal 7

1 #include <signal.h>
2
3 struct sigaction {
4 void (*sa_handler)(int);
5 int sa_flags;
6 // ...
7 };
8
9 int sigaction(int signum, const struct sigaction *act,
10 struct sigaction *oldact);
▶ active le traitant act et récupère le précédent dans oldact
▶ act.sa_handler est un pointeur sur une fonction void (int)
▶ act.sa_flags indique comment gérer le traitant : (combiner avec |)
▶ SA_NODEFER ⇒ un nouveau signal peut être reçu pendant le traitant
▶ SA_RESETHAND ⇒ le traitant sera désinstallé à réception de signum
▶ SA_RESTART ⇒ le traitant sera réinstallé à réception de signum
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
▶ l’appel système signal 2 est plus simple mais pas portable
Franck Pommereau Communications entre processus • Signaux 127 / 172

Exemple de réception de signaux

signal.c signal.c
1 #include <signal.h> 15 int main (void) {
2 #include <stdio.h> 16 struct sigaction act;
3 #include <stdlib.h> 17 act.sa_handler = exit_on_sig;
4 #include <unistd.h> 18 sigaction(SIGINT, &act, NULL);
5 19 act.sa_handler = print_on_sig;
6 void exit_on_sig (int sig) { 20 act.sa_flags = SA_RESTART;
7 printf("! %i\n", sig); 21 sigaction(SIGQUIT, &act, NULL);
8 exit(0); 22 printf("= %i\n", getpid());
9 } 23 while (1) {
10 24 sleep(1);
11 void print_on_sig (int sig) { 25 }
12 printf("? %i\n", sig); 26 }
13 } 27

▶ on définit deux traitants


▶ on les installe à tour de rôle au début de main
▶ puis le processus affiche son pid et dort indéfiniment
Franck Pommereau Communications entre processus • Pipes 128 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • Pipes 129 / 172

Communiquer par tubes


▶ pipe = file d’attente de char
▶ plusieurs lecteurs/écrivains
▶ lectures/écritures potentiellement bloquantes
▶ dans le shell :
$ ls *.c | grep hello | sed 's/hello/yolo/'
yolo.c
yolo-main.c
yolo-print.c
yolo-read.c
$

stdin stdout stdin stdout stdin stdout

ls grep sed
stderr stderr stderr

¥
Franck Pommereau Communications entre processus • Pipes 130 / 172
pipe 2
pipe() pipe 7

1 #include <unistd.h>
2
3 int pipe(int pipefd[2]);

▶ crée un pipe et fournit deux numéros de fichiers :


▶ pipefd[0] ⇒ pour la lecture
▶ pipefd[1] ⇒ pour l’écriture
▶ équivalent à deux fichiers ouverts mais :
▶ mode FIFO
▶ vide ⇒ bloquant en lecture
▶ plein ⇒ bloquant en écriture
un signal peut interrompre une écriture bloquée, write 2 termine alors et renvoie le nombre
d’octets déjà écrits avant l’interruption. Ce n’est pas une erreur dans ce cas.
▶ hérités par les processus fils ⇒ à utiliser avant fork 2
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • Pipes 131 / 172
dup2 2
dup2()
1 #include <unistd.h>
2
3 int dup2(int oldfd, int newfd);
▶ remplace le descripteur de fichier newfd par un copie de oldfd
▶ si newfd est ouvert, il est d’abord fermé
▶ agit directement sur la table des fichiers ouverts ý
▶ utilisé surtout pour connecter un pipe à une entrée/sortie standard
▶ renvoie newfd en cas de succès, -1 en cas d’erreur (avec errno)
dup2.c dup2.c
1 #include <unistd.h> 11 // connecte le côté écriture du pipe
2 #include <stdlib.h> 12 // sur la sortie standard du processus
3 #include <stdio.h> 13 if (dup2(p[1], STDOUT_FILENO) == -1) {
4 14 perror("dup2");
5 int main (void) { 15 exit(EXIT_FAILURE);
6 int p[2]; 16 }
7 if (pipe(p) == -1) { 17 // ...
8 perror("pipe"); 18 }
9 exit(EXIT_FAILURE);
10 }
Franck Pommereau Communications entre processus • Pipes 132 / 172
mkfifo 2
mkfifo()

1 #include <sys/types.h>
2 #include <sys/stat.h>
3
4 int mkfifo(const char *path, mode_t mode);

▶ crée un pipe nommé sur le système de fichier


avec le nom path et les permissions mode
▶ fichier spécial de type S_IFFIFO
▶ le fichier doit ensuite être ouvert en lecture et/ou écriture
▶ bloquant tant que les deux extrémités ne sont pas ouvertes
▶ partagé entre tous les processus qui peuvent y accéder
(compte tenu des permissions)
▶ vidé quand tous les processus l’ont fermé
▶ devra être effacé
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • Pipes 133 / 172
poll 2
poll()
1 #include <poll.h>
2
3 struct pollfd {
4 int fd; // file descriptor
5 short events; // requested events
6 short revents; // returned events
7 };
8 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
▶ surveille nfds fichiers pendant timeout milli-secondes (au plus)
▶ chaque fichier dans un .fd, événements attendus dans .events
▶ POLLIN ⇒ données disponibles en lecture
▶ POLLOUT ⇒ écriture possible
▶ POLLERR ⇒ fichier en erreur
▶ timeout < 0 ⇒ attente infinie
▶ renvoie -1 en cas d’erreur (avec errno) et sinon
▶ 0 ⇒ temps écoulé, aucun des événements attendus n’a eu lieu
▶ > 0 ⇒ nombre de fichiers avec des événements ⇒ dans les .revents
▶ POLLHUP ⇒ pipe fermé à l’autre extrémité
▶ POLLNVAL ⇒ demande invalide
Franck Pommereau Communications entre processus • IPC système V 134 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • IPC système V 135 / 172
sysvipc 7
IPC système V
▶ communications avancées entre processus
▶ files de messages : msg (format libre)
▶ sémaphores : sem (verrous flexibles)
▶ partage de mémoire : shm (segments)
▶ indépendant du système de fichiers
▶ chaque type ⇒ gestion spécifique
▶ identifiant externe (clef) de type key_t (≃ chemin d’un fichier)
▶ identifiant interne de type int (≃ numéro d’un fichier ouvert)
▶ permissions (comme pour les fichiers)
1 #include <sys/ipc.h>
2
3 struct ipc_perm {
4 uid_t cuid; // creator user ID
5 gid_t cgid; // creator group ID
6 uid_t uid; // owner user ID
7 gid_t gid; // owner group ID
8 unsigned short mode; // u/g/o r/w permissions
9 };
Franck Pommereau Communications entre processus • IPC système V 136 / 172

Une API uniforme


▶ files de messages : msg
▶ msgget() ⇒ création/ouverture d’une file
▶ msgctl() ⇒ contrôle d’une file
▶ msgsnd() ⇒ envoi d’un message
▶ msgrcv() ⇒ réception d’un message
▶ plus struct msgid_ds et struct msgbuf
▶ segments partagés : shm
▶ shmget() ⇒ création/ouverture d’un segment de mémoire partagé
▶ shmctl() ⇒ contrôle d’un segment
▶ shmat() ⇒ rattachement d’un segment à une adresse
▶ shmdt() ⇒ détachement d’un segment
▶ plus struct shmid_ds
▶ sémaphores : sem
▶ semget() ⇒ création/ouverture d’un ensemble de sémaphores
▶ semctl() ⇒ contrôle d’un ensemble de sémaphores
▶ semop() ⇒ opération sur un ensemble de sémaphores
▶ plus struct semid_ds et struct sembuf
Franck Pommereau Communications entre processus • IPC système V 137 / 172
ftok 3
ftok()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3
4 key_t ftok(const char *pathname, int proj_id);
▶ crée une clef à partir de
▶ le nom pathname d’un fichier existant
▶ les 8 bits de poids faible de proj_id
▶ utilisable pour tous les types d’IPC
▶ renvoie la clef en cas de succès, -1 en cas d’erreur (avec errno)
▶ sous Linux, c’est un numéro sur 32 bits avec
▶ 16 bits issus du numéro d’inode
▶ 8 bits issus du numéro de volume
▶ 8 bits issus de proj_id
⇒ le fichier doit exister et être accessible
▶ on n’est pas obligé de créer une clef ⇒ IPC_PRIVATE (voir plus loin)
Franck Pommereau Communications entre processus • IPC : files de messages 138 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • IPC : files de messages 139 / 172
msgget 2
Files de messages : msgget()

1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4
5 int msgget(key_t key, int flags);

▶ ouvre la file de messages identifiée par la clef key


▶ key == IPC_PRIVATE ⇒ une nouvelle file est créée, sans clef
⇒ ne pourra pas être partagée avec d’autres processus (sauf enfants)
▶ flags est un mode (permissions) combiné par | avec
▶ IPC_CREAT ⇒ crée la file si elle n’existe pas
▶ IPC_EXCL ⇒ échoue si la file existe déjà
▶ renvoie l’identifiant interne en cas de succès
-1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : files de messages 140 / 172
msgctl 2
Files de messages : msgctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4
5 struct msqid_ds {
6 struct ipc_perm msg_perm; // ownership and permissions *
7 time_t msg_stime; // time of last msgsnd
8 time_t msg_rtime; // time of last msgrcv
9 time_t msg_ctime; // time of last change
10 msgqnum_t msg_qnum; // current number of messages
11 msglen_t msg_qbytes; // maximum number of bytes allowed *
12 pid_t msg_lspid; // PID of last msgsnd
13 pid_t msg_lrpid; // PID of last msgrcv
14 };
15
16 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
▶ opération de contrôle sur la file msqid selon cmd
▶ IPC_STAT ⇒ renseigne buf avec les paramètres actuels
▶ IPC_SET ⇒ modifie les paramètres * selon buf
▶ IPC_RMID ⇒ supprime la file immédiatement
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : files de messages 141 / 172
msgsnd 2
Files de messages : msgsnd()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4
5 struct msgbuf {
6 long mtype; // message type, must be > 0
7 ... // user-defined message data
8 };
9
10 int msgsnd(int msqid, const void *msgp, size_t msgsz, int flags);
▶ envoie sur la file msqid un message contenu dans msgp
▶ msgp est un pointeur sur struct msgbuf
▶ structure libre après le champ .mtype
▶ msgsz ⇒ taille en octets de la partie libre de struct msgbuf
▶ flags == IPC_NOWAIT ⇒ échec immédiat si la file est pleine
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : files de messages 142 / 172
msgrcv 2
Files de messages : msgrcv()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4
5 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int flags);
▶ récupère et supprime un message sur la file msqid
▶ copié dans msgq pour un maximum de msgsz octets (partie libre)
▶ msgtyp permet de filtrer le message à récupérer
▶ 0 ⇒ le premier de la file
▶ > 0 ⇒ le premier message de ce type
▶ < 0 ⇒ le premier de type minimal <= -msgtyp
▶ flags paramètre le comportement
▶ IPC_NOWAIT ⇒ termine avec erreur en l’absence de message
▶ MSG_NOERROR ⇒ ne fait pas d’erreur si le message est trop long
▶ MSG_EXCEPT ⇒ inverse le sens de msgtyp > 0 (le premier d’un autre type)
▶ renvoie le nombre d’octets lus dans la partie libre en cas de succès
-1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : mémoire partagée 143 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • IPC : mémoire partagée 144 / 172
shmget 2
Partage de mémoire : shmget()

1 #include <sys/ipc.h>
2 #include <sys/shm.h>
3
4 int shmget(key_t key, size_t size, int flags);

▶ ouvre un segment de mémoire partagée


▶ identifié par la clef key (ou IPC_PRIVATE)
▶ de taille size octets (ou zéro s’il existe déjà)
▶ flags ⇒ comme pour msgget 2
▶ segment créé ⇒ initialisé avec des zéros
▶ renvoie l’identifiant interne en cas de succès
-1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : mémoire partagée 145 / 172
shmctl 2
Partage de mémoire : shmctl()
1 #include <sys/ipc.h>
2 #include <sys/shm.h>
3
4 struct shmid_ds {
5 struct ipc_perm shm_perm; // ownership and permissions *
6 size_t shm_segsz; // size of segment (bytes)
7 time_t shm_atime; // last attach time
8 time_t shm_dtime; // last detach time
9 time_t shm_ctime; // last change time
10 pid_t shm_cpid; // PID of creator
11 pid_t shm_lpid; // PID of last shmat/shmdt
12 shmatt_t shm_nattch; // number of current attaches
13 };
14
15 int shmctl(int shmid, int cmd, struct shmid_ds *buf);

▶ opération de contrôle sur l’ensemble shmid, selon cmd


▶ IPC_STAT ⇒ renseigne buf selon le paramétrage courant
▶ IPC_SET ⇒ change le paramétrage* selon buf
▶ IPC_RMID ⇒ supprime le segment partagé (fait quand plus aucun processus ne l’utilisera)
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : mémoire partagée 146 / 172
shmat 2
Partage de mémoire : shmat() et shmdt() shmdt 2

1 #include <sys/types.h>
2 #include <sys/shm.h>
3
4 void *shmat(int shmid, const void *shmaddr, int shmflg);
5 int shmdt(const void *shmaddr);

▶ shmat attache un segment de mémoire partagé


▶ shaddr != NULL ⇒ l’attache à cette adresse spécifique
▶ sinon, choisit une adresse
▶ shmflg == SHM_RDONLY ⇒ lecture seule
▶ renvoie l’adresse d’attachement en cas de succès (≃ malloc 3 )
(void*)-1 en cas d’erreur (avec errno)
▶ shmdt détache le segment attaché à shmaddr
▶ renvoie 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : sémaphores 147 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • IPC : sémaphores 148 / 172

Sémaphores
▶ sémaphore = compteur semval avec opérations atomiques
▶ affecter ⇒ semval = p
▶ lire ⇒ donne semval
▶ “prendre” p <= semval ⇒ semval -= p
tant que p > semval ⇒ le processus est bloqué
▶ “rendre” p ⇒ semval += p
▶ attendre 0 ⇒ processus bloqué tant que semval > 0
▶ cas particulier : semval <= 1 ⇒ simple verrou
▶ dans IPC système V ⇒ ensembles de sémaphores
(protéger plusieurs ressources simultanément)
▶ exemple : garantir un maximum de personnes présentes simultanément dans un magasin
ayant plusieurs accès
▶ initialiser un sémaphore au maximum souhaité
▶ entrée ⇒ prendre 1
▶ sortie ⇒ rendre 1
Franck Pommereau Communications entre processus • IPC : sémaphores 149 / 172
semget 2
Sémaphores : semget()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 int semget(key_t key, int nsems, int flags);
▶ ouvre l’ensemble de sémaphores identifié par la clef key
▶ s’il n’existe pas encore :
▶ flags = mode | IPC_CREAT
▶ nsems > 0 ⇒ nombre de sémaphores dans l’ensemble
▶ s’il existe déjà :
▶ on peut utiliser nsems == 0
▶ flags ignoré
▶ key == IPC_PRIVATE ⇒ création sans clef (comme msgget 2 )
▶ IPC_EXCL dans flags ⇒ échoue si l’ensemble existe déjà
▶ renvoie l’identifiant interne en cas de succès
-1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
⇒ avec semnum ignoré et struct semid_ds *arg
▶ cmd == IPC_STAT ⇒ renseigne args avec le paramétrage courant
▶ cmd == IPC_SET ⇒ change le paramétrage* selon arg
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
⇒ avec semnum ignoré et sans arg
▶ cmd == IPC_RMID ⇒ sans arg, supprime l’ensemble immédiatement
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
⇒ pour le sémaphore d’index semnum dans l’ensemble, sans arg
▶ cmd == GETVAL ⇒ valeur du sémaphore semval
▶ cmd == GETPID ⇒ pid du dernier processus ayant utilisé le sémaphore
▶ cmd == GETNCNT ⇒ nombre de processus attendant semval++
▶ cmd == GETZCNT ⇒ nombre de processus attentant semval == 0
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
⇒ pour le sémaphore d’index semnum dans l’ensemble, avec int arg
▶ cmd == SETVAL ⇒ assigne la valeur du sémaphore
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
⇒ avec semnum ignoré, et unsigned short *arg
▶ cmd == GETALL ⇒ écrit la valeur de tous les sémaphores de l’ensemble dans arg
▶ cmd == GETALL ⇒ assigne la valeur de tous les sémaphores de l’ensemble selon arg
Franck Pommereau Communications entre processus • IPC : sémaphores 150 / 172
semctl 2
Sémaphores : semctl()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct semid_ds {
6 struct ipc_perm sem_perm; // ownership and permissions *
7 time_t sem_otime; // Last semop time
8 time_t sem_ctime; // Last change time
9 unsigned long sem_nsems; // No. of semaphores in set
10 };
11
12 int semctl(int semid, int semnum, int cmd, ... /* arg */ );
▶ opération de contrôle sur l’ensemble semid, selon cmd
▶ renvoie -1 en cas d’erreur (avec errno)
sinon, retour selon cmd
Franck Pommereau Communications entre processus • IPC : sémaphores 151 / 172
semop 2
Sémaphores : semop()
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/sem.h>
4
5 struct sembuf {
6 unsigned short sem_num; // index in the set
7 short sem_op; // operation to apply
8 short sem_flg; // IPC_NOWAIT, SEM_UNDO
9 };
10
11 int semop(int semid, struct sembuf *sops, size_t nsops);
▶ applique de façon atomique les nsops opérations dans sops
▶ .sem_op < 0 ⇒ prend des ressources au sémaphore .sem_num
▶ .sem_op > 0 ⇒ rend des ressources au sémaphore .sem_num
▶ .sem_op == 0 ⇒ attend que le sémaphore .sem_num atteigne zéro
▶ si IPC_NOWAIT dans .sem_flg ⇒ erreur au lieu d’un blocage
▶ si SEM_UNDO dans .sem_flg ⇒ gère un compteur de ressources prises
⇒ rendues si le processus s’arrête (par processus et par sémaphore)
Franck Pommereau Communications entre processus • IPC : conclusion 152 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • IPC : conclusion 153 / 172

Bilan sur les IPC système V


▶ files de messages
✔ assez simples à utiliser, files à priorités, persistance des messages
✘ libération manuelle des ressources, pas de multiplexage (poll 2 )
pipes (pipe 2 )
pipes nommés (mkfifo 3 )
▶ segments de mémoire partagés
✔ simples à utiliser, assez généraux
✘ (rien)
fichiers en mémoire (mmap 2 )
threads POSIX (pthreads 7 )
▶ sémaphores
✔ généraux et flexibles
✘ lourds à utiliser, peu performants
verrous de fichiers (fcntl 2 )
sémaphores POSIX (sem_overview 7 ⇒ juste après)
Franck Pommereau Communications entre processus • Sémaphores POSIX 154 / 172

Sommaire
Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Fichiers
Signaux
Pipes
IPC système V
IPC : files de messages
IPC : mémoire partagée
IPC : sémaphores
IPC : conclusion
Sémaphores POSIX
Threads POSIX
Franck Pommereau Communications entre processus • Sémaphores POSIX 155 / 172
sem_overview 7
Sémaphores POSIX ý mutex ý queues

▶ plus simples que ceux d’IPC système V (et plus performants)


▶ sémaphores uniques ▶ similaire aux fichiers
▶ uniquement ±1 ▶ suppression selon utilisation
▶ deux types
▶ nommés ⇒ facilement partageables entre des processus
▶ sem_open 3 ⇒ ouvre ou crée un sémaphore (comme un fichier)
▶ sem_close 3 ⇒ ferme un sémaphore
▶ sem_unlink 3 ⇒ détruit un sémaphore
▶ anonymes ⇒ gérés uniquement en mémoire
▶ sem_init 3 ⇒ crée un sémaphore
▶ sem_destroy 3 ⇒ supprime un sémaphore
▶ quatre opérations (principales)
▶ sem_wait 3 ⇒ prend une ressource
▶ sem_trywait 3 ⇒ prend une ressource sans blocage
▶ sem_timedwait 3 ⇒ prend une ressource avec blocage limité
▶ sem_post 3 ⇒ rend une ressource
▶ option -pthread à la compilation (dans CoW : // ldd: -pthread )
Franck Pommereau Communications entre processus • Sémaphores POSIX 156 / 172
sem_open 3
sem_open(), sem_close(), et sem_unlink() sem_close 3
sem_unlink 3
1 #include <fcntl.h>
2 #include <sys/stat.h>
3 #include <semaphore.h>
4
5 sem_t *sem_open(const char *name, int oflag,
6 mode_t mode, unsigned int value);
7 sem_t *sem_open(const char *name, int oflag);
8 int sem_close(sem_t *sem);
9 int sem_unlink(const char *name);
▶ sem_open
▶ 4 arguments ⇒ crée un nouveau sémaphore ⇒ O_CREAT dans oflag
(O_EXCL utilisable, comme pour open 2 )
▶ 2 arguments ⇒ ouvre un sémaphore existant
▶ name ⇒ exactement un “/”, placé au début
▶ renvoie un pointeur vers le sémaphore en case de succès
SEM_FAILED en cas d’erreur (avec errno)
▶ sem_close et sem_unlink renvoient 0 en cas de succès
-1 sinon (avec errno)
Franck Pommereau Communications entre processus • Sémaphores POSIX 157 / 172
sem_init 3
sem_init() et sem_destroy() sem_destroy 3

1 #include <semaphore.h>
2
3 int sem_init(sem_t *sem, int pshared, unsigned int value);
4 int sem_destroy(sem_t *sem);

▶ sem_init
▶ nécessite une variable sem_t partagée par les processus
(par exemple dans un segment de mémoire partagé)
▶ pshared == 1 pour un partage entre processus
(0 pour un partage entre threads ⇒ sem peut être une variable globale)
▶ value ⇒ valeur initiale du sémaphore
▶ ne pas utiliser sem_destroy pour un sémaphore sur lequel des processus sont bloqués
▶ renvoient 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Communications entre processus • Sémaphores POSIX 158 / 172
sem_wait 3
sem_wait(), sem_trywait(), et sem_post() sem_trywait 3
sem_post 3

1 #include <semaphore.h>
2
3 struct timespec {
4 time_t tv_sec; // seconds
5 long tv_nsec; // nanoseconds [0 .. 999999999]
6 };
7
8 int sem_wait(sem_t *sem);
9 int sem_trywait(sem_t *sem);
10 int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
11 int sem_post(sem_t *sem);
▶ sem_wait ⇒ prend une ressource en bloque si le sémaphore vaut zéro
▶ sem_trywait ⇒ retourne en erreur au lieu de bloquer
▶ sem_timedwait ⇒ retourne en erreur si bloqué après abs_timeout
(“date” fixe à partir de l’epoch)
▶ sem_post ⇒ rend une resource (et débloque un processus)
▶ renvoient 0 en cas de succès, -1 en cas d’erreur (avec errno)
Franck Pommereau Threads POSIX • 159 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Vue d’ensemble
API de base
Mécanismes de synchronisation
Franck Pommereau Threads POSIX • Vue d’ensemble 160 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Vue d’ensemble
API de base
Mécanismes de synchronisation
Franck Pommereau Threads POSIX • Vue d’ensemble 161 / 172
pthreads 7
Threads
Processus légers

▶ threads = exécutions parallèles au sein d’un même processus


▶ même espace mémoire ⇒ variables globales, tas, fichiers, etc.
▶ piles séparées ⇒ variables locales, paramètres, etc.
✔ plus légers que des processus (commutations, mémoire)
✔ communications plus simples (mémoire partagée)
✘ mêmes difficultés pour la synchronisation (races, deadlocks)

processus threads remarque


pid_t pthread_t type opaque, non portable
getpid() pthread_self()
fork() pthread_create()
exit() pthread_exit() statut arbitraire
waitpid() pthread_join() statut arbitraire
errno retour des fonctions pthread_... errno disponible

les exemples donnés dans ce chapitre ne testent pas les erreurs


Franck Pommereau Threads POSIX • API de base 162 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Vue d’ensemble
API de base
Mécanismes de synchronisation
Franck Pommereau Threads POSIX • API de base 163 / 172
pthread_self 3p
Identifiants de threads pthread_equal 3p

1 // ldd: -pthread
2 #include <pthread.h>
3
4 pthread_t pthread_self(void);
5 int pthread_equal(pthread_t t1, pthread_t t2);

▶ contrairement à pid_t, pthread_t est opaque


▶ différent entre les versions d’Unix
▶ on ne peut pas l’afficher
▶ pthread_self ⇒ identifiant du thread appelant
▶ pthread_equal ⇒ test l’égalité de deux identifiants de threads
Franck Pommereau Threads POSIX • API de base 164 / 172
pthread_create 3p
Création et terminaison d’un thread pthread_exit 3p

1 // ldd: -pthread
2 #include <pthread.h>
3
4 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
5 void *(*start_routine) (void *), void *arg);
6 void pthread_exit(void *retval);

▶ pthread_create ⇒ démarre start_routine(arg) dans un nouveau thread


▶ on doit avoir déclaré : void* start_routine (void*)
▶ écrit l’identifiant du nouveau thread dans thread
▶ attr == NULL ⇒ attributs par défaut (suffisant le plus souvent)
▶ arg est une structure de donnée arbitraire
▶ renvoie 0 en cas de succès, un code d’erreur sinon
▶ pthread_exit ⇒ termine le thread appelant en renvoyant retval
▶ même effet que return retval depuis start_routine
▶ retval récupérable par pthread_join
▶ comme exit 3 , cette fonction ne retourne pas (fin du thread)
Franck Pommereau Threads POSIX • API de base 165 / 172
pthread_join 3p
Retour d’un thread pthread_cancel 3p

1 // ldd: -pthread
2 #include <pthread.h>
3
4 int pthread_join(pthread_t thread, void **retval);
5 int pthread_cancel(pthread_t thread);

▶ pthread_join attend la terminaison de thread


▶ retval != NULL ⇒ écrit la valeur de retour dedans
▶ renvoie 0 en cas de succès, un code d’erreur sinon
▶ pthread_cancel demande l’arrêt de thread
▶ on ne peut pas forcer l’arrêt
▶ il peut l’accepter ou pas (dans ses attributs)
▶ il peut choisir quand il est arrêtable
(n’importe quand ou sur un point d’arrêt = fonctions particulières)
▶ arrêt ⇒ la valeur de retour est PTHREAD_CANCELED
▶ renvoie 0 en cas de succès, un code d’erreur sinon
Franck Pommereau Threads POSIX • API de base 166 / 172

Exemple
threads.c threads.c

1 // ldd: -pthread 23 int main (int argc, char *argv[]) {


2 #include <pthread.h> 24 pthread_t threads[argc];
3 #include <stdio.h> 25 struct thread_arg ta[argc];
4 #include <unistd.h> 26 void *ret;
5 #include <stdlib.h> 27 int i;
6 28 for (i=0; i<argc; i++) {
7 struct thread_arg { 29 ta[i].num = i;
8 int num; 30 ta[i].txt = argv[i];
9 char* txt; 31 pthread_create(&(threads[i]), NULL, start, &(ta[i]));
10 }; 32 }
11 33 for (i=0; i<argc; i++) {
12 void* start (void *arg) { 34 pthread_cancel(threads[i]);
13 struct thread_arg *ta = arg; 35 pthread_join(threads[i], &ret);
14 if (ta->num) { 36 printf("> %i => %li\n", i, (long)ret);
15 printf("hello from #%i: %s\n", 37 }
16 ta->num, ta->txt); 38 exit(0);
17 return (void*)1; 39 }
18 } else {
$ ./a.out Jacques Lucie Sarah
19 return (void*)0;
hello from #1: Jacques
20 }
> 0 => 0
21 }
> 1 => 1
hello from #3: Sarah
hello from #2: Lucie
> 2 => 1
> 3 => 1
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 167 / 172

Sommaire

Rappels de C
Environnement du programme
Le système de fichiers
Entrées/sorties
Les processus
Communications entre processus
Threads POSIX
Vue d’ensemble
API de base
Mécanismes de synchronisation
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 168 / 172
pthread_mutex_lock 3p
Mutex (mutual exclusion) pthread_mutex_unlock 3p

▶ on a déjà vu les sémaphores POSIX/pthreads ý


▶ mutex ≃ cas particulier avec valeur maximale à 1
▶ prendre ⇒ verrouiller (lock)
▶ rendre ⇒ déverrouiller (unlock)
mutex.c mutex.c

1 // ldd: -pthread 20 int main (void) {


2 #include <pthread.h> 21 pthread_t threads[100];
3 #include <stdio.h> 22 int targs[100];
4 #include <unistd.h> 23 int i;
5 #include <stdlib.h> 24 for (i=0; i<100; i++) {
6 25 targs[i] = i;
7 int count = 0; 26 pthread_create(threads+i, NULL,
8 pthread_mutex_t lock = 27 start, targs+i);
9 PTHREAD_MUTEX_INITIALIZER; 28 }
10 29 for (i=0; i<100; i++) {
11 void* start (void *arg) { 30 pthread_join(threads[i], NULL);
12 int *stop = arg; 31 }
13 for (int i=0; i<*stop; i++) { 32 printf("%i == %i\n", count, 99*100/2);
14 pthread_mutex_lock(&lock); 33 exit(0);
15 count += 1; 34 }
16 pthread_mutex_unlock(&lock);
17 }
18 } Exercice : essayez sans mutex, qu’observez-vous ?
19
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 169 / 172
pthread_cond_wait 3p
Conditions pthread_cond_signal 3p

▶ attente d’un événement ⇒ threads débloqués par un signal


▶ couplé à un verrou ⇒ protège les données associées à l’événement
cond.c cond.c

1 // ldd: -pthread 23 pthread_cond_signal(&cond);


2 #include <pthread.h> 24 break;
3 #include <stdio.h> 25 }
4 #include <unistd.h> 26 } // end while
5 #include <stdlib.h> 27 }
6 28
7 int count = 1000; 29 int main (void) {
8 30 pthread_t threads[10];
9 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 31 int targs[10], i;
10 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 32 for (i=0; i<10; i++) {
11 33 targs[i] = i;
12 void* start (void *arg) { 34 pthread_create(threads+i, NULL, start, targs+i);
13 int *step = arg; 35 }
14 int zero; 36 pthread_mutex_lock(&lock);
15 while (1) { 37 pthread_cond_wait(&cond, &lock);
16 pthread_mutex_lock(&lock); 38 printf("%i\n", count);
17 if (count >= *step) { 39 pthread_mutex_unlock(&lock);
18 count -= *step; 40 for (i=0; i<10; i++) {
19 } 41 pthread_join(threads[i], NULL);
20 zero = (count <= 0); 42 }
21 pthread_mutex_unlock(&lock); 43 exit(0);
22 if (zero) { 44 }
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 170 / 172
pthread_barrier_init 3p
Barrières de synchronisation pthread_barrier_wait 3p

▶ rendez-vous entre num threads :


▶ pthread_barrier_init ⇒ initialise le compteur de la barrière à num
▶ pthread_barrier_wait ⇒ décrémente et bloque le thread
▶ le compteur tombe à zéro ⇒ tous les threads sont débloqués
▶ un peu l’inverse d’un sémaphore

barrier.c barrier.c

1 // ldd: -pthread 13 int main (void) {


2 #include <stdio.h> 14 pthread_t threads[10];
3 #include <pthread.h> 15 int targs[10], i;
4 #include <unistd.h> 16 pthread_barrier_init(&barrier, NULL, 10);
5 17 for (i=0; i<10; i++) {
6 pthread_barrier_t barrier; 18 sleep(1);
7 19 targs[i] = i;
8 void *start (void *arg) { 20 pthread_create(threads+i, NULL, start, targs+i);
9 pthread_barrier_wait(&barrier); 21 }
10 printf("hello from %i!\n", *(int*)arg); 22 for (i=0; i<10; i++) {
11 } 23 pthread_join(threads[i], NULL);
12 24 }
25 }
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 171 / 172
mq_overview 7
Files de messages

▶ API proche des sémaphores POSIX/pthreads ý


▶ mq_open 3 ⇒ ouvre ou crée une file
▶ mq_send 3 ⇒ envoie un message
▶ mq_receive 3 ⇒ reçoit un message
▶ mq_close 3 ⇒ ferme une file
▶ mq_unlink 3 ⇒ détruit une file
▶ plus de fonctionnalités que les files IPC système V
▶ support explicite des priorités
▶ notifications asynchrones (mq_notify 3 )
▶ attente avec échéance (mq_timedsend 3 , mq_timedreceive 3 )
▶ persistance après l’arrêt des processus
▶ subtilité sur la réception : prévoir pour le plus grand message possible
▶ compiler avec la bibliothèque librt : option -lrt
(en plus de -pthread)
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 172 / 172

Files de messages : exemple

mq.c
1 // ldd: -pthread -lrt
2 #include <pthread.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <mqueue.h>
9
10 struct msg { // stores a message
11 int num;
12 char txt[256];
13 };
14
15 typedef union { // stores a message + raw char* to it
16 struct msg msg;
17 char raw[sizeof(struct msg)];
18 } msg_t;
19
20 mqd_t queue; // shared among threads
21
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 172 / 172

Files de messages : exemple

mq.c
22 void* start (void *arg) { // threads activity
23 msg_t msg;
24 while (1) {
25 mq_receive(queue, msg.raw, sizeof(msg_t), NULL);
26 printf("[%i] %i: %s\n", *(int*)arg, msg.msg.num, msg.msg.txt);
27 }
28 }
29
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 172 / 172

Files de messages : exemple

mq.c
30 int main (int argc, char *argv[]) {
31 int i;
32 msg_t msg;
33 pthread_t threads[10]; // threads
34 int targs[10]; // threads args
35 struct mq_attr attr = {.mq_maxmsg = argc,
36 .mq_msgsize = sizeof(msg_t)}; // important for mq_receive
37 queue = mq_open("/myqueue", O_RDWR|O_CREAT|O_EXCL, 0660, &attr);
38 for (i=0; i<10; i++) { // create 10 threads
39 targs[i] = i;
40 pthread_create(threads+i, NULL, start, targs+i);
41 }
42 // ...
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 172 / 172

Files de messages : exemple

mq.c
43 // main...
44 for (i=1; i<argc; i++) { // send each argv[i] as a message
45 msg.msg.num = i;
46 memset(msg.msg.txt, 0, 256);
47 strncpy(msg.msg.txt, argv[i], 255);
48 mq_send(queue, msg.raw, sizeof(msg_t), 0);
49 }
50 sleep(1); // wait enough for messages to be received
51 for (i=0; i<10; i++) { // terminate threads
52 pthread_cancel(threads[i]); // work when blocked on queue
53 pthread_join(threads[i], NULL);
54 }
55 mq_close(queue); // close queue
56 mq_unlink("/myqueue"); // delete queue
57 exit(0);
58 }
Franck Pommereau Threads POSIX • Mécanismes de synchronisation 172 / 172

Files de messages : exemple

$ ./a.out foo bar egg spam


[2] 3: egg
[0] 1: foo
[6] 4: spam
[1] 2: bar

▶ les messages sont envoyés et reçus dans l’ordre


▶ mais les threads sont ordonnancés arbitrairement
▶ n’importe lequel peut recevoir n’importe quel message
▶ entre la réception et l’affichage, d’autres peuvent s’exécuter

Vous aimerez peut-être aussi