2016-05-11 25 views
6

Trong eglibc của nptl/sysdeps/unix/sysv/linux/i386/fork.c có một định nghĩa:Tại sao sys_fork không được sử dụng bởi việc thực hiện ngã ba của glibc?

#define ARCH_FORK() \ 
    INLINE_SYSCALL (clone, 5,       \ 
      CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,  \ 
      NULL, NULL, &THREAD_SELF->tid) 

được sử dụng trong thực tế __libc_fork() như trung tâm của việc thực hiện. Nhưng ví dụ: trong số arch/x86/entry/syscalls/syscall_32.tbl của Linux tồn tại một mục nhập sys_fork, cũng như trong syscalls_64.tbl. Vì vậy, dường như Linux có syscall đặc biệt của nó cho fork.

Vì vậy, bây giờ tôi tự hỏi: tại sao glibc thực hiện fork() về mặt số clone, nếu hạt nhân đã cung cấp tòa nhà chọc trời fork?

Trả lời

6

Tôi đã xem xét cam kết mà Ulrich Drepper đã thêm mã đó vào glibc và không có bất kỳ lời giải thích nào trong nhật ký cam kết (hoặc ở nơi khác).

Hãy nhìn vào thực hiện fork Linux, mặc dù:

return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0); 

Và đây là clone:

return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls); 

Rõ ràng, họ gần như giống hệt nhau. Sự khác biệt duy nhất là khi gọi clone, bạn có thể đặt các cờ khác nhau, có thể chỉ định kích thước ngăn xếp cho quy trình mới, v.v. fork không nhận bất kỳ đối số nào.

Nhìn vào mã của Drepper, cờ cloneCLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD. Nếu sử dụng fork, cờ duy nhất sẽ là SIGCHLD.

Dưới đây là những gì các clone manpage nói về những lá cờ thêm:

CLONE_CHILD_CLEARTID (since Linux 2.5.49) 
      Erase child thread ID at location ctid in child memory when the child 
      exits, and do a wakeup on the futex at that address. The address 
      involved may be changed by the set_tid_address(2) system call. This is 
      used by threading libraries. 

CLONE_CHILD_SETTID (since Linux 2.5.49) 
      Store child thread ID at location ctid in child memory. 

... Và bạn có thể thấy rằng anh ta vượt qua một con trỏ đến nơi hạt nhân đầu tiên nên lưu trữ thread ID của trẻ và sau đó làm một cuộc đánh thức futex. Glibc có đang chờ đợi futex trên địa chỉ đó ở đâu đó không? Tôi không biết. Nếu vậy, điều đó sẽ giải thích tại sao Drepper lại chọn sử dụng clone.

(Và nếu không, nó sẽ chỉ là một ví dụ nữa về sự tích tụ cực đại của tàu tuần dương là glibc yêu quý của chúng tôi! Nếu bạn muốn tìm một số mã đẹp, sạch, được bảo trì tốt, hãy tiếp tục di chuyển và đi nhìn vào musl libc!)

+1

'pthread_join()' thực hiện việc đánh thức. Tương tự như thế nào, nếu bạn liên kết với các chủ đề, glibc gọi 'set_tid_address()' để chủ đề "chính" có thể được nối: http://stackoverflow.com/questions/6975098/when-is-the-system-call-set -tid-address-used – ninjalj

+0

@usr: quá trình mới có thể sinh ra các luồng. Nếu bạn muốn các luồng đó có thể 'pthread_join()' trên luồng chính của tiến trình mới, glibc cần địa chỉ của futex. – ninjalj

+0

@usr: 'execve()' xử lý điều đó bằng cách gọi 'set_tid_address()'. BTW, nếu bạn ngay lập tức exec, có 'vfork()', hoặc 'posix_spawn()', nếu libc của bạn cung cấp điều đó. – ninjalj

0

Tóm lại: tại sao không?

Bạn có một syscall được đảm bảo tồn tại trên tất cả các nền tảng (bạn nhận ra rằng Intel không phải là nền tảng duy nhất trên mạng, phải không?) Và một phiên bản khác không được chấp nhận vì nó là không cần thiết. Cả hai đều mang cùng ngữ nghĩa chính xác. Mã của bạn nhỏ gọn hơn nhiều khi bạn chỉ gọi một mã được đảm bảo tồn tại.

Tôi sẽ giải thích thêm một chút.

Ngã ba được xác định bởi Posix, trong khi bản sao là Linux cụ thể. Tuy nhiên, Linux, nhân dịp, có Posix định nghĩa "cuộc gọi hệ thống" và thực hiện chúng trong không gian người dùng. Đó là trường hợp cho ngã ba (và vfork và pthread_create). Tất cả chúng đều được thực hiện trong không gian người dùng bằng cách gọi "clone".

Như vậy, ngã ba được coi là không cần thiết ở cấp hạt nhân. Nếu một trình bao bọc không gian người dùng mỏng có thể thực hiện nó, thì hạt nhân sẽ ổn với điều đó. Như vậy, trên Linux, bản sao được đảm bảo tồn tại trên tất cả các nền tảng, trong khi ngã ba có thể hoặc không tồn tại, tùy thuộc vào nền tảng cụ thể.

+0

Tôi tin rằng 'fork (2)' tồn tại trước 'clone (2)'. –

+0

Điều đó vừa chính xác vừa không liên quan. Tôi đã chỉnh sửa câu trả lời để giải thích lý do. –

Các vấn đề liên quan