diff options
author | Dan Winship <danw@gnome.org> | 2013-07-17 18:58:18 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-07-17 21:41:45 -0400 |
commit | 72a7e824d65b725a5f64224ee274fe5e3d7933fc (patch) | |
tree | b7174507fba1d8d3c04ab0a7380949a7db5acb9c | |
parent | d06400cbaf4d3f6741a463668b2c8a56f695d124 (diff) |
gsourceclosure: fix idle/timeout/signal closures, add child watch support
And add a test for all source types.
https://bugzilla.gnome.org/show_bug.cgi?id=704267
-rw-r--r-- | gobject/gsourceclosure.c | 69 | ||||
-rw-r--r-- | gobject/tests/.gitignore | 1 | ||||
-rw-r--r-- | gobject/tests/Makefile.am | 1 | ||||
-rw-r--r-- | gobject/tests/closure.c | 202 |
4 files changed, 270 insertions, 3 deletions
diff --git a/gobject/gsourceclosure.c b/gobject/gsourceclosure.c index 26b89529f..a16b6c55b 100644 --- a/gobject/gsourceclosure.c +++ b/gobject/gsourceclosure.c @@ -51,6 +51,31 @@ g_io_condition_get_type (void) return etype; } +/* We need to hand-write this marshaler, since it doesn't have an + * instance object. + */ +static void +source_closure_marshal_BOOLEAN__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GSourceFunc callback; + GCClosure *cc = (GCClosure*) closure; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 0); + + callback = (GSourceFunc) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (closure->data); + + g_value_set_boolean (return_value, v_return); +} + static gboolean io_watch_closure_callback (GIOChannel *channel, GIOCondition condition, @@ -79,6 +104,35 @@ io_watch_closure_callback (GIOChannel *channel, return result; } +static gboolean +g_child_watch_closure_callback (GPid pid, + gint status, + gpointer data) +{ + GClosure *closure = data; + + GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; + GValue result_value = G_VALUE_INIT; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms[0], G_TYPE_ULONG); + g_value_set_ulong (¶ms[0], pid); + + g_value_init (¶ms[1], G_TYPE_INT); + g_value_set_int (¶ms[1], status); + + g_closure_invoke (closure, &result_value, 2, params, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms[0]); + g_value_unset (¶ms[1]); + + return result; +} + #ifdef G_OS_UNIX static gboolean g_unix_fd_source_closure_callback (int fd, @@ -138,7 +192,9 @@ closure_callback_get (gpointer cb_data, if (!closure_callback) { if (source->source_funcs == &g_io_watch_funcs) - closure_callback = (GSourceFunc)io_watch_closure_callback; + closure_callback = (GSourceFunc)io_watch_closure_callback; + else if (source->source_funcs == &g_child_watch_funcs) + closure_callback = (GSourceFunc)g_child_watch_closure_callback; #ifdef G_OS_UNIX else if (source->source_funcs == &g_unix_fd_source_funcs) closure_callback = (GSourceFunc)g_unix_fd_source_closure_callback; @@ -147,8 +203,8 @@ closure_callback_get (gpointer cb_data, #ifdef G_OS_UNIX source->source_funcs == &g_unix_signal_funcs || #endif - source->source_funcs == &g_idle_funcs) - closure_callback = source_closure_callback; + source->source_funcs == &g_idle_funcs) + closure_callback = source_closure_callback; } *func = closure_callback; @@ -191,6 +247,7 @@ g_source_set_closure (GSource *source, source->source_funcs != &g_unix_fd_source_funcs && source->source_funcs != &g_unix_signal_funcs && #endif + source->source_funcs != &g_child_watch_funcs && source->source_funcs != &g_io_watch_funcs && source->source_funcs != &g_timeout_funcs && source->source_funcs != &g_idle_funcs) @@ -210,6 +267,12 @@ g_source_set_closure (GSource *source, GClosureMarshal marshal = (GClosureMarshal)source->source_funcs->closure_marshal; if (marshal) g_closure_set_marshal (closure, marshal); + else if (source->source_funcs == &g_idle_funcs || +#ifdef G_OS_UNIX + source->source_funcs == &g_unix_signal_funcs || +#endif + source->source_funcs == &g_timeout_funcs) + g_closure_set_marshal (closure, source_closure_marshal_BOOLEAN__VOID); else g_closure_set_marshal (closure, g_cclosure_marshal_generic); } diff --git a/gobject/tests/.gitignore b/gobject/tests/.gitignore index 274099393..345bf9a70 100644 --- a/gobject/tests/.gitignore +++ b/gobject/tests/.gitignore @@ -1,5 +1,6 @@ binding boxed +closure dynamictests enums ifaceproperties diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am index 1b8965442..78895ff2f 100644 --- a/gobject/tests/Makefile.am +++ b/gobject/tests/Makefile.am @@ -20,6 +20,7 @@ test_programs = \ valuearray \ type \ private \ + closure \ $(NULL) # ----------------------------------------------------------------------------- diff --git a/gobject/tests/closure.c b/gobject/tests/closure.c new file mode 100644 index 000000000..71a50de79 --- /dev/null +++ b/gobject/tests/closure.c @@ -0,0 +1,202 @@ +#include <glib-object.h> + +#ifdef G_OS_UNIX +#include <glib-unix.h> + +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#endif + +static void +test_source (GSource *one, GCallback quit_callback) +{ + GClosure *closure; + GMainLoop *loop; + + /* Callback with GMainLoop user_data */ + loop = g_main_loop_new (NULL, FALSE); + + closure = g_cclosure_new (quit_callback, loop, NULL); + g_source_set_closure (one, closure); + + g_source_attach (one, NULL); + g_main_loop_run (loop); + + g_source_destroy (one); + g_closure_unref (closure); + g_main_loop_unref (loop); +} + +static gboolean +simple_quit_callback (gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + + return TRUE; +} + +static void +test_closure_idle (void) +{ + GSource *source; + + source = g_idle_source_new (); + test_source (source, G_CALLBACK (simple_quit_callback)); + g_source_unref (source); +} + +static void +test_closure_timeout (void) +{ + GSource *source; + + source = g_timeout_source_new (10); + test_source (source, G_CALLBACK (simple_quit_callback)); + g_source_unref (source); +} + +static gboolean +iochannel_quit_callback (GIOChannel *channel, + GIOCondition cond, + gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + + return TRUE; +} + +static void +test_closure_iochannel (void) +{ + GIOChannel *chan; + GSource *source; + char *path; + GError *error = NULL; + + if (g_path_is_absolute (g_get_prgname ())) + path = g_strdup (g_get_prgname ()); + else + { + path = g_test_build_filename (G_TEST_BUILT, + g_get_prgname (), + NULL); + } + chan = g_io_channel_new_file (path, "r", &error); + g_assert_no_error (error); + g_free (path); + + source = g_io_create_watch (chan, G_IO_IN); + test_source (source, G_CALLBACK (iochannel_quit_callback)); + g_source_unref (source); + + g_io_channel_unref (chan); +} + +static void +test_closure_child (void) +{ + GSource *source; + GPid pid; + GError *error = NULL; + gchar *argv[3]; + + g_assert (getenv ("DO_NOT_ACCIDENTALLY_RECURSE") == NULL); + g_setenv ("DO_NOT_ACCIDENTALLY_RECURSE", "1", TRUE); + + if (g_path_is_absolute (g_get_prgname ())) + argv[0] = g_strdup (g_get_prgname ()); + else + { + argv[0] = g_test_build_filename (G_TEST_BUILT, + g_get_prgname (), + NULL); + } + argv[1] = "-l"; + argv[2] = NULL; + + g_spawn_async (NULL, argv, NULL, + G_SPAWN_STDOUT_TO_DEV_NULL | + G_SPAWN_STDERR_TO_DEV_NULL | + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, + &pid, &error); + g_assert_no_error (error); + + g_free (argv[0]); + + source = g_child_watch_source_new (pid); + test_source (source, G_CALLBACK (iochannel_quit_callback)); + g_source_unref (source); +} + +#ifdef G_OS_UNIX +static gboolean +fd_quit_callback (gint fd, + GIOCondition condition, + gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + + return TRUE; +} + +static void +test_closure_fd (void) +{ + gint fd; + GSource *source; + + fd = open ("/dev/null", O_RDONLY); + g_assert (fd != -1); + + source = g_unix_fd_source_new (fd, G_IO_IN); + test_source (source, G_CALLBACK (fd_quit_callback)); + g_source_unref (source); + + close (fd); +} + +static gboolean +send_usr1 (gpointer user_data) +{ + kill (0, SIGUSR1); + return FALSE; +} + +static void +test_closure_signal (void) +{ + GSource *source; + + g_idle_add_full (G_PRIORITY_LOW, send_usr1, NULL, NULL); + + source = g_unix_signal_source_new (SIGUSR1); + test_source (source, G_CALLBACK (fd_quit_callback)); + g_source_unref (source); +} +#endif + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/closure/idle", test_closure_idle); + g_test_add_func ("/closure/timeout", test_closure_timeout); + g_test_add_func ("/closure/iochannel", test_closure_iochannel); + g_test_add_func ("/closure/child", test_closure_child); +#ifdef G_OS_UNIX + g_test_add_func ("/closure/fd", test_closure_fd); + g_test_add_func ("/closure/signal", test_closure_signal); +#endif + + return g_test_run (); +} |