Em um raspberry pi (um raspian recente), escrevi um aplicativo que, sob demanda por meio de solicitação de rede, gera um aplicativo e, sob demanda, por meio de solicitação de rede diferente, o mata. O mecanismo de desova é apenas fork/exec. Matar é feito com kill(childPid, SIGQUIT). É um simples pedaço de C++ como você pensa e funciona bem.
Ou seja, funciona bem, a menos que eu o inicie em /etc/rc.local. O comando para iniciá-lo a partir daí é apenas um cd apropriado e depois
./effectPlayer &
e ele inicia bem, recebe solicitações bem, gera bem (abrange um aplay, por isso é trivial saber quando funciona), mas falha completamente ao matar o subprocesso aplay a pedido. Ele chama kill() normalmente e kill() retorna 0. Mas aplay continua.
Eu suponho que isso seja alguma estranheza tendo a ver com o fato de que spawná-lo de /etc/rc.local dá a ele algum comportamento especial em fork ou kill, mas não entendo o quê. o que estou perdendo?
Edit: adicionando respostas às perguntas. Execute a partir de /etc/rc.local com o log ativado, o aplicativo relata:
23:10:06 10-11-2019 (effectPlayer) 7: P1 64 elvenHall #command to start playing
23:10:06 10-11-2019 (sound) launched 1083: /usr/bin/aplay -q -... #what it forks/execs
23:10:10 10-11-2019 (effectPlayer) 7: X1000 #command to stop playing
23:10:10 10-11-2019 (sound) sending 3 to 1083, result 0 0 #what kill() is asked to do
Tradução, é solicitado a tocar um efeito específico e gera um aplay para lidar com isso. Funciona (ouço o áudio) e depois mando um comando para parar toda a reprodução. Ele chama kill() com sucesso no PID correto com o sinal correto e kill() retorna 0 com errno=0. Exceto que o aplay ainda está em execução.
Quando faço a mesma sequência na linha de comando, tudo age da mesma forma, exceto que um jogo realmente morre.
Quando troco SIGQUIT por SIGKILL, funciona como esperado: aplay morre independentemente de como o effectsPlayer é iniciado.
Vou atribuir isso a alguma estranheza em uma peça por enquanto. Eu não gosto de usar o SIGKILL - pode haver uma limpeza importante sendo ignorada. Mas funciona...
Pode ser que você tenha herdado uma ignorância do SIGQUIT dos scripts de inicialização, já que fork e exec os deixam em paz. Redefina o SIGQUIT para o estado padrão em seu programa pai para experimentar isso.
É improvável, devido à execução em rc.local, causar isso.
Primeiro, verifique se o pai está realmente enviando o sinal (você pode precisar de algumas linhas de depuração aqui) e se o filho não está sendo morto (execute pgrep aplay, faça o pai matar e depois pgrep aplay novamente). Eu também vou assumir que você não tem nenhum SELINUX ou outra estranheza MAC acontecendo aqui.
Um processo que não responde a kill() se resume a algumas coisas: permissões, manipulação e PID. Parece que você tem um processo pai "effectPlayer" que gera um filho "aplay" e effectPlayer está enviando o sinal QUIT para o filho.
Supondo que você não esteja fazendo nada de estranho com setuid e amigos, tanto o pai quanto o filho teriam o mesmo proprietário, então tudo bem.
O sinal de saída pode ser mascarado, mas tenho certeza que aplay não faria isso. Então essa é uma possibilidade. Você pode alterar SIGQUIT para SIGKILL para ver se isso muda as coisas.
Finalmente o PID. Tem certeza que é o pid certo? Novamente, algumas linhas de depuração informando o PID que você está tentando eliminar e combinando isso com um comando ps testariam isso. Às vezes você pode usar exec em um shell e está matando o processo errado.