Should I be able to call g_main_loop_quit
from a signal handler?
I have a GObject
subclass, let’s call XQuitter
. This class defines a signal named “disconnected”. I use an instance of this subclass in a program that uses a GMainLoop
to maintain a connection to a D-Bus broker. The program connects to the broker using g_bus_own_name
. The instance is passed into this function as the user_data parameter. In the name_lost_handler function, g_signal_emit
is called using the instance as the object and “disconnected” as the signal name. In the signal handler callback function, the GMainLoop
is passed in as the user_data parameter, and the function g_main_loop_quit
is called. My assumption is that the main loop will quit running and the program will exit cleanly. However, the signal handler function is called, but the program does not quit. Is this expected behavior? Am I misusing GObject signals? Is there a better way to have my program quit if it cannot acquire a name on the bus?
I believe I have isolated this behavior into a small C program.
#include <gio/gio.h>
#include <glib-object.h>
#define X_TYPE_QUITTER (x_quitter_get_type())
G_DECLARE_FINAL_TYPE (XQuitter, x_quitter, X, QUITTER, GObject)
struct _XQuitter
{
GObject parent_instance;
};
G_DEFINE_FINAL_TYPE (XQuitter, x_quitter, G_TYPE_OBJECT)
enum {
SIGNAL_DISCONNECTED = 1,
N_SIGNALS
};
static guint signals[N_SIGNALS];
static void
on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data)
{
g_debug ("on_bus_acquired: %s", name);
}
static void
on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data)
{
g_debug ("on_name_acquired: %s", name);
}
static void
on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data)
{
g_debug ("on_name_lost: %s", name);
XQuitter *self = X_QUITTER (user_data);
g_signal_emit (self, signals[SIGNAL_DISCONNECTED], 0);
}
static void
x_quitter_class_init (XQuitterClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
signals[SIGNAL_DISCONNECTED] = g_signal_newv ("disconnected",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
NULL,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
}
static void
x_quitter_init (XQuitter *self)
{
}
static void
disconnected_signal_handler (gpointer user_data)
{
g_debug ("disconnected_signal_handler");
g_main_loop_quit (user_data);
}
gint
main (gint argc, gchar *argv[])
{
g_autoptr (GMainContext) context = g_main_context_default ();
g_autoptr (GMainLoop) loop = g_main_loop_new (context, FALSE);
g_autoptr (XQuitter) quitter = g_object_new (X_TYPE_QUITTER, NULL);
g_signal_connect (quitter, "disconnected", G_CALLBACK (disconnected_signal_handler), loop);
guint bus_id = g_bus_own_name (G_BUS_TYPE_STARTER,
"com.test.quitter",
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
quitter,
NULL);
g_main_loop_run (loop);
return 0;
}