%3F.png)
Acimalinko que significa parent_tidptr
e child_tidptr
sobre 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);
ptid
e ctid
são seus parent_tidptr
e 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.c
que faz uma clone()
chamada que inclui CLONE_PARENT_SETTID
e CLONE_CHILD_CLEARTID
em flags
.
Nessa clone()
chamada, também podemos ver que os argumentos ptid
ectid
apontar para o mesmo endereço. (Lembre-se de que threads POSIX compartilham um espaço de endereço; isso é feito com o clone()
CLONE_VM
sinalizador.)
Então, o que está acontecendo aqui é o seguinte.
CLONE_PARENT_SETTID
está 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_CLEARTID
está sendo usado para limpar (ou seja, zero) o mesmo local quando o thread criado porclone()
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 tid
ocorre 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_SETTID
garante 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_SETTID
também pode ser usado com efeito semelhante.)
A razão CLONE_CHILD_CLEARTID
usada 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
/ ctid
está 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 grep
para usos de lll_wait_tid
e lll_futex_wait
no código-fonte da glibc. Em última análise, há uma FUTEX_WAIT
operação em andamento. Lembre-se acima que CLONE_CHILD_CLEARTID
faz uma ativação futex no endereço de destino.)
Responder2
tid
significa "ID do tópico". Os parâmetros parent_tidptr
e child_tidptr
apontam 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.