Как выходит поток в NPTL? - PullRequest
2 голосов
/ 26 мая 2020

Мне любопытно, как выходит один поток NPTL с точки зрения реализации.

Что я понимаю о реализации glib c -2.30 :

  1. Поток NPTL построен поверх облегченного процесса на Linux, с дополнительной информацией, хранящейся в объекте pthread в пользовательском стеке, для отслеживания специфической c информации NPTL, такой как статус соединения / отсоединения и возвращаемый указатель объекта .
  2. когда поток NPTL завершается, он исчезает навсегда, остается только объект пользовательского стека (и, следовательно,) pthread, который нужно собрать (чтобы присоединить другие потоки), если только он не отсоединен, в этом случае это пространство освобождается напрямую.
  3. _exit() syscall уничтожает все потоки в группе потоков.
  4. пользовательская функция, которую принимает pthread_create(), на самом деле заключена в другую функцию start_thread(), которая выполняет некоторую подготовку перед запуском пользовательской функции и некоторую очистку после этого.

Вопросы:

  1. В конце функции-оболочки start_thread() есть следующий комментарий и код:

    /* We cannot call '_exit' here.  '_exit' will terminate the process.
    
     The 'exit' implementation in the kernel will signal when the
     process is really dead since 'clone' got passed the CLONE_CHILD_CLEARTID
     flag.  The 'tid' field in the TCB will be set to zero.
    
     The exit code is zero since in case all threads exit by calling
     'pthread_exit' the exit status must be 0 (zero).  */
     __exit_thread ();
    

    но __exit_thread(), похоже, подходит syscall _exit() в любом случае:

     static inline void __attribute__ ((noreturn, always_inline, unused))
     __exit_thread (void)
     {
       /* some comments here */
       while (1)
         {
           INTERNAL_SYSCALL_DECL (err);
           INTERNAL_SYSCALL (exit, err, 1, 0);
         }
     }
    

    поэтому я запутался здесь, так как он действительно не должен выполнять syscall _exit(), потому что он завершает все потоки.

  2. pthread_exit() должен завершать один поток, поэтому он должен делать что-то похожее на то, что делает оболочка start_thread() в конце, однако он вызывает __do_cancel(), и TBH Я потерялся в отслеживании этой функции. Похоже, это не связано с указанным выше __exit_thread() и не вызывает _exit().

1 Ответ

2 голосов
/ 27 мая 2020

Я запутался здесь, так как он действительно не должен выполнять syscall _exit ()

Путаница здесь возникает из-за смешивания системного вызова exit с _exit lib c подпрограмма (системный вызов _exit для Linux отсутствует).

Первый завершает текущий Linux поток (как задумано).

Второй (сбивает с толку) не выполнить системный вызов exit. Скорее, он выполняет системный вызов exit_group, который завершает все потоков.

thread_exit () должен завершать один поток

Это делает, косвенно. Он раскручивает текущий стек (аналог siglongjmp), выполняя передачу управления в точку, где был установлен cleanup_jmp_buf. И это было в start_thread.

После передачи управления start_thread очищает ресурсы и вызывает __exit_thread для фактического завершения потока.

...