mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 19:36:18 +01:00
gmain: Guarantee handler dispatch after receiving UNIX signal
Guarantee that user signal callback is dispatched _after_ receiving a signal as long as the handler expresses continued interest in receiving such a notification. Previously if a signal has been received during user callback dispatch but before pending flag had been cleared then the signal would be irrevocably lost. This is a very useful guarantee to have in cases where signals are used to signify a need for synchronization with external resources. For example: reloading configuration file after SIGUSR1 or retrieving a terminal size after SIGWINCH.
This commit is contained in:
parent
9e652f94d2
commit
969b0e00b3
@ -5214,10 +5214,10 @@ g_unix_signal_watch_dispatch (GSource *source,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
again = (callback) (user_data);
|
|
||||||
|
|
||||||
g_atomic_int_set (&unix_signal_source->pending, FALSE);
|
g_atomic_int_set (&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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user