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

4

No link acima, o que significa parent_tidptr e child_tidptr em do_fork() , que cria um novo processo?

    
por bawejakunal 03.10.2016 / 17:50

2 respostas

3

tid significa "id de thread". Os parâmetros parent_tidptr e child_tidptr apontam para a memória de 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 segmento recém-criado é armazenado nas variáveis int apontadas pelos ponteiros.

Para mais informações, consulte a clone(2) manpage .

    
por 03.10.2016 / 20:10
1

Vamos começar examinando a interface de chamadas do sistema bruta. Isso varia um pouco pela arquitetura, mas no x86-64 é:

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

ptid e ctid são seus parent_tidptr e child_tidptr . Agora vamos ver o que a clone(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 encadeamento. Se dermos uma olhada na implementação do NPTL de pthread_create() dentro da glibc, eventualmente encontrar código em sysdeps/unix/sysv/linux/createthread.c que faz uma chamada clone() que inclui CLONE_PARENT_SETTID e CLONE_CHILD_CLEARTID em flags .

Na chamada clone() , também podemos ver que os argumentos ptid e ctid apontam para o mesmo endereço . (Lembre-se de que os encadeamentos POSIX compartilham um espaço de endereço; isso é realizado com o sinalizador clone() CLONE_VM .)

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

  • CLONE_PARENT_SETTID está sendo usado para garantir que o ID do encadeamento 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 de segmentação precisa saber esse ID de encadeamento.
  • CLONE_CHILD_CLEARTID está sendo usado para limpar (ou seja, zero) esse mesmo local quando o encadeamento criado por clone() é finalizado.

Vamos um pouco mais longe ...

O ID do encadeamento retornado por meio de ptid / ctid não é igual ao ID de encadeamento POSIX ( pthread_t ), embora nas implementações de encadeamento 1: 1 como NPTL , existe uma correspondência um-para-um entre IDs de encadeamentos do kernel e IDs de encadeamentos POSIX. O ID do encadeamento do kernel é o mesmo ID que você obtém usando a chamada gettid() do Linux . Ele também é retornado por clone() como o valor de retorno da chamada do sistema, que faz a pergunta: 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 da segmentação do espaço do usuário, há uma corrida aqui, porque a designação para tid ocorre apenas após clone() retornos. Isso significa que a biblioteca de encadeamentos do espaço do usuário pode ter alguns problemas se desejar obter essas informações antes que o novo encadeamento faça alguma coisa (como terminar, por exemplo). Usar CLONE_PARENT_SETTID garante que o novo ID de encadeamento seja colocado no local apontado por ptid antes clone() retorna e, assim, permite que uma biblioteca de threads evite essas condições de corrida. ( CLONE_CHILD_SETTID também pode ser usado para efeito semelhante).

O motivo pelo qual CLONE_CHILD_CLEARTID é usado para limpar o ptid / ctid é fornecer uma maneira para um pthread_join() chama em outro thread para descobrir que o segmento foi finalizado. Em essência, a localização ptid / ctid está sendo usada como um futex , e o futex() chamada do sistema é usada para bloquear, esperando que o inteiro neste local seja alterado. (Os detalhes são um pouco confusos, mas grep para usos de lll_wait_tid e lll_futex_wait no código-fonte glibc. Por fim, há uma operação FUTEX_WAIT ocorrendo. Lembre-se acima disso CLONE_CHILD_CLEARTID faz uma ativação de futex no endereço de destino.)

    
por 13.10.2016 / 15:00