Similar to domain shutdown events, processing domain death events can be a
lengthy process and we don't want to block the event handler while the
operation completes. Move the death handling function to a thread.
Signed-off-by: Jim Fehlig <jfehlig(a)suse.com>
---
src/libxl/libxl_domain.c | 67 ++++++++++++++++++++++++++++------------
1 file changed, 47 insertions(+), 20 deletions(-)
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 5d0034102e..d6c5f7e5b7 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -613,12 +613,17 @@ libxlDomainShutdownThread(void *opaque)
}
static void
-libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm)
+libxlDomainDeathThread(void *opaque)
{
+ struct libxlEventHandlerThreadInfo *death_info = opaque;
+ virDomainObj *vm = death_info->vm;
+ libxl_event *ev = death_info->event;
+ libxlDriverPrivate *driver = death_info->driver;
virObjectEvent *dom_event = NULL;
+ g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
- return;
+ goto cleanup;
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED);
dom_event = virDomainEventLifecycleNewFromObj(vm,
@@ -629,6 +634,11 @@ libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm)
virDomainObjListRemove(driver->domains, vm);
libxlDomainObjEndJob(driver, vm);
virObjectEventStateQueue(driver->domainEventState, dom_event);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ libxl_event_free(cfg->ctx, ev);
+ VIR_FREE(death_info);
}
@@ -642,6 +652,9 @@ libxlDomainEventHandler(void *data, libxl_event *event)
libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason;
virDomainObj *vm = NULL;
g_autoptr(libxlDriverConfig) cfg = NULL;
+ struct libxlEventHandlerThreadInfo *thread_info = NULL;
+ virThread thread;
+ g_autofree char *thread_name = NULL;
VIR_DEBUG("Received libxl event '%d' for domid '%d'",
event->type, event->domid);
@@ -664,31 +677,27 @@ libxlDomainEventHandler(void *data, libxl_event *event)
goto cleanup;
}
+ /*
+ * Start event-specific threads to handle shutdown and death.
+ * They are potentially lengthy operations and we don't want to be
+ * blocking this event handler while they are in progress.
+ */
if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) {
- struct libxlEventHandlerThreadInfo *shutdown_info = NULL;
- virThread thread;
- g_autofree char *name = NULL;
+ thread_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
- /*
- * Start a thread to handle shutdown. We don't want to be tying up
- * libxl's event machinery by doing a potentially lengthy shutdown.
- */
- shutdown_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
-
- shutdown_info->driver = driver;
- shutdown_info->vm = vm;
- shutdown_info->event = (libxl_event *)event;
- name = g_strdup_printf("shutdown-event-%d", event->domid);
+ thread_info->driver = driver;
+ thread_info->vm = vm;
+ thread_info->event = (libxl_event *)event;
+ thread_name = g_strdup_printf("shutdown-event-%d", event->domid);
/*
* Cleanup will be handled by the shutdown thread.
*/
if (virThreadCreateFull(&thread, false, libxlDomainShutdownThread,
- name, false, shutdown_info) < 0) {
+ thread_name, false, thread_info) < 0) {
/*
* Not much we can do on error here except log it.
*/
VIR_ERROR(_("Failed to create thread to handle domain shutdown"));
- VIR_FREE(shutdown_info);
goto cleanup;
}
/*
@@ -697,15 +706,33 @@ libxlDomainEventHandler(void *data, libxl_event *event)
*/
return;
} else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
+ thread_info = g_new0(struct libxlEventHandlerThreadInfo, 1);
+
+ thread_info->driver = driver;
+ thread_info->vm = vm;
+ thread_info->event = (libxl_event *)event;
+ thread_name = g_strdup_printf("death-event-%d", event->domid);
/*
- * On death the domain is cleaned up from Xen's perspective.
- * Cleanup on the libvirt side can be done synchronously.
+ * Cleanup will be handled by the death thread.
*/
- libxlDomainHandleDeath(driver, vm);
+ if (virThreadCreateFull(&thread, false, libxlDomainDeathThread,
+ thread_name, false, thread_info) < 0) {
+ /*
+ * Not much we can do on error here except log it.
+ */
+ VIR_ERROR(_("Failed to create thread to handle domain death"));
+ goto cleanup;
+ }
+ /*
+ * virDomainObjEndAPI is called in the death thread, where
+ * libxlEventHandlerThreadInfo and libxl_event are also freed.
+ */
+ return;
}
cleanup:
virDomainObjEndAPI(&vm);
+ VIR_FREE(thread_info);
cfg = libxlDriverConfigGet(driver);
/* Cast away any const */
libxl_event_free(cfg->ctx, (libxl_event *)event);
--
2.33.0