[libdispatch-dev] What's with this sigsuspend stuff?
zarzycki at apple.com
Mon Jul 4 16:34:33 PDT 2011
On Jul 4, 2011, at 3:35 PM, DrPizza wrote:
>> To dequeue pending signals installed via signal()/sigaction() that would
>> otherwise be blocked in a pure GCD app. This is because GCD threads block all
>> maskable signals (see _dispatch_worker_thread() in the same file).
> It only blocks maskable signals when using raw pthreads. The pthread_workqueue implementation calls _dispatch_worker_thread2() , and that function doesn't touch the signal masks. Do pthread_workqueue threads block signals automatically?
Yes. That helps us avoid two system calls per callback from the pthread_workqueue.
> And if the intent of _dispatch_pthread_sigmask() is to block maskable signals, instead of masking one by one, shouldn't it just be using sigfillset()?
I'm not sure I understand the question.
In any case, it probably doesn't matter for two reasons. First, _dispatch_pthread_sigmask() is a static C function, simple, and only used once. It is a great candidate for inlining, and in fact is inlined. The second reason is that the sig*set() APIs on Mac OS X and iOS are C macros that often compile completely away when optimizations are enabled.
>> behavior helps all code that uses GCD avoid spurious EINTR errors from Unix
>> system calls (which are often not tested for).
> So, the (special, undocumented?) behaviour here is that if the program is determined to be "callback driven" (explicit call to dispatch_main(), or implicit use of Cocoa) then one victim workqueue thread will clear its mask and handle any signal, so that, if all other threads mask their signals, this victim thread will handle any and every signal. The value of this being that if you follow the (unwritten?) rules and mask signals from every other thread, you shouldn't then receive EINTR because you'll never have to worry about a signal being delivered to a regular thread?
In general, the intersection of different subsystems always creates undefined/undocumented behavior/assumptions. The relationship between libdispatch, POSIX, the Mac OS X kernel, and apps in general is no different.
In practice, what we found was that programs that installed signal handlers via signal()/sigaction() often made the assumption that there will always be a thread available to handle the signal. In other words, deferring traditional Unix signal handlers until a worker thread was idle could cause apps to hang. That is why GCD keeps a dedicated signal handling thread running. However, we cannot blindly create this helper thread when libdispatch is initialized because other programs [dubiously] assume that libraries do not leave lingering helper threads. Therefore, GCD only creates the helper thread if the main thread exits (because the main thread doesn't start out with any masked signals – technically it could, but in practice it doesn't happen.)
> OK, so nothing Windows has to worry about then.
I don't know how Windows supports POSIX, but that sounds reasonable.
More information about the libdispatch-dev