bool start();
+ void stop();
+
// If the GVariant 'param' is floating, it is consumed.
void publish(const std::string& busName, const std::string& signalName, GVariant* param);
protected:
DBusService(GDBusConnection* conn, const char* serviceName, const char* methodSpecs);
- virtual void prepare() = 0;
- virtual ClientProxy* createProxy(const std::string& busName) = 0;
+ virtual bool prepare() = 0;
+
+ virtual void cleanup() = 0;
- virtual void onUserActivated(uid_t uid);
+ virtual void onUserActivated(uid_t uid) = 0;
+
+ virtual ClientProxy* createProxy(const std::string& busName) = 0;
private:
static gpointer __threadFunc(gpointer data);
const gchar* path, const gchar* iface, const gchar* name,
GVariant* param, gpointer userData);
+ static gboolean __stopMainLoop(gpointer data);
+
void __onMethodCalled(const std::string& sender,
const std::string& name, GVariant* param, GDBusMethodInvocation* invocation);
DBusService::~DBusService()
{
-#ifndef SINGLE_THREADING
- if (__mainLoop && g_main_loop_is_running(__mainLoop)) {
- _I(PURPLE("Stopping the mainloop of '%s'"), __serviceName);
- g_main_loop_quit(__mainLoop);
- }
-
- if (__gthread) {
- _I("Joining the thread of '%s'", __serviceName);
- g_thread_join(__gthread);
- }
-#else
- __release();
-#endif
}
GDBusConnection* DBusService::getConnection()
#else
_I(CYAN("'%s' runs on the default main loop"), __serviceName);
IF_FAIL_RETURN(__init(), false);
- prepare();
#endif
return true;
}
+void DBusService::stop()
+{
+#ifndef SINGLE_THREADING
+ if (__mainLoop && g_main_loop_is_running(__mainLoop)) {
+ GSource *gSrc = g_idle_source_new();
+ if (gSrc) {
+ // Tries to stop the main loop within its thread.
+ // In this way, already scheduled idle tasks are not discarded.
+ g_source_set_callback(gSrc, __stopMainLoop, this, NULL);
+ g_source_attach(gSrc, __mainContext);
+ } else {
+ __stopMainLoop(this);
+ }
+ }
+
+ if (__gthread) {
+ _I("Joining the thread of '%s'", __serviceName);
+ g_thread_join(__gthread);
+ }
+#else
+ __release();
+#endif
+}
+
+gboolean DBusService::__stopMainLoop(gpointer data)
+{
+ DBusService* svc = static_cast<DBusService*>(data);
+ _I(PURPLE("Stopping '%s'"), svc->__serviceName);
+ g_main_loop_quit(svc->__mainLoop);
+ return G_SOURCE_REMOVE;
+}
+
void DBusService::publish(const std::string& busName, const std::string& signalName, GVariant* param)
{
GError* gerr = NULL;
HANDLE_GERROR(gerr);
}
-void DBusService::onUserActivated(uid_t uid)
-{
-}
-
uid_t DBusService::getActiveUser()
{
if (__activeUid == 0) {
return;
}
- prepare();
-
_I(CYAN("Starting '%s'"), __serviceName);
g_main_loop_run(__mainLoop);
NULL, "org.freedesktop.login1.Manager", "UserNew", NULL,
NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserNew, this, NULL);
- return true;
+ return prepare();
}
void DBusService::__release()
{
+ _D("Releasing '%s'", __serviceName);
+
for (auto iter = __proxies.begin(); iter != __proxies.end(); ++iter) {
iter->second.proxy->onDisconnected();
delete iter->second.proxy;
__proxies.clear();
+ cleanup();
+
if (__userNewSignalId > 0)
g_dbus_connection_signal_unsubscribe(__connection, __userNewSignalId);
if (__nodeInfo)
g_dbus_node_info_unref(__nodeInfo);
-#ifndef SINGLE_THREADING
if (__mainLoop)
g_main_loop_unref(__mainLoop);
if (__mainContext)
g_main_context_unref(__mainContext);
-#endif
}
void DBusService::__onUserNew(GDBusConnection* conn, const gchar* sender,