virNetDaemonRemoveShutdownInhibition;
virNetDaemonRun;
virNetDaemonSetLifecycleCallbacks;
-virNetDaemonSetStateStopWorkerThread;
+virNetDaemonStop;
virNetDaemonUpdateServices;
static GDBusConnection *sessionBus;
static GDBusConnection *systemBus;
-static void daemonStopWorker(void *opaque)
-{
- virNetDaemon *dmn = opaque;
-
- VIR_DEBUG("Begin stop dmn=%p", dmn);
-
- ignore_value(virStateStop());
-
- VIR_DEBUG("Completed stop dmn=%p", dmn);
-
- /* Exit daemon cleanly */
- virNetDaemonQuit(dmn);
-}
-
-
-/* We do this in a thread to not block the main loop */
-static void daemonStop(virNetDaemon *dmn)
-{
- virThread *thr;
- virObjectRef(dmn);
-
- thr = g_new0(virThread, 1);
-
- if (virThreadCreateFull(thr, true,
- daemonStopWorker,
- "daemon-stop", false, dmn) < 0) {
- virObjectUnref(dmn);
- g_free(thr);
- return;
- }
-
- virNetDaemonSetStateStopWorkerThread(dmn, &thr);
-}
-
-
static GDBusMessage *
handleSessionMessageFunc(GDBusConnection *connection G_GNUC_UNUSED,
GDBusMessage *message,
if (virGDBusMessageIsSignal(message,
"org.freedesktop.DBus.Local",
"Disconnected"))
- daemonStop(dmn);
+ virNetDaemonStop(dmn);
return message;
}
VIR_DEBUG("dmn=%p", dmn);
- daemonStop(dmn);
+ virNetDaemonStop(dmn);
}
g_atomic_int_set(&driversInitialized, 1);
virNetDaemonSetLifecycleCallbacks(dmn,
+ virStateStop,
virStateShutdownPrepare,
virStateShutdownWait);
GHashTable *servers;
virJSONValue *srvObject;
+ virNetDaemonLifecycleCallback stopCb;
virNetDaemonLifecycleCallback shutdownPrepareCb;
virNetDaemonLifecycleCallback shutdownWaitCb;
virThread *stateStopThread;
}
}
+ VIR_DEBUG("Main loop exited");
if (dmn->graceful) {
virThreadJoin(&shutdownThread);
+ VIR_DEBUG("Graceful shutdown complete");
} else {
VIR_WARN("Make forcefull daemon shutdown");
exit(EXIT_FAILURE);
void
-virNetDaemonSetStateStopWorkerThread(virNetDaemon *dmn,
- virThread **thr)
+virNetDaemonQuit(virNetDaemon *dmn)
{
VIR_LOCK_GUARD lock = virObjectLockGuard(dmn);
- VIR_DEBUG("Setting state stop worker thread on dmn=%p to thr=%p", dmn, thr);
- dmn->stateStopThread = g_steal_pointer(thr);
+ VIR_DEBUG("Quit requested %p", dmn);
+ dmn->quit = true;
}
void
-virNetDaemonQuit(virNetDaemon *dmn)
+virNetDaemonQuitExecRestart(virNetDaemon *dmn)
{
VIR_LOCK_GUARD lock = virObjectLockGuard(dmn);
- VIR_DEBUG("Quit requested %p", dmn);
+ VIR_DEBUG("Exec-restart requested %p", dmn);
dmn->quit = true;
+ dmn->execRestart = true;
+}
+
+
+static void
+virNetDaemonStopWorker(void *opaque)
+{
+ virNetDaemon *dmn = opaque;
+
+ VIR_DEBUG("Begin stop dmn=%p", dmn);
+
+ dmn->stopCb();
+
+ VIR_DEBUG("Completed stop dmn=%p", dmn);
+
+ virNetDaemonQuit(dmn);
+ virObjectUnref(dmn);
}
void
-virNetDaemonQuitExecRestart(virNetDaemon *dmn)
+virNetDaemonStop(virNetDaemon *dmn)
{
VIR_LOCK_GUARD lock = virObjectLockGuard(dmn);
- VIR_DEBUG("Exec-restart requested %p", dmn);
- dmn->quit = true;
- dmn->execRestart = true;
+ if (!dmn->stopCb ||
+ dmn->stateStopThread)
+ return;
+
+ virObjectRef(dmn);
+ dmn->stateStopThread = g_new0(virThread, 1);
+
+ if (virThreadCreateFull(dmn->stateStopThread, true,
+ virNetDaemonStopWorker,
+ "daemon-stop", false, dmn) < 0) {
+ virObjectUnref(dmn);
+ g_clear_pointer(&dmn->stateStopThread, g_free);
+ return;
+ }
}
void
virNetDaemonSetLifecycleCallbacks(virNetDaemon *dmn,
+ virNetDaemonLifecycleCallback stopCb,
virNetDaemonLifecycleCallback prepareCb,
virNetDaemonLifecycleCallback waitCb)
{
VIR_LOCK_GUARD lock = virObjectLockGuard(dmn);
+ VIR_DEBUG("Lifecycle callbacks stop=%p prepare=%p wait=%p",
+ stopCb, prepareCb, waitCb);
+
+ /* Immutable once set */
+ if (dmn->stopCb || dmn->shutdownPrepareCb || dmn->shutdownWaitCb)
+ return;
+
+ dmn->stopCb = stopCb;
dmn->shutdownPrepareCb = prepareCb;
dmn->shutdownWaitCb = waitCb;
}
void virNetDaemonUpdateServices(virNetDaemon *dmn,
bool enabled);
-void virNetDaemonSetStateStopWorkerThread(virNetDaemon *dmn,
- virThread **thr);
-
void virNetDaemonRun(virNetDaemon *dmn);
void virNetDaemonQuit(virNetDaemon *dmn);
void virNetDaemonQuitExecRestart(virNetDaemon *dmn);
+void virNetDaemonStop(virNetDaemon *dmn);
bool virNetDaemonHasClients(virNetDaemon *dmn);
typedef int (*virNetDaemonLifecycleCallback)(void);
+/*
+ * @stopCb: preserves any active state on host shutdown / session exit
+ * @prepareCb: start shutting down daemon
+ * @waitCb: wait for shutdown completion
+ *
+ * This method may only be invoked once, the callbacks are immutable
+ * once set.
+ *
+ * On host shutdown (privileged) or session exit (unprivileged)
+ * the @stopCb will be invoked first.
+ *
+ * When the daemon shuts down, the sequence of operations is
+ * as follows
+ *
+ * - Listener stops accepting new clients
+ * - Existing clients are closed
+ * - Delay until @stopCb is complete (if still running)
+ * - @prepareCb invoked
+ * - Server worker pool is drained in background
+ * - @waitCb is invoked in background
+ * - Main loop terminates
+ */
void virNetDaemonSetLifecycleCallbacks(virNetDaemon *dmn,
+ virNetDaemonLifecycleCallback stopCb,
virNetDaemonLifecycleCallback prepareCb,
virNetDaemonLifecycleCallback waitCb);