[Twisted-Python] signal handlers and threads

Hi.
I have written a small module for sending signals to a "foreign" Python process on Windows 2000/XP.
The trunk is on http://svn.berlios.de/svnroot/repos/pykill32/trunk
In this way I can send KILL, TERM and so, like in a POSIX system.
This works by creating a thread on the remote process (yes, Windows allow this...) and let it call the function "raise" from the MSVCR71 DLL.
This seems to work fine, and now I can stop a Twisted process with kill.py TERM pid (does twistd save the pid in a file on Windows?)
but I'm not sure if signal handlers are thread safe.
Regards Manlio Perillo

On May 12, 2006, at 11:56 AM, Manlio Perillo wrote:
Hi.
I have written a small module for sending signals to a "foreign" Python process on Windows 2000/XP.
The trunk is on http://svn.berlios.de/svnroot/repos/pykill32/trunk
In this way I can send KILL, TERM and so, like in a POSIX system.
This works by creating a thread on the remote process (yes, Windows allow this...) and let it call the function "raise" from the MSVCR71 DLL.
Wow, that is sick! I thought _I_ did weird stuff with signals!
So Windows provides signal(), raise(), and the usual signal numbers, but no kill()? Weird! Does it have pthread_kill()? sigprocmask()? pthread_sigprocmask()? sigaction()? Do the semantics differ from the usual ones?
Interesting when compared to the Cygwin stuff: <http://cygwin.com/cgi- bin/cvsweb.cgi/src/winsup/cygwin/sigproc.cc?cvsroot=src>
This seems to work fine, and now I can stop a Twisted process with kill.py TERM pid (does twistd save the pid in a file on Windows?)
but I'm not sure if signal handlers are thread safe.
In Twisted's case, it sure looks to be. See twisted/internet/base.py:
def sigTerm(self, *args): """Handle a SIGTERM interrupt. """ log.msg("Received SIGTERM, shutting down.") self.callFromThread(self.stop)
Actually, http://docs.python.org/lib/module-signal.html says this:
"Some care must be taken if both signals and threads are used in the same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform signal() operations in the main thread of execution. Any thread can perform an alarm(), getsignal(), or pause(); only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Python signal module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can't be used as a means of inter- thread communication. Use locks instead."
so the self.callFromThread() only matters if the reactor thread is not Python's main thread.
And Python does seem to provide this guarantee even with your thing. See signal_handler in <http://svn.python.org/projects/python/trunk/ Modules/signalmodule.c>. It just sets a flag to be picked up later, and only the main thread does that apparently.
Now, I don't see any guarantee that signals always handled before entering blocking calls, so they can be delayed forever if nothing else wakes it up. (This is like their documented note about long computations but worse.) It does the "normal syscall + flag handler" stuff I describe at http://www.slamb.org/projects/sigsafe/api/. That's a problem with Python's signal handling everywhere, not with your thing or Twisted.
Regards, Scott

Scott Lamb ha scritto:
[...]
This works by creating a thread on the remote process (yes, Windows allow this...) and let it call the function "raise" from the MSVCR71 DLL.
Wow, that is sick! I thought _I_ did weird stuff with signals!
So Windows provides signal(), raise(), and the usual signal numbers, but no kill()?
Yes! http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/... http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/...
Note that it is supported also SIGBREAK (but not documented on msdn).
Weird! Does it have pthread_kill()? sigprocmask()? pthread_sigprocmask()? sigaction()? Do the semantics differ from the usual ones?
No, Windows support signals because they are required by ISO C.
I have found this document: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html...
Interesting when compared to the Cygwin stuff: http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/sigproc.cc?cvsroot=src
Pass.
This seems to work fine, and now I can stop a Twisted process with kill.py TERM pid (does twistd save the pid in a file on Windows?)
but I'm not sure if signal handlers are thread safe.
In Twisted's case, it sure looks to be. See twisted/internet/base.py:
def sigTerm(self, *args): """Handle a SIGTERM interrupt. """ log.msg("Received SIGTERM, shutting down.") self.callFromThread(self.stop)
Ok, fine!
Actually, http://docs.python.org/lib/module-signal.html says this:
"Some care must be taken if both signals and threads are used in the
same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform signal() operations in the main thread of execution. Any thread can perform an alarm(), getsignal(), or pause(); only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Python signal module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can't be used as a means of inter-thread communication. Use locks instead."
I have read this and it seems to allow what I'm doing.
so the self.callFromThread() only matters if the reactor thread is not Python's main thread.
There is someone who run the reactor in a child thread?
And Python does seem to provide this guarantee even with your thing. See signal_handler in http://svn.python.org/projects/python/trunk/Modules/signalmodule.c. It just sets a flag to be picked up later, and only the main thread does that apparently.
Now, I don't see any guarantee that signals always handled before entering blocking calls, so they can be delayed forever if nothing else wakes it up.
But this should not be a problem in Twisted, since there are no blocking calls.
(This is like their documented note about long computations but worse.) It does the "normal syscall + flag handler" stuff I describe at http://www.slamb.org/projects/sigsafe/api/. That's a problem with Python's signal handling everywhere, not with your thing or Twisted.
Well, thanks!
Just to add more informations: when killing a normal Python process with TERM, the Interpreter terminates without calling the functions registered with atexit.
Now this is strange because the MSDN says that, by default, SIGTERM is ignored and the Python documentation says that only an handler for SIGINT is installed.
Regards Manlio Perillo

On May 12, 2006, at 2:30 PM, Manlio Perillo wrote:
Now, I don't see any guarantee that signals always handled before entering blocking calls, so they can be delayed forever if nothing else wakes it up.
But this should not be a problem in Twisted, since there are no blocking calls.
There's one: select().
participants (2)
-
Manlio Perillo
-
Scott Lamb