0

On a raspberry pi (a recent raspian) I wrote an application that, on demand via network request, spawns an application, and on demand via different network request, kills it. The spawning mechanism is just fork/exec. Killing is done with kill(childPid, SIGQUIT). It's as a simple a piece of C++ as you'd think and it works fine.

That is, it works fine, unless I start it from /etc/rc.local. The command to start it from there is just an appropriate cd and then

    ./effectPlayer &

and it starts up fine, receives requests fine, spawns fine (it spans an aplay, so it's trivial to tell when it works) but completely fails to kill the aplay subprocess on request. It calls kill() as normal and kill() returns 0. But aplay plays on.

I assume this is some weirdness having to do with the fact that spawning it from /etc/rc.local gives it some special behavior in fork or kill, but I don't understand what. What am I missing?

Edit: adding answers to questions. Run from /etc/rc.local with logging turned on, the application reports:

    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

Translation, it's asked to play a particular effect and spawns an aplay to handle it. It works (I hear the audio) and then I send a command to stop all playing. It successfully calls kill() on the right PID with the right signal, and kill() returns 0 with errno=0. Except aplay is still running.

When I do the same sequence from the command line, it all acts the same, except aplay actually dies.

When I swap SIGQUIT for SIGKILL, it works as expected: aplay dies regardless of how effectsPlayer is started.

I'm going to put this down to some weirdness in aplay for now. I don't like using SIGKILL - there might be important clean up being skipped. But it works...

1

It may be that you inherited an ignore of SIGQUIT from the boot scripts, since fork and exec leave these alone. Reset SIGQUIT to the default state in your parent program to try this out.

1
  • SIG_DFL for the win. I'm a little annoyed that didn't occur to me earlier. Thanks. – Scott M Nov 11 '19 at 22:25
0

It's unlikely due to running under rc.local would cause this.

First, check that the parent is actually sending the signal (you might need some debug lines here) and the child is not getting killed (run pgrep aplay, get the parent to kill, then pgrep aplay again). I'm also going to assume you don't have any SELINUX or other MAC oddness going on here.

A process not responding to kill() comes down to a few things: permissions, handling and PID. It sounds like you have a parent process "effectPlayer" which spawns a child "aplay" and effectPlayer is sending signal QUIT to the child.

Assuming you are not doing anything strange with setuid and friends both the parent and child would have the same owner, so this is ok.

The quit signal can be masked, but I'm pretty sure aplay wouldn't do that. So this is a possibility. You could change SIGQUIT to SIGKILL to see if it changes things.

Finally the PID. Are you sure its the right pid? Again some debug lines stating the PID you are trying to kill and matching this with a ps command would test this. Sometimes you might use exec into a shell and you're killing the wrong process.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.