Compte-rendu de TP
Appels système Unix — lseek, fork/wait, tubes
Exercice 1 — Appel système lseek et évolution de deplacementTF
Cas 1 : Sans O_APPEND
Après l'ouverture du fichier texte avec O_RDWR | O_CREAT, le descripteur de fichier est
positionné à 0.
Sortie standard affichée :
0 ← lseek après open (position initiale)
26 ← lseek après write (26 octets écrits)
0 ← lseek SEEK_SET à 0
abc ← read 3 octets
3 ← position après 1er read
def ← read 3 octets suivants
6 ← position après 2e read
9 ← position après write(buf,3) → "def" écrit en pos 6
4 ← lseek(-5, SEEK_CUR) → 9-5=4
efd ← read 3 octets à partir de la pos 4 (e, f, d écrasé)
7 ← position finale
Contenu du fichier après exécution :
abcde[def]jklmnopqrstuvwxyz (positions 6-8 : 'ghi' remplacé par 'def')
2e exécution consécutive sans O_APPEND :
Le fichier existant est ouvert sans troncature (O_CREAT ne recrée pas le fichier). La même
séquence de lectures/écritures s'applique à un fichier identique : le contenu ne change pas.
Cas 2 : Avec O_APPEND
Avec O_APPEND, chaque appel write() déplace automatiquement le curseur en fin de
fichier avant d'écrire, quelle que soit la position courante.
Sortie standard affichée (1re exécution) :
0 ← lseek après open (position initiale)
26 ← lseek après write : O_APPEND place en fin (0), écrit 26 octets
0 ← lseek SEEK_SET
abc ← read 3 octets
3 ← position après 1er read
def ← read 3 octets suivants
6 ← position après 2e read
29 ← write(buf,3) : O_APPEND place en fin (26), écrit 3 octets → pos 29
24 ← lseek(-5, SEEK_CUR) → 29-5=24
yzd ← read à partir de 24 : 'y','z' puis 'd' (1er octet ajouté)
27 ← position finale
Contenu du fichier :
abcdefghijklmnopqrstuvwxyz + def (29 octets)
2e exécution avec O_APPEND :
Le fichier fait déjà 29 octets. Les deux writes() ajoutent respectivement 26 puis 3 octets en
fin de fichier. Le fichier atteint 58 octets. Les valeurs affichées diffèrent (55 pour la 2e
position, etc.) car le curseur est positionné plus loin après chaque écriture. Le fichier grandit
à chaque exécution.
Exercice 2 — Complément sur fork et wait
Messages affichés
Le processus père crée deux fils via fork() :
• Le fils 1 affiche son PID puis entre dans une boucle infinie (for(;;)).
• Le fils 2 affiche son PID puis termine avec exit(12).
• Le père attend 2 secondes (sleep(2)), puis appelle deux fois wait().
Sortie typique observée :
fils = <PID_fils2>
fils = <PID_fils1>
(... 2 secondes ...)
fin de <PID_fils2>, p = 3072 ← exit(12) → p = 12 << 8 = 3072
fin de <PID_fils1>, p = ... ← bloquant, car fils1 tourne encore
Le fils 2 se termine rapidement et devient zombie en attendant que le père l'attende. Le
premier wait() récupère le fils 2 (valeur p = 12 × 256 = 3072 via WEXITSTATUS). Le
deuxième wait() est bloquant tant que le fils 1 tourne.
Destruction du processus en boucle infinie
Pour tuer le fils 1 qui est en boucle infinie, il faut envoyer un signal SIGKILL depuis le
terminal :
kill -9 <PID_fils1>
Une fois le signal envoyé, le fils 1 se termine, et le deuxième wait() dans le père se débloque
et retourne.
Exercice 3 — Tube ordinaire et inter-blocage
Un tube (pipe) est créé, puis fork() donne un fils. Le père écrit dans le tube, le fils lit.
Cas 1 : Code d'origine (sans sleep ni modifications)
Le père effectue deux appels write() et deux appels close() sur p[1]. Le fils ferme p[0] avant
de lire — c'est une erreur critique :
• close(p[0]) ferme le descripteur de lecture du fils.
• Les appels read(p[0], ...) suivants échouent (Bad file descriptor).
• Aucun message n'est affiché, les write() vers stdout renvoient 0.
Cas 2 : Avec sleep(2) décommenté (1re occurrence)
Le père attend 2 secondes avant de fermer p[1]. Le fils tente de lire p[0] mais ce descripteur
est déjà fermé (close(p[0]) en tête du else). Même résultat : aucun affichage significatif. Le
sleep ne change pas le problème fondamental.
Cas 3 : Fils modifié avec sleep(1) et sans close(p[1])
Le fils attend 1 seconde, puis lit sans fermer p[1]. Le père écrit "abcdefgh" dans le tube et
ferme p[1]. Ensuite il tente un deuxième write() sur p[1] déjà fermé → signal SIGPIPE (ou
errno EPIPE).
• Le fils lit 4 octets : affiche "abcd".
• Le fils lit 4 octets : affiche "efgh".
• Le fils tente de lire 1 octet : bloquant si p[1] n'est pas totalement fermé.
abcdefgh
Cas 4 : Cas 3 avec close(p[1]) décommenté dans le fils
Le fils ferme sa copie de p[1] après sleep(1). Tous les descripteurs en écriture sont alors
fermés. Les lectures se terminent proprement :
• 1er read : lit "abcd" → affiche "abcd".
• 2e read : lit les 4 octets suivants "efgh" → affiche "efgh".
• 3e read : retourne 0 (fin de fichier) → rien affiché.
abcdefgh
C'est le seul cas où le programme se termine proprement, sans inter-blocage. Fermer toutes
les extrémités inutiles du tube est indispensable pour éviter les blocages.