Código fonte do kernel: O que são parent_tidptr e child_tidptr em do_fork()?

Código fonte do kernel: O que são parent_tidptr e child_tidptr em do_fork()?

Acimalinko que significa parent_tidptre child_tidptrsobre do_fork()qual cria um novo processo?

Responder1

Vamos começar examinando a interface bruta de chamada do sistema. Varia um pouco de acordo com a arquitetura, mas no x86-64 é:

   long clone(unsigned long flags, void *child_stack,
              int *ptid, int *ctid,
              unsigned long newtls);

ptide ctidsão seus parent_tidptre child_tidptr. Agora vamos ver o queclone(2)página de manual tem a dizer:

   CLONE_CHILD_CLEARTID (since Linux 2.5.49)
          Erase  the  child  thread  ID  at the location ctid in
          child memory when the child exits, and do a wakeup  on
          the  futex  at that address.

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

   CLONE_PARENT_SETTID (since Linux 2.5.49)
          Store  the child thread ID at the location ptid in the
          parent's memory. 

Esses sinalizadores foram projetados principalmente para implementar bibliotecas de threading. Se dermos uma olhada na implementação do NPTLpthread_create()dentro da glibc, eventualmente encontramos código emsysdeps/unix/sysv/linux/createthread.cque faz uma clone()chamada que inclui CLONE_PARENT_SETTIDe CLONE_CHILD_CLEARTIDem flags.

Nessa clone()chamada, também podemos ver que os argumentos ptidectidapontar para o mesmo endereço. (Lembre-se de que threads POSIX compartilham um espaço de endereço; isso é feito com o clone() CLONE_VMsinalizador.)

Então, o que está acontecendo aqui é o seguinte.

  • CLONE_PARENT_SETTIDestá sendo usado para garantir que o ID do thread do kernel esteja sendo armazenado em um determinado local no espaço do usuário. O lado do espaço do usuário da implementação do threading precisa saber esse ID do thread.
  • CLONE_CHILD_CLEARTIDestá sendo usado para limpar (ou seja, zero) o mesmo local quando o thread criado por clone()termina.

Vamos um pouco mais longe...

O ID do thread retornado via ptid/ ctidénãoo mesmo que um ID de thread POSIX ( pthread_t), embora nas implementações de threading 1:1, como NPTL, haja uma correspondência um-para-um entre os IDs de thread do kernel e os IDs de thread POSIX. O ID do thread do kernel é o mesmo ID que você obtém usando o Linuxgettid()chamar. Também é retornado clone()como o valor de retorno da chamada do sistema, o que levanta a questão: por que precisamos de ptid/ ctid? O problema é que do lado do espaço do usuário, as coisas são assim:

tid = clone(...);

Do ponto de vista da implementação de threading no espaço do usuário, há uma corrida aqui, porque a atribuição tidocorre apenasdepois clone()retorna. Isso significa que a biblioteca de threading do espaço do usuário pode ter certos problemas se desejar essas informações antes que o novo thread faça qualquer coisa (como encerrar, por exemplo). O uso CLONE_PARENT_SETTIDgarante que o novo ID do thread seja colocado no local apontado porptid antes clone()retorna e, portanto, permite que uma biblioteca de threading evite tais condições de corrida. ( CLONE_CHILD_SETTIDtambém pode ser usado com efeito semelhante.)

A razão CLONE_CHILD_CLEARTIDusada para limpar o ptid/ ctidé fornecer uma maneira para umpthread_join()chame outro thread para descobrir que o thread foi encerrado. Em essência, o local ptid/ ctidestá sendo usado como umfutex, e afutex()a chamada do sistema é usada para bloquear, aguardando a mudança do número inteiro neste local. (Os detalhes são um pouco complicados, mas greppara usos de lll_wait_tide lll_futex_waitno código-fonte da glibc. Em última análise, há uma FUTEX_WAIToperação em andamento. Lembre-se acima que CLONE_CHILD_CLEARTIDfaz uma ativação futex no endereço de destino.)

Responder2

tidsignifica "ID do tópico". Os parâmetros parent_tidptre child_tidptrapontam para a memória do espaço do usuário no espaço de endereço do processo pai e no espaço de endereço do processo filho, respectivamente. O id do thread recém-criado é armazenado nas variáveis ​​int para as quais os ponteiros apontam.

Para obter mais informações, consulte oclone(2)página de manual.

informação relacionada