Apa yang terjadi ketika saya menutup () deskriptor file?

16

Saya mencoba untuk mendapatkan seluruh gambar dengan deskriptor file. Katakanlah saya memiliki process1 yang awalnya memiliki deskriptor file ini:

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

Lalu saya menutup file descriptor 1:

close(1);

Deskriptor file 1 menerjemahkan (menunjuk) ke struktur FILE stdout di Open Files Table kernel .

Dengan kode di atas file deskriptor 1 akan dihapus dari tabel proses yang menjadi:

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

Tetapi apa yang terjadi di kernel? Apakah stdoutstruktur FILE dapat dialokasikan kembali? Bagaimana mungkin jika stdout adalah file khusus (monitor) dan mungkin digunakan oleh proses lain? Bagaimana dengan struktur FILE yang hanya file biasa (misalnya .txt)? Bagaimana jika file seperti itu digunakan oleh proses lain?

Pithikos
sumber

Jawaban:

13

Deskripsi file 1 diterjemahkan ke struktur FILE stdout di Tabel File Terbuka Kernel.

Ini adalah kesalahpahaman. Tabel file kernel tidak ada hubungannya dengan struktur file ruang pengguna.

Bagaimanapun, kernel memiliki dua tingkat tipuan. Ada struktur internal yang mewakili file itu sendiri, yang dihitung referensi. Ada "deskripsi file terbuka" yang dihitung referensi. Dan kemudian ada pegangan file, yang tidak dihitung referensi. Struktur file menunjukkan jalan ke inode itu sendiri. Deskripsi file terbuka berisi hal-hal seperti mode terbuka dan penunjuk file.

Saat Anda memanggil tutup, Anda selalu menutup gagang file. Ketika suatu pegangan file ditutup, jumlah referensi pada deskripsi file yang terbuka dikurangi. Jika menjadi nol, deskripsi file yang terbuka juga dirilis dan jumlah referensi pada file itu sendiri dikurangi. Hanya jika itu menjadi nol adalah struktur file kernel dibebaskan.

Tidak ada peluang bagi satu proses untuk melepaskan sumber daya yang digunakan proses lain karena sumber daya bersama dihitung referensi.

David Schwartz
sumber
Saya memiliki sedikit kesulitan dengan pemahaman tentang terminologi dalam jawaban Anda. Saya menduga bahwa penunjuk file berarti "file offset". Apakah itu yang kamu maksud? Juga apa yang Anda maksud dengan pegangan file ?
Geek
Itu benar, dengan "file offset", maksud saya offset di mana baca atau tulis berikutnya akan terjadi. "Pegangan file" adalah tautan antara proses dan deskripsi file terbuka - itulah yang Anda dapatkan saat openberhasil.
David Schwartz
6

Dalam hal ini tidak banyak yang akan terjadi. stdin, stdout, dan stderr semuanya cenderung merupakan klon dari deskriptor file yang sama. Penghitung referensi untuk deskriptor file akan dikurangi oleh satu. Deskriptor file yang sama biasanya dipegang oleh shell tempat program dijalankan, sehingga deskriptor file perlu disimpan.

Kernel menyimpan jumlah referensi untuk semua file (inode) yang terbuka. Selama jumlah referensi lebih besar dari nol file akan disimpan. Saya berharap penghitung terpisah disimpan untuk menangani file terbuka. Setelah ini mencapai nol, kernel dapat melepaskan memori yang digunakan oleh file handle.

Ketika semua referensi ke file (entri direktori dan pegangan file) telah dihapus, kode sistem file akan menandai inode untuk digunakan kembali. Setiap blok file telah tersedia untuk alokasi. Banyak sistem file akan menghapus pointer blok di inode ketika dirilis. Ini membuat memulihkan file yang dihapus menjadi sulit. Pembaruan ke disk dapat disangga dan diselesaikan di lain waktu.

BillThor
sumber
1
Dua pertanyaan: (1) apakah deskriptor file benar-benar dihitung ulang? Saat Anda mengontrol-a cat > some.file, kucing mendapat EOF pada stdin, tetapi cangkangnya tidak. (2) Mengapa penghitungan referensi? Mengapa tidak mengumpulkan sampah? Bukankah GC jauh lebih baik di ruang pengguna?
Bruce Ediger
Memperluas jawaban BillThor: Dalam kasus normal stdin, stdout, dan stderr hanyalah buka pegangan file ke perangkat TTY. Jadi jika Anda menutup pegangan file, perangkat TTY itu masih ada, dan bahkan dapat dibuka kembali di lain waktu.
Patrick
1
@BruceEdiger: (1) ketika shell menjalankan cat > some.fileapa yang sebenarnya dilakukan adalah forking, membuka 'some.file' dan menugaskannya ke file deskriptor 1, maka ia melakukannya exec("cat"). Ketika suatu proses adalah exec () 'd, itu mewarisi deskriptor file terbuka.
Patrick
@BruceEdiger (2) Penghitungan referensi adalah bentuk pengumpulan sampah yang sangat baik ketika digunakan pada struktur data yang tidak mengandung pointer ke (atau rantai pointer berakhir) struktur data lain dari tipe yang sama. Juga, ini terjadi dalam ruang kernel (bukan berarti sangat penting).
Gilles 'SO- stop being evil'