Cosa succede quando chiudo () un descrittore di file?


16

Sto cercando di ottenere l'intera immagine con i descrittori di file. Supponiamo di avere process1 che inizialmente ha questi descrittori di file:

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

Quindi chiudo il descrittore di file 1:

close(1);

Il descrittore di file 1 traduce (punti) nella struttura FILE stdout nella tabella Open Files del kernel .

Con il codice sopra il descrittore di file 1 viene eliminato dalla tabella del processo che diventa:

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

Ma cosa succede nel kernel? La stdoutstruttura FILE viene deallocata? Come è possibile se stdout è un file speciale (il monitor) e probabilmente utilizzato da altri processi? Che dire delle strutture FILE che sono solo file normali (ad esempio .txt)? Cosa succede se un tale file viene utilizzato da un altro processo?

Risposte:


13

Il descrittore di file 1 si traduce nella struttura FILE stdout nella tabella Open Files del kernel.

Questo è un malinteso. La tabella dei file del kernel non ha nulla a che fare con le strutture dei file dello spazio utente.

In ogni caso, il kernel ha due livelli di riferimento indiretto. C'è la struttura interna che rappresenta il file stesso, che viene contato come riferimento. Esiste una "descrizione del file aperto" che viene contata come riferimento. E poi c'è l'handle del file, che non viene contato come riferimento. La struttura del file indica la strada verso l'inode stesso. La descrizione del file aperto contiene elementi come la modalità aperta e il puntatore del file.

Quando chiami chiudi, chiudi sempre l'handle del file. Quando viene chiuso un handle di file, il conteggio dei riferimenti nella descrizione del file aperto viene ridotto. Se va a zero, viene rilasciata anche la descrizione del file aperto e il conteggio dei riferimenti sul file stesso viene ridotto. Solo se questo va a zero viene liberata la struttura dei file del kernel.

Non è possibile che un processo rilasci una risorsa utilizzata da un altro processo poiché vengono contate le risorse condivise.


Ho una leggera difficoltà a comprendere la terminologia nella tua risposta. Immagino che il puntatore del file significhi "offset del file". È quello che volevi dire? Anche cosa intendevi per gestione dei file ?
Geek,

Esatto, con "offset file" intendo l'offset in corrispondenza del quale si verificherebbe una successiva lettura o scrittura. Un "handle di file" è un collegamento tra un processo e una descrizione del file aperto: è ciò che ottieni quando ci openriesce.
David Schwartz,

6

In questo caso non succederà molto. stdin, stdout e stderr tendono ad essere cloni dello stesso descrittore di file. Il contatore di riferimento per il descrittore di file verrà decrementato di uno. Lo stesso descrittore di file è in genere gestito dalla shell da cui è stato eseguito il programma, quindi il descrittore di file deve essere mantenuto.

Il kernel mantiene i conteggi dei riferimenti per tutti i file (inode) che sono aperti. Finché il conteggio dei riferimenti è maggiore di zero, il file verrà mantenuto. Mi aspetto che venga mantenuto un contatore separato per gli handle di file aperti. Una volta che questo raggiunge lo zero, il kernel può rilasciare la memoria utilizzata dall'handle del file.

Quando tutti i riferimenti al file (voci di directory e handle di file) sono stati rimossi, il codice del file system contrassegnerà l'inode per il riutilizzo. Tutti i blocchi che il file ha sono resi disponibili per l'allocazione. Molti file system cancellano i puntatori di blocco nell'inode quando viene rilasciato. Ciò rende difficile il ripristino di un file eliminato. Gli aggiornamenti al disco possono essere bufferizzati e completati in un secondo momento.


1
Due domande: (1) i descrittori di file sono davvero contati di nuovo? Quando controlli-d a cat > some.file, cat ottiene un EOF su stdin, ma la shell no. (2) Perché contare i riferimenti? Perché non una qualche forma di raccolta dei rifiuti? GC non è molto meglio nello spazio utente?
Bruce Ediger,

Espandere la risposta di BillThor: in casi normali stdin, stdout e stderr sono solo handle di file aperti su un dispositivo TTY. Quindi, se chiudi l'handle del file, quel dispositivo TTY è ancora lì e può anche essere riaperto in un secondo momento.
Patrick,

1
@BruceEdiger: (1) quando la shell esegue cat > some.fileciò che sta effettivamente facendo è il fork, aprendo 'some.file' e assegnandolo al descrittore di file 1, quindi lo fa exec("cat"). Quando un processo è exec () 'd, eredita i descrittori di file aperti.
Patrick,

@BruceEdiger (2) Il conteggio dei riferimenti è una forma perfettamente accurata di garbage collection quando viene utilizzato su strutture di dati che non contengono puntatori (o catene di puntatori che terminano in) altre strutture di dati dello stesso tipo. Inoltre, questo sta accadendo nello spazio del kernel (non che sia molto importante).
Gilles 'SO- smetti di essere malvagio' il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.