[zeromq-dev] Poll on sockets OR child process
mail17 at mah.priv.at
Thu Nov 28 08:30:07 CET 2013
Am 28.11.2013 um 01:58 schrieb Greg Ward <greg at gerg.ca>:
> On 27 November 2013, Michael Haberler said:
>>> Is there any sane way to do this? (The whole system is written in
>>> Python, using zeromq-3.2.3 and pyzmq 13.1.0.)
>> maybe you'd want to use SIGCHLD
> Hey, 20 years with Unix and I'm still looking for an excuse to use
> SIGCHLD. (So far I've always been happy with waitpid() and friends.)
> You might have just found it for me -- thanks!
>> and poll on a signalfd
> Hmmm, I had not heard of that. Sounds interesting. Downsides: it's
> Linux-specific, and AFAICT is not exposed via the Python std library.
> (There's a binding here: https://launchpad.net/python-signalfd.)
> My initial inclination is to handle SIGCHLD and ... ummm ... then
> what? Say my code looks like this:
> def handle_sigchld(sig, frame):
> print('child terminated')
> [...now what?]
> def mainloop():
> [install handle_sigchld() for SIGCHLD]
> while True:
> sockets = poller.poll(timeout)
> [recv() messages, do stuff in response, send() replies, etc.]
the most important step to understand signalfd is: put the notion of a 'signal handler' to rest. You do not need it anymore.
so you dont 'handle the child signal', you just read signalfd once it's readable - it's all inline synchronous delivery like any other I/O event, not a glorified interrupt handler with shady semantics and 237 variations of a fundamentally broken API. For each pending signal registered with the signalfd, the kernel will queue a descriptor on the signalfd and make that fd readable, and you handle it when you get around to it, not when the next system call happens to return. So you gain full control over when the signal is 'handled'.
in zeroMQ terms, you would handle the signalfd like another normal Unix file descriptor with a pollitem, and trigger on POLL_IN (see man 2 signalfd)
I only have a C example but I think transliterating to Python should be easy provided you have the signalfd() call wrapped:
for setting up signalfd, see: http://git.mah.priv.at/gitweb?p=emc2-dev.git;a=blob;f=src/hal/halreport/halreport.c;h=7856fadb92d4e2894be4e8150d67608493fc5062;hb=refs/heads/hal-namespace-investigation#l1021
setting up the poller is stock (931, 945):
in the read callback you just read the struct signalfd_siginfo from the signal fd which will give you pid, exit status etc:
btw a similarily useful vehicle for notification user/user but also for kernel/user is eventfd(2); libzmq uses it too, see libzmq/src/signaler.cpp. The key difference to signalfd is that eventfd is signalled by POLL_ERR so you might have to set the relaxed socket option so the poller item isnt removed, which would be default semantics for POLL_ERR. This would give you the ability to watch sysfs entries changing, for instance. Very powerful but using POLL_ERR requires careful coding (as I found out empirically ;).
maybe the eventfd and signalfd calls might make sense as additional pyczmq wrappings to get rid of esoteric python module dependencies.
> Presumably that SIGCHLD will arrive while my mainloop() is inside
> poller.poll(), which boils down to 0MQ being in a poll() system call.
> So I'm guessing that poll() call will be interrupted, and my main loop
> will be back in control. I guess the thing to do is set a "some child
> terminated" flag in handle_sigchld(), and then check that flag when
> poll() exits. That should let me get the results of the child process
> back to the master process with minimal latency.
> Unless, of course, 0MQ does clever stuff with signals and/or
> interrupted system calls. I'm going to give this a shot and see what
> zeromq-dev mailing list
> zeromq-dev at lists.zeromq.org
More information about the zeromq-dev