fork()
dan vfork()
pembungkus di glibc diimplementasikan melalui clone()
panggilan sistem. Untuk lebih memahami hubungan antara fork()
dan clone()
, kita harus mempertimbangkan hubungan antara proses dan utas di Linux.
Biasanya, fork()
akan menduplikasi semua sumber daya yang dimiliki oleh proses induk dan menugaskan salinan tersebut ke proses anak. Pendekatan ini menimbulkan banyak biaya tambahan, yang semuanya mungkin sia-sia jika anak segera memanggil exec()
. Di Linux, fork()
menggunakan copy-on-write halaman untuk menunda atau sama sekali menghindari penyalinan data yang dapat dibagi antara proses induk dan anak. Dengan demikian, satu-satunya overhead yang dikeluarkan selama fork()
normal adalah penyalinan tabel halaman induk dan penetapan struktur deskriptor proses yang unik, task_struct
, untuk anak.
Linux juga mengambil pendekatan luar biasa untuk utas. Di Linux, utas hanyalah proses biasa yang berbagi beberapa sumber daya dengan proses lain. Ini adalah pendekatan utas yang sangat berbeda dibandingkan dengan sistem operasi lain seperti Windows atau Solaris, di mana proses dan utas adalah jenis binatang buas yang sama sekali berbeda. Di Linux, setiap utas memiliki task_struct
biasa sendiri yang kebetulan disiapkan sedemikian rupa sehingga berbagi sumber daya tertentu, seperti ruang alamat, dengan proses induk.
flags
parameter clone()
panggilan sistem menyertakan sekumpulan tanda yang menunjukkan sumber daya mana, jika ada, proses induk dan anak yang harus dibagikan. Proses dan utas keduanya dibuat melalui clone()
, satu-satunya perbedaan adalah set flag yang diteruskan ke clone()
.
fork()
biasa dapat diimplementasikan sebagai:
clone(SIGCHLD, 0);
Ini membuat tugas yang tidak membagikan sumber daya apa pun dengan induknya, dan disetel untuk mengirim SIGCHLD
sinyal terminasi ke induk saat keluar.
Sebaliknya, tugas yang berbagi ruang alamat, sumber daya sistem file, deskriptor file, dan penangan sinyal dengan induknya, dengan kata lain, sebuah utas , dapat dibuat dengan:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
vfork()
pada gilirannya diimplementasikan melalui CLONE_VFORK
yang terpisah flag, yang akan menyebabkan proses induk untuk tidur sampai proses anak membangunkannya melalui sinyal. Anak akan menjadi satu-satunya utas eksekusi di namespace induk, hingga memanggil exec()
atau keluar. Anak tidak diperbolehkan menulis ke memori. clone()
yang sesuai panggilan bisa sebagai berikut:
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)
Penerapan sys_clone()
khusus untuk arsitektur, tetapi sebagian besar pekerjaan terjadi di do_fork()
didefinisikan dalam kernel/fork.c
. Fungsi ini memanggil clone_process()
statis , yang membuat proses baru sebagai salinan induknya, tetapi belum memulainya. clone_process()
menyalin register, menugaskan PID ke tugas baru, dan menggandakan atau membagikan bagian yang sesuai dari lingkungan proses seperti yang ditentukan oleh klon flags
. Ketika clone_process()
kembali, do_clone()
akan membangunkan proses yang baru dibuat dan menjadwalkannya untuk dijalankan.
Komponen yang bertanggung jawab untuk menerjemahkan fungsi panggilan sistem pengguna ke panggilan sistem kernel di Linux adalah libc. Di GLibC, perpustakaan NPTL mengalihkan ini ke clone(2)
panggilan sistem.