Date: Mon, 04 Mar 2013 11:21:16 +0200 From: Andriy Pylypenko <bamby@sippysoft.com> To: Pavel Perestoronin <eigenein@gmail.com> Cc: freebsd-ports-bugs@freebsd.org Subject: Re: SIgnal delivery to child threads is blocked in Python 2.x Message-ID: <5134678C.10202@sippysoft.com> In-Reply-To: <CANbiqPbKRvNZQnoCKO=De8C03R2Y1YWf-3oofLzwe4LpcSzHrQ@mail.gmail.com> References: <CANbiqPbKRvNZQnoCKO=De8C03R2Y1YWf-3oofLzwe4LpcSzHrQ@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On 01.03.13 16:52, Pavel Perestoronin wrote: > Hello, > > I think there is an issue caused by the following patch: http://svnweb.freebsd.org/ports/head/lang/python27/files/patch-Python_thread__pthread.h?view=log > > The patch ensures a signal is delivered to the main thread always. This makes impossible to send a signal to a child process that is spawned by a child thread. This can be shown on the following script that works differently in FreeBSD and Linux: > [skip] > > There is also the comment to the patch: > >> Make sure the singal is delivered to the main thread, where python > runs its signal handlers, not to a random thread that happens to be > executing at the time when signal arrives. This functionality has been > lost since Python 2.3, possible cause is that the linux implementation > of POSIX threads always delivered signal to the main thread. This > bug results in rather annoying inability to terminate threading script > with ^C for example and there could be other issues as well. > > But on Linux child threads has no signals blocked and according to Linux man signal(7): > >> If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal. > > Anyway, the patch makes Python scripts that use threading work differently in FreeBSD and Linux. Hi Pavel, But yes of course the patch ensures exactly the behaviour you're complaining about. The POSIX does not define which thread the signal should be delivered to. The Linux always delivers signals to the main thread and FreeBSD chooses a random thread and both behaviours are POSIX conforming. However Python 2.x cannot handle signals coming from non-main threads correctly and this is worsened by the fact the Python 2.x does not have signal mask manipulation procedures in standard library. This is why this patch was created. If you want to create a portable and standards conforming code, you can use Python 3. Its standard library supports the pthread_sigmask() & friends and it does not include this patch and never will. Under Python 2.x I would suggest to unblock the signals using the ctypes. Below is your code with an example of such workaround: #!/usr/bin/env python # -*- coding: utf-8 -*- from ctypes import CDLL, Structure, sizeof, c_ulong, pointer from platform import system import threading SIGSET_NWORDS = 1024 / (8 * sizeof(c_ulong)) class SIGSET(Structure): _fields_ = [ ('val', c_ulong * SIGSET_NWORDS) ] if system() == "FreeBSD": libc = CDLL('libc.so') pthread_sigmask = libc.pthread_sigmask SIG_BLOCK = 1 SIG_UNBLOCK = 2 SIG_SETMASK = 3 else: libc = CDLL("libc.so.6") libpthread = CDLL("libpthread.so.0") pthread_sigmask = libpthread.pthread_sigmask SIG_BLOCK = 0 SIG_UNBLOCK = 1 SIG_SETMASK = 2 def test(): sigset = SIGSET() old_sigset = SIGSET() libc.sigemptyset(pointer(sigset)) for i in range(1, 33): libc.sigaddset(pointer(sigset), i) pthread_sigmask(SIG_UNBLOCK, pointer(sigset), pointer(old_sigset)) print "sigblock is " print libc.sigblock(0) # Linux and FreeBSD show 0 here # start new process here pthread_sigmask(SIG_SETMASK, pointer(old_sigset), None) # restore sigmask print "sigblock is " print libc.sigblock(0) # Linux shows 0, while FreeBSD shows 2147417855 if __name__ == "__main__": threading.Thread(target=test).start() Kind regards, Andriy Pylypenko
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5134678C.10202>