mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-11 11:44:03 +02:00
Merge branch 'gmain-tsan' into 'master'
gmain: Fix data races in GUnixSignalWatchSource and GChildWatchSource See merge request GNOME/glib!446
This commit is contained in:
34
glib/gmain.c
34
glib/gmain.c
@@ -327,7 +327,7 @@ struct _GChildWatchSource
|
|||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
GPollFD poll;
|
GPollFD poll;
|
||||||
#else /* G_OS_WIN32 */
|
#else /* G_OS_WIN32 */
|
||||||
gboolean child_exited;
|
gboolean child_exited; /* (atomic) */
|
||||||
#endif /* G_OS_WIN32 */
|
#endif /* G_OS_WIN32 */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ struct _GUnixSignalWatchSource
|
|||||||
{
|
{
|
||||||
GSource source;
|
GSource source;
|
||||||
int signum;
|
int signum;
|
||||||
gboolean pending;
|
gboolean pending; /* (atomic) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GPollRec
|
struct _GPollRec
|
||||||
@@ -462,10 +462,10 @@ static volatile sig_atomic_t any_unix_signal_pending;
|
|||||||
static volatile int unix_signal_pending[NSIG];
|
static volatile int unix_signal_pending[NSIG];
|
||||||
static volatile int any_unix_signal_pending;
|
static volatile int any_unix_signal_pending;
|
||||||
#endif
|
#endif
|
||||||
static volatile guint unix_signal_refcount[NSIG];
|
|
||||||
|
|
||||||
/* Guards all the data below */
|
/* Guards all the data below */
|
||||||
G_LOCK_DEFINE_STATIC (unix_signal_lock);
|
G_LOCK_DEFINE_STATIC (unix_signal_lock);
|
||||||
|
static guint unix_signal_refcount[NSIG];
|
||||||
static GSList *unix_signal_watches;
|
static GSList *unix_signal_watches;
|
||||||
static GSList *unix_child_watches;
|
static GSList *unix_child_watches;
|
||||||
|
|
||||||
@@ -5107,7 +5107,7 @@ dispatch_unix_signals_unlocked (void)
|
|||||||
{
|
{
|
||||||
GChildWatchSource *source = node->data;
|
GChildWatchSource *source = node->data;
|
||||||
|
|
||||||
if (!source->child_exited)
|
if (!g_atomic_int_get (&source->child_exited))
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
do
|
do
|
||||||
@@ -5117,14 +5117,14 @@ dispatch_unix_signals_unlocked (void)
|
|||||||
pid = waitpid (source->pid, &source->child_status, WNOHANG);
|
pid = waitpid (source->pid, &source->child_status, WNOHANG);
|
||||||
if (pid > 0)
|
if (pid > 0)
|
||||||
{
|
{
|
||||||
source->child_exited = TRUE;
|
g_atomic_int_set (&source->child_exited, TRUE);
|
||||||
wake_source ((GSource *) source);
|
wake_source ((GSource *) source);
|
||||||
}
|
}
|
||||||
else if (pid == -1 && errno == ECHILD)
|
else if (pid == -1 && errno == ECHILD)
|
||||||
{
|
{
|
||||||
g_warning ("GChildWatchSource: Exit status of a child process was requested but ECHILD was received by waitpid(). See the documentation of g_child_watch_source_new() for possible causes.");
|
g_warning ("GChildWatchSource: Exit status of a child process was requested but ECHILD was received by waitpid(). See the documentation of g_child_watch_source_new() for possible causes.");
|
||||||
source->child_exited = TRUE;
|
|
||||||
source->child_status = 0;
|
source->child_status = 0;
|
||||||
|
g_atomic_int_set (&source->child_exited, TRUE);
|
||||||
wake_source ((GSource *) source);
|
wake_source ((GSource *) source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5138,14 +5138,10 @@ dispatch_unix_signals_unlocked (void)
|
|||||||
{
|
{
|
||||||
GUnixSignalWatchSource *source = node->data;
|
GUnixSignalWatchSource *source = node->data;
|
||||||
|
|
||||||
if (!source->pending)
|
if (pending[source->signum] &&
|
||||||
|
g_atomic_int_compare_and_exchange (&source->pending, FALSE, TRUE))
|
||||||
{
|
{
|
||||||
if (pending[source->signum])
|
wake_source ((GSource *) source);
|
||||||
{
|
|
||||||
source->pending = TRUE;
|
|
||||||
|
|
||||||
wake_source ((GSource *) source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5167,7 +5163,7 @@ g_child_watch_prepare (GSource *source,
|
|||||||
|
|
||||||
child_watch_source = (GChildWatchSource *) source;
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
return child_watch_source->child_exited;
|
return g_atomic_int_get (&child_watch_source->child_exited);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -5177,7 +5173,7 @@ g_child_watch_check (GSource *source)
|
|||||||
|
|
||||||
child_watch_source = (GChildWatchSource *) source;
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
return child_watch_source->child_exited;
|
return g_atomic_int_get (&child_watch_source->child_exited);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -5188,7 +5184,7 @@ g_unix_signal_watch_prepare (GSource *source,
|
|||||||
|
|
||||||
unix_signal_source = (GUnixSignalWatchSource *) source;
|
unix_signal_source = (GUnixSignalWatchSource *) source;
|
||||||
|
|
||||||
return unix_signal_source->pending;
|
return g_atomic_int_get (&unix_signal_source->pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -5198,7 +5194,7 @@ g_unix_signal_watch_check (GSource *source)
|
|||||||
|
|
||||||
unix_signal_source = (GUnixSignalWatchSource *) source;
|
unix_signal_source = (GUnixSignalWatchSource *) source;
|
||||||
|
|
||||||
return unix_signal_source->pending;
|
return g_atomic_int_get (&unix_signal_source->pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -5218,9 +5214,9 @@ g_unix_signal_watch_dispatch (GSource *source,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
again = (callback) (user_data);
|
g_atomic_int_set (&unix_signal_source->pending, FALSE);
|
||||||
|
|
||||||
unix_signal_source->pending = FALSE;
|
again = (callback) (user_data);
|
||||||
|
|
||||||
return again;
|
return again;
|
||||||
}
|
}
|
||||||
|
@@ -245,6 +245,56 @@ test_sighup_nested (void)
|
|||||||
g_main_loop_unref (mainloop);
|
g_main_loop_unref (mainloop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_sigwinch_received (gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *loop = (GMainLoop *) data;
|
||||||
|
|
||||||
|
sig_counter ++;
|
||||||
|
|
||||||
|
if (sig_counter == 1)
|
||||||
|
kill (getpid (), SIGWINCH);
|
||||||
|
else if (sig_counter == 2)
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
else if (sig_counter > 2)
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
|
/* Increase the time window in which an issue could happen. */
|
||||||
|
g_usleep (G_USEC_PER_SEC);
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_callback_after_signal (void)
|
||||||
|
{
|
||||||
|
/* Checks that user signal callback is invoked *after* receiving a signal.
|
||||||
|
* In other words a new signal is never merged with the one being currently
|
||||||
|
* dispatched or whose dispatch had already finished. */
|
||||||
|
|
||||||
|
GMainLoop *mainloop;
|
||||||
|
GMainContext *context;
|
||||||
|
GSource *source;
|
||||||
|
|
||||||
|
sig_counter = 0;
|
||||||
|
|
||||||
|
context = g_main_context_new ();
|
||||||
|
mainloop = g_main_loop_new (context, FALSE);
|
||||||
|
|
||||||
|
source = g_unix_signal_source_new (SIGWINCH);
|
||||||
|
g_source_set_callback (source, on_sigwinch_received, mainloop, NULL);
|
||||||
|
g_source_attach (source, context);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
g_assert_cmpint (sig_counter, ==, 0);
|
||||||
|
kill (getpid (), SIGWINCH);
|
||||||
|
g_main_loop_run (mainloop);
|
||||||
|
g_assert_cmpint (sig_counter, ==, 2);
|
||||||
|
|
||||||
|
g_main_loop_unref (mainloop);
|
||||||
|
g_main_context_unref (context);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@@ -259,6 +309,7 @@ main (int argc,
|
|||||||
g_test_add_func ("/glib-unix/sighup_again", test_sighup);
|
g_test_add_func ("/glib-unix/sighup_again", test_sighup);
|
||||||
g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
|
g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
|
||||||
g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
|
g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
|
||||||
|
g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user