Charles-François Natali <neolo...@free.fr> added the comment:
>> I just noticed something "funny": signal_sigwait doesn't release
>> the GIL, which means that it's pretty much useless :-)
>
> sigwait() is not useless: the signal is not necessary send by another thread.
> The signal can be send by alarm(), from a child process, by an user, by the
> kernel.
>
If it doesn't release the GIL, it is useless.
The common usage pattern for sigwait() is to create a dedicated thread
for signals management. If this thread calls sigwait without releasing
the GIL, the whole process is suspended, which is definitely not what
you want.
>> Also, test_sigwait doesn't block the signal before calling sigwait:
>> it happens to work because there's only one thread, but it's
>> undefined behaviour.
>
> test_sigwait() test pass on all 3.x buildbots (some don't have sigwait(), the
> test is skipped). Sometimes, test_sigwait() is executed with 2 threads, the
> main thread and Tkinter event loop thread, and the signal is not blocked in
> any thread.
>
It's mere luck:
def test_sigwait(self):
old_handler = signal.signal(signal.SIGALRM, self.handler)
self.addCleanup(signal.signal, signal.SIGALRM, old_handler)
signal.alarm(1)
self.assertEqual(signal.sigwait([signal.SIGALRM]), signal.SIGALRM)
Comment out the first two lines that change the signal handler, and
the test will be killed by SIGALRM's default handler ("Alarm clock").
I tested on Linux, and if a the signal isn't blocked before calling sigwait:
- if a custom signal handler is installed, then it is not called
- if the default signal handler is in place, then it's called (and
with SIGALRM the process gets killed)
This is a typical example of what POSIX calls "undefined behavior".
If pthread_sigmask is called before sigwait, then it works as expected.
If we really wanted to test this properly, the way to go would be to
fork() a child process (that way we're sure there's only one thread),
have it block and sigwait() SIGUSR1 without touching the handler, send
it SIGUSR1, and check its return code.
Patch attached.
----------
Added file: http://bugs.python.org/file22312/test_sigwait.diff
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue8407>
_______________________________________
--- cpython-302424b84b07/Lib/test/test_signal.py 2011-06-01
04:39:38.000000000 +0200
+++ cpython/Lib/test/test_signal.py 2011-06-10 10:47:33.521906867 +0200
@@ -601,11 +601,24 @@
@unittest.skipUnless(hasattr(signal, 'sigwait'),
'need signal.sigwait()')
def test_sigwait(self):
- old_handler = signal.signal(signal.SIGALRM, self.handler)
- self.addCleanup(signal.signal, signal.SIGALRM, old_handler)
-
- signal.alarm(1)
- self.assertEqual(signal.sigwait([signal.SIGALRM]), signal.SIGALRM)
+ # sigwait must be called with the signal blocked: since the current
+ # process might have several threads running, we fork() a child process
+ # to have a single thread.
+ signum = signal.SIGUSR1
+ pid = os.fork()
+ if pid == 0:
+ # child: block and wait the signal
+ signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
+ res = signal.sigwait([signum])
+ if res == signum:
+ os._exit(0)
+ os._exit(1)
+ else:
+ # parent: let the child some time to wait, send him the signal, and
+ # check it correcty received it
+ time.sleep(0.5)
+ os.kill(pid, signum)
+ self.assertEqual(os.waitpid(pid, 0), (pid, 0))
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()')
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com