glib-unix: fix handling of multiple signal source for the same signal

We can't reset the pending flag for a signal until we've traversed
the whole list, as the documentation clearly says that in case multiple
sources they all get invoked.
This is still racy if you get a signal after checking the flag
but before resetting it, but it was the same before. The correct
fix would be to use sigwait() or signalfd(), but that would mean
blocking all signals in all threads, which is not compatible
with existing applications.

https://bugzilla.gnome.org/show_bug.cgi?id=704322
This commit is contained in:
Giovanni Campagna
2013-07-16 15:26:02 +02:00
parent 72a7e824d6
commit be2c7b83c4
2 changed files with 71 additions and 5 deletions

View File

@@ -4828,8 +4828,6 @@ dispatch_unix_signals (void)
/* handle GChildWatchSource instances */
if (unix_signal_pending[SIGCHLD])
{
unix_signal_pending[SIGCHLD] = FALSE;
/* The only way we can do this is to scan all of the children.
*
* The docs promise that we will not reap children that we are not
@@ -4875,7 +4873,6 @@ dispatch_unix_signals (void)
{
if (unix_signal_pending[source->signum])
{
unix_signal_pending[source->signum] = FALSE;
source->pending = TRUE;
wake_source ((GSource *) source);
@@ -4883,6 +4880,8 @@ dispatch_unix_signals (void)
}
}
memset ((void*)unix_signal_pending, 0, sizeof (unix_signal_pending));
G_UNLOCK(unix_signal_lock);
}
@@ -4994,7 +4993,6 @@ _g_main_create_unix_signal_watch (int signum)
unix_signal_watches = g_slist_prepend (unix_signal_watches, unix_signal_source);
if (unix_signal_pending[signum])
unix_signal_source->pending = TRUE;
unix_signal_pending[signum] = FALSE;
G_UNLOCK (unix_signal_lock);
return source;