Que se passe-t-il lorsque je ferme () un descripteur de fichier?

16

J'essaie d'obtenir l'image complète avec des descripteurs de fichiers. Disons que j'ai process1 qui a initialement ces descripteurs de fichiers:

 _process1_
|          |
| 0 stdin  |
| 1 stdout |
| 2 stderr |
|__________|

Ensuite, je ferme le descripteur de fichier 1:

close(1);

Le descripteur de fichier 1 se traduit (pointe) par la structure stdout FILE dans la table des fichiers ouverts du noyau .

Avec le code ci-dessus, le descripteur de fichier 1 est supprimé de la table du processus qui devient:

 _process1_
|          |
| 0 stdin  |
| 2 stderr |
|__________|

Mais que se passe-t-il dans le noyau? La stdoutstructure FILE est-elle désallouée? Comment est-ce possible si stdout est un fichier spécial (le moniteur) et probablement utilisé par d'autres processus? Qu'en est-il des structures FILE qui ne sont que des fichiers normaux (.txt par exemple)? Que faire si un tel fichier est utilisé par un autre processus?

Pithikos
la source

Réponses:

13

Le descripteur de fichier 1 se traduit par la structure FICHIER stdout dans la table des fichiers ouverts du noyau.

C'est un malentendu. La table de fichiers du noyau n'a rien à voir avec les structures de fichiers de l'espace utilisateur.

En tout état de cause, le noyau a deux niveaux d'indirection. Il y a la structure interne qui représente le fichier lui-même, qui est compté par référence. Il existe une "description de fichier ouvert" qui est comptée par référence. Et puis il y a le descripteur de fichier, qui n'est pas compté par référence. La structure du fichier indique le chemin vers l'inode lui-même. La description du fichier ouvert contient des éléments comme le mode ouvert et le pointeur de fichier.

Lorsque vous appelez close, vous fermez toujours le descripteur de fichier. Lorsqu'un descripteur de fichier est fermé, le nombre de références sur sa description de fichier ouvert est décrémenté. S'il passe à zéro, la description du fichier ouvert est également publiée et le nombre de références sur le fichier lui-même est décrémenté. Ce n'est que si cela va à zéro que la structure de fichiers du noyau est libérée.

Il n'y a aucune chance qu'un processus libère une ressource qu'un autre processus utilise car les ressources partagées sont comptées par référence.

David Schwartz
la source
J'ai une légère difficulté avec la compréhension de la terminologie dans votre réponse. Je suppose que le pointeur de fichier signifie "décalage de fichier". C'est ce que vous vouliez dire? Aussi ce que vous vouliez dire par descripteur de fichier ?
Geek
C'est exact, par "décalage de fichier", je veux dire le décalage auquel une lecture ou une écriture ultérieure se produirait. Un "descripteur de fichier" est un lien entre un processus et une description de fichier ouvert - c'est ce que vous obtenez en cas de opensuccès.
David Schwartz
6

Dans ce cas, il ne se passera pas grand-chose. stdin, stdout et stderr ont tous tendance à être des clones du même descripteur de fichier. Le compteur de référence pour le descripteur de fichier sera décrémenté de un. Le même descripteur de fichier est généralement détenu par le shell à partir duquel le programme a été exécuté, donc le descripteur de fichier doit être conservé.

Le noyau conserve le nombre de références pour tous les fichiers (inodes) ouverts. Tant que le nombre de références est supérieur à zéro, le fichier sera conservé. Je m'attendrais à ce qu'un compteur séparé soit conservé pour les descripteurs de fichiers ouverts. Une fois que cela atteint zéro, le noyau peut libérer la mémoire utilisée par le descripteur de fichier.

Lorsque toutes les références au fichier (entrées de répertoire et descripteurs de fichiers) ont été supprimées, le code du système de fichiers marque l'inode pour la réutilisation. Tous les blocs du fichier sont disponibles pour l'allocation. De nombreux systèmes de fichiers effaceront les pointeurs de bloc dans l'inode lorsqu'il sera libéré. Cela rend difficile la récupération d'un fichier supprimé. Les mises à jour sur le disque peuvent être mises en mémoire tampon et terminées ultérieurement.

BillThor
la source
1
Deux questions: (1) les descripteurs de fichiers sont-ils vraiment recomptés? Lorsque vous contrôlez-d a cat > some.file, cat obtient un EOF sur stdin, mais pas le shell. (2) Pourquoi compter les références? Pourquoi pas une forme de ramassage des ordures? Le GC n'est-il pas bien meilleur dans l'espace utilisateur?
Bruce Ediger
Étendre la réponse de BillThor: Dans des cas normaux, stdin, stdout et stderr sont simplement des descripteurs de fichiers ouverts vers un appareil TTY. Donc, si vous fermez le descripteur de fichier, ce périphérique TTY est toujours là et peut même être rouvert ultérieurement.
Patrick
1
@BruceEdiger: (1) lorsque le shell exécute cat > some.filece qu'il fait, il ouvre, 'some.file' et l'affecte au descripteur de fichier 1, alors il le fait exec("cat"). Lorsqu'un processus est exec () 'd, il hérite des descripteurs de fichiers ouverts.
Patrick
@BruceEdiger (2) Le comptage de références est une forme parfaitement fine de récupération de place lorsqu'il est utilisé sur des structures de données qui ne contiennent pas de pointeurs vers (ou des chaînes de pointeurs se terminant par) d'autres structures de données du même type. En outre, cela se produit dans l'espace noyau (ce n'est pas très important).
Gilles 'SO- arrête d'être méchant'