[libdispatch-dev] libdispatch threads, blocked SIGINT and child process

Thomas Clement tclement at intego.com
Fri Dec 3 00:59:09 PST 2010


On 3 déc. 2010, at 09:41, Daniel A. Steffen wrote:

> Thomas,
> 
> On Dec 3, 2010, at 12:00 AM, Thomas Clement wrote:
> 
>> HI have encountered a strange behavior when using libdispatch (OS X 10.6.5). I'm not sure if there is a bug in libdispatch or else what the correct fix is for me.
>> I found myself in the situation of doing a fork/exec/waitpid from a libdispatch thread, the child process waiting for user input, then doing ctrl-c in my Terminal window. I would expect the child process to also be terminated, however the child process is still running, consuming lots of cpu (and its ppid is now 1 which is weird).
> 
> The reason for the cpu-consuming behavior is that the child process main thread inherits the signal mask of the parent process thread that calls fork().
> As that thread is a libdispatch thread it has SIGINT masked by default, so you end up with a single-threaded child process with SIGINT masked. This means that the kernel cannot find an unmasked thread in that process to deliver the signal on when the Terminal shell sends it. As the kernel continuously retries to deliver the signal, this results in the increased cpu consumption you observed.
> 
>> I have noticed that libdispatch calls pthread_sigmask() when creating new threads blocking many signals.
> 
> In fact it does not, the code in question is only used on platforms without workqueue support.
> However on Mac OS X the kernel does indeed mask a similar set of signals on the workqueue threads it creates on behalf of libdispatch.
> 
>> I have found that calling pthread_sigmask() in my dispatch_asynced code to unblock the SIGINT signal fixes the issue (the child process is also terminated when doing a ctrl-c in my Terminal window).
> 
> This is the correct action to take, you must not make any assumptions about the signal mask of libdispatch worker threads, so if you need a specific signal mask to be in place like in this case, your workitem must set it up with pthread_sigmask(), and restore it to the original value before returning.
> 
> This is documented in dispatch_queue_create(3): 
> 
>     Applications MAY call the following interfaces from a block submitted to a dispatch queue if and only
>     if they restore the thread to its original state before returning:
> 
>           o   pthread_setcancelstate()
>           o   pthread_setcanceltype()
>           o   pthread_setschedparam()
>           o   pthread_sigmask()
>           o   pthread_setugid_np()
>           o   pthread_chdir()
>           o   pthread_fchdir()
> 
> Daniel

Thanks Daniel, that totally answered my interrogations :)

Regards,
Thomas



More information about the libdispatch-dev mailing list