File mana di kernel yang menentukan fork (), vfork () ... untuk menggunakan sys_clone () system call

9

Ketika ltrace digunakan untuk melacak panggilan sistem, saya bisa melihat bahwa fork () menggunakan sys_clone () daripada sys_fork (). Tapi saya tidak bisa menemukan sumber linux di mana ia didefinisikan.

Program saya adalah

#include<stdio.h>
main()
{
        int pid,i=0,j=0;
        pid=fork();
        if(pid==0)
                printf("\nI am child\n");
        else
                printf("\nI am parent\n");

}

Dan output ltrace adalah

SYS_brk(NULL)                                                                               = 0x019d0000
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_mmap(0, 8192, 3, 34, 0xffffffff)                                                        = 0x7fe3cf84f000
SYS_access("/etc/ld.so.preload", 04)                                                        = -2
SYS_open("/etc/ld.so.cache", 0, 01)                                                         = 3
SYS_fstat(3, 0x7fff47007890)                                                                = 0
SYS_mmap(0, 103967, 1, 2, 3)                                                                = 0x7fe3cf835000
SYS_close(3)                                                                                = 0
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_open("/lib/x86_64-linux-gnu/libc.so.6", 0, 00)                                          = 3
SYS_read(3, "\177ELF\002\001\001", 832)                                                     = 832
SYS_fstat(3, 0x7fff470078e0)                                                                = 0
SYS_mmap(0, 0x389858, 5, 2050, 3)                                                           = 0x7fe3cf2a8000
SYS_mprotect(0x7fe3cf428000, 2097152, 0)                                                    = 0
SYS_mmap(0x7fe3cf628000, 20480, 3, 2066, 3)                                                 = 0x7fe3cf628000
SYS_mmap(0x7fe3cf62d000, 18520, 3, 50, 0xffffffff)                                          = 0x7fe3cf62d000
SYS_close(3)                                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf834000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf833000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf832000
SYS_arch_prctl(4098, 0x7fe3cf833700, 0x7fe3cf832000, 34, 0xffffffff)                        = 0
SYS_mprotect(0x7fe3cf628000, 16384, 1)                                                      = 0
SYS_mprotect(0x7fe3cf851000, 4096, 1)                                                       = 0
SYS_munmap(0x7fe3cf835000, 103967)                                                          = 0
__libc_start_main(0x40054c, 1, 0x7fff47008298, 0x4005a0, 0x400590 <unfinished ...>
fork( <unfinished ...>
SYS_clone(0x1200011, 0, 0, 0x7fe3cf8339d0, 0)                                               = 5967
<... fork resumed> )                                                                        = 5967
puts("\nI am parent" <unfinished ...>
SYS_fstat(1, 0x7fff47008060)                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff
)                                                        = 0x7fe3cf84e000
I am child
SYS_write(1, "\n", 1
)                                                                       = 1
SYS_write(1, "I am parent\n", 12)                                                           = -512
--- SIGCHLD (Child exited) ---
SYS_write(1, "I am parent\n", 12I am parent
)                                                           = 12
<... puts resumed> )                                                                        = 13
SYS_exit_group(13 <no return ...>
+++ exited (status 13) +++
user3539
sumber
Ini mungkin bermanfaat bagi Anda: lxr.linux.no/linux+v3.10.9
ulangan
@ mauro.stettler Saya tidak bisa menemukannya di lxr
user3539
Apakah maksud Anda git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… sekitar baris 1700? Apa yang ingin kamu ketahui?
msw

Jawaban:

29

The fork()dan vfork()pembungkus di glibc dilaksanakan melalui clone()system call. Untuk lebih memahami hubungan antara fork()dan clone(), kita harus mempertimbangkan hubungan antara proses dan utas di Linux.

Secara tradisional, fork()akan mempublikasikan semua sumber daya yang dimiliki oleh proses induk dan menetapkan salinan untuk proses anak. Pendekatan ini menimbulkan biaya overhead yang besar, yang semuanya mungkin sia-sia jika anak itu segera menelepon exec(). Di Linux, fork()menggunakan halaman copy-on-write untuk menunda atau sama sekali menghindari menyalin data yang dapat dibagi antara proses induk dan anak. Dengan demikian, satu-satunya overhead yang dikeluarkan selama normal fork()adalah menyalin tabel halaman induk dan penugasan struct deskriptor proses yang unik task_struct,, untuk anak.

Linux juga mengambil pendekatan yang luar biasa untuk utas. Di Linux, utas hanyalah proses biasa yang berbagi sumber daya dengan proses lain. Ini adalah pendekatan yang sangat berbeda untuk utas dibandingkan dengan sistem operasi lain seperti Windows atau Solaris, di mana proses dan utas adalah jenis binatang yang sama sekali berbeda. Di Linux, setiap utas memiliki kebiasaan task_structsendiri yang kebetulan diatur sedemikian rupa sehingga berbagi sumber daya tertentu, seperti ruang alamat, dengan proses induk.

The flagsparameter clone()system call mencakup seperangkat bendera yang menunjukkan mana sumber daya, jika ada, proses orangtua dan anak harus berbagi. Proses dan utas sama-sama dibuat melalui clone(), satu-satunya perbedaan adalah set bendera yang diteruskan ke clone().

Normal fork()dapat diimplementasikan sebagai:

clone(SIGCHLD, 0);

Ini menciptakan tugas yang tidak membagikan sumber daya apa pun dengan induknya, dan diatur untuk mengirim SIGCHLDsinyal terminasi ke induk ketika ia keluar.

Sebaliknya, tugas yang berbagi ruang alamat, sumber daya sistem file, deskriptor file dan penangan sinyal dengan induknya, dengan kata lain utas , dapat dibuat dengan:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

vfork()pada gilirannya diimplementasikan melalui CLONE_VFORKbendera terpisah , yang akan menyebabkan proses induk tidur sampai proses anak membangunkannya melalui sinyal. Anak akan menjadi satu-satunya utas eksekusi di ruang nama orang tua, sampai panggilan exec()atau keluar. Anak tidak diperbolehkan menulis ke memori. clone()Panggilan yang sesuai bisa sebagai berikut:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

Implementasi sys_clone()adalah arsitektur spesifik, tetapi sebagian besar pekerjaan terjadi di do_fork()didefinisikan dalam kernel/fork.c. Fungsi ini memanggil statis clone_process(), yang menciptakan proses baru sebagai salinan dari induknya, tetapi belum memulainya. clone_process()menyalin register, menetapkan PID untuk tugas baru, dan baik mempublikasikan atau berbagi 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 berjalan.

Thomas Nyman
sumber
2
+1 Penjelasan yang bagus tentang pentingnya clone()kaitan dengan utas dan garpu.
goldilocks
1
Menghapus semua keraguan saya
user3539
2

Komponen yang bertanggung jawab untuk menerjemahkan fungsi-fungsi panggilan sistemlandland menjadi panggilan sistem kernel di Linux adalah libc. Dalam GLibC, perpustakaan NPTL mengarahkan ini ke clone(2)panggilan sistem.

Ignacio Vazquez-Abrams
sumber