Use a FIFO(named pipe) for --event-monitor option in CH. Introduce a new
thread, `virCHEventHandlerLoop`, to continuously monitor and handle
events from cloud-hypervisor.
Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
Co-authored-by: Vineeth Pillai <viremana@linux.microsoft.com>
---
po/POTFILES | 1 +
src/ch/ch_events.c | 93 +++++++++++++++++++++++++++++++++++++++++++++
src/ch/ch_events.h | 26 +++++++++++++
src/ch/ch_monitor.c | 32 ++++++++++++++--
src/ch/ch_monitor.h | 3 ++
src/ch/meson.build | 2 +
6 files changed, 154 insertions(+), 3 deletions(-)
create mode 100644 src/ch/ch_events.c
create mode 100644 src/ch/ch_events.h
diff --git a/po/POTFILES b/po/POTFILES
index 1ed4086d2c..d53307cec4 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -21,6 +21,7 @@ src/bhyve/bhyve_process.c
src/ch/ch_conf.c
src/ch/ch_domain.c
src/ch/ch_driver.c
+src/ch/ch_events.c
src/ch/ch_interface.c
src/ch/ch_monitor.c
src/ch/ch_process.c
diff --git a/src/ch/ch_events.c b/src/ch/ch_events.c
new file mode 100644
index 0000000000..bb27f340e2
--- /dev/null
+++ b/src/ch/ch_events.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright Microsoft Corp. 2024
+ *
+ * ch_events.c: Handle Cloud-Hypervisor events
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <fcntl.h>
+
+#include "ch_events.h"
+#include "virfile.h"
+#include "virlog.h"
+
+VIR_LOG_INIT("ch.ch_events");
+
+static void virCHEventHandlerLoop(void *data)
+{
+ virCHMonitor *mon = data;
+ virDomainObj *vm = NULL;
+ int event_monitor_fd;
+
+ /* Obtain a vm reference */
+ vm = virObjectRef(mon->vm);
+
+ VIR_DEBUG("%s: Event handler loop thread starting", vm->def->name);
+
+ while ((event_monitor_fd = open(mon->eventmonitorpath, O_RDONLY)) < 0) {
+ if (errno == EINTR) {
+ /* 100 milli seconds */
+ g_usleep(100000);
+ continue;
+ }
+ /* Any other error should be a BUG(kernel/libc/libvirtd)
+ * (ENOMEM can happen on exceeding per-user limits)
+ */
+ VIR_ERROR(_("%1$s: Failed to open the event monitor FIFO(%2$s) read end!"),
+ vm->def->name, mon->eventmonitorpath);
+ abort();
+ }
+ VIR_DEBUG("%s: Opened the event monitor FIFO(%s)", vm->def->name, mon->eventmonitorpath);
+
+ while (g_atomic_int_get(&mon->event_handler_stop) == 0) {
+ VIR_DEBUG("%s: Reading events from event monitor file", vm->def->name);
+ /* Read and process events here */
+ }
+
+ VIR_FORCE_CLOSE(event_monitor_fd);
+ virObjectUnref(vm);
+
+ VIR_DEBUG("%s: Event handler loop thread exiting", vm->def->name);
+ return;
+}
+
+int virCHStartEventHandler(virCHMonitor *mon)
+{
+ g_autofree char *name = NULL;
+ name = g_strdup_printf("ch-evt-%d", mon->pid);
+
+ virObjectRef(mon);
+ if (virThreadCreateFull(&mon->event_handler_thread,
+ false,
+ virCHEventHandlerLoop,
+ name,
+ false,
+ mon) < 0) {
+ virObjectUnref(mon);
+ return -1;
+ }
+ virObjectUnref(mon);
+
+ g_atomic_int_set(&mon->event_handler_stop, 0);
+ return 0;
+}
+
+void virCHStopEventHandler(virCHMonitor *mon)
+{
+ g_atomic_int_set(&mon->event_handler_stop, 1);
+}
diff --git a/src/ch/ch_events.h b/src/ch/ch_events.h
new file mode 100644
index 0000000000..4c8a48231d
--- /dev/null
+++ b/src/ch/ch_events.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright Microsoft Corp. 2024
+ *
+ * ch_events.h: header file for handling Cloud-Hypervisor events
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ch_monitor.h"
+
+int virCHStartEventHandler(virCHMonitor *mon);
+void virCHStopEventHandler(virCHMonitor *mon);
diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c
index 21a9ee273e..097e64d9d5 100644
--- a/src/ch/ch_monitor.c
+++ b/src/ch/ch_monitor.c
@@ -26,6 +26,7 @@
#include "datatypes.h"
#include "ch_conf.h"
+#include "ch_events.h"
#include "ch_interface.h"
#include "ch_monitor.h"
#include "domain_interface.h"
@@ -572,6 +573,27 @@ virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg)
return NULL;
}
+ /* Event monitor file to listen for VM state changes */
+ mon->eventmonitorpath = g_strdup_printf("%s/%s-event-monitor-fifo",
+ cfg->stateDir, vm->def->name);
+ if (virFileExists(mon->eventmonitorpath)) {
+ VIR_WARN("Monitor file (%s) already exists, trying to delete!",
+ mon->eventmonitorpath);
+ if (virFileRemove(mon->eventmonitorpath, -1, -1) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to remove the file: %1$s"),
+ mon->eventmonitorpath);
+ return NULL;
+ }
+ }
+
+ if (mkfifo(mon->eventmonitorpath, S_IWUSR | S_IRUSR) < 0 &&
+ errno != EEXIST) {
+ virReportSystemError(errno, "%s",
+ _("Cannot create monitor FIFO"));
+ return NULL;
+ }
+
cmd = virCommandNew(vm->def->emulator);
virCommandSetUmask(cmd, 0x002);
socket_fd = chMonitorCreateSocket(mon->socketpath);
@@ -593,12 +615,15 @@ virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg)
if (virCommandRunAsync(cmd, &mon->pid) < 0)
return NULL;
- /* get a curl handle */
- mon->handle = curl_easy_init();
-
/* now has its own reference */
mon->vm = virObjectRef(vm);
+ if (virCHStartEventHandler(mon) < 0)
+ return NULL;
+
+ /* get a curl handle */
+ mon->handle = curl_easy_init();
+
return g_steal_pointer(&mon);
}
@@ -633,6 +658,7 @@ void virCHMonitorClose(virCHMonitor *mon)
g_free(mon->socketpath);
}
+ virCHStopEventHandler(mon);
if (virFileExists(mon->eventmonitorpath)) {
if (virFileRemove(mon->eventmonitorpath, -1, -1) < 0) {
VIR_WARN("Unable to remove CH event monitor file '%s'",
diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h
index 2ef8706b99..878a185f29 100644
--- a/src/ch/ch_monitor.h
+++ b/src/ch/ch_monitor.h
@@ -97,6 +97,9 @@ struct _virCHMonitor {
char *eventmonitorpath;
+ virThread event_handler_thread;
+ int event_handler_stop;
+
pid_t pid;
virDomainObj *vm;
diff --git a/src/ch/meson.build b/src/ch/meson.build
index 633966aac7..77bbb2d450 100644
--- a/src/ch/meson.build
+++ b/src/ch/meson.build
@@ -7,6 +7,8 @@ ch_driver_sources = [
'ch_domain.h',
'ch_driver.c',
'ch_driver.h',
+ 'ch_events.c',
+ 'ch_events.h',
'ch_interface.c',
'ch_interface.h',
'ch_monitor.c',
--
2.34.1
On 10/23/24 10:02, Purna Pavan Chandra Aekkaladevi wrote:
> Use a FIFO(named pipe) for --event-monitor option in CH. Introduce a new
> thread, `virCHEventHandlerLoop`, to continuously monitor and handle
> events from cloud-hypervisor.
>
> Signed-off-by: Purna Pavan Chandra Aekkaladevi <paekkaladevi@linux.microsoft.com>
> Co-authored-by: Vineeth Pillai <viremana@linux.microsoft.com>
> ---
> po/POTFILES | 1 +
> src/ch/ch_events.c | 93 +++++++++++++++++++++++++++++++++++++++++++++
> src/ch/ch_events.h | 26 +++++++++++++
> src/ch/ch_monitor.c | 32 ++++++++++++++--
> src/ch/ch_monitor.h | 3 ++
> src/ch/meson.build | 2 +
> 6 files changed, 154 insertions(+), 3 deletions(-)
> create mode 100644 src/ch/ch_events.c
> create mode 100644 src/ch/ch_events.h
>
> diff --git a/po/POTFILES b/po/POTFILES
> index 1ed4086d2c..d53307cec4 100644
> --- a/po/POTFILES
> +++ b/po/POTFILES
> @@ -21,6 +21,7 @@ src/bhyve/bhyve_process.c
> src/ch/ch_conf.c
> src/ch/ch_domain.c
> src/ch/ch_driver.c
> +src/ch/ch_events.c
> src/ch/ch_interface.c
> src/ch/ch_monitor.c
> src/ch/ch_process.c
> diff --git a/src/ch/ch_events.c b/src/ch/ch_events.c
> new file mode 100644
> index 0000000000..bb27f340e2
> --- /dev/null
> +++ b/src/ch/ch_events.c
> @@ -0,0 +1,93 @@
> +/*
> + * Copyright Microsoft Corp. 2024
> + *
> + * ch_events.c: Handle Cloud-Hypervisor events
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library. If not, see
> + * <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <config.h>
> +
> +#include <fcntl.h>
> +
> +#include "ch_events.h"
> +#include "virfile.h"
> +#include "virlog.h"
> +
> +VIR_LOG_INIT("ch.ch_events");
> +
> +static void virCHEventHandlerLoop(void *data)
> +{
> + virCHMonitor *mon = data;
> + virDomainObj *vm = NULL;
> + int event_monitor_fd;
> +
> + /* Obtain a vm reference */
> + vm = virObjectRef(mon->vm);
> +
> + VIR_DEBUG("%s: Event handler loop thread starting", vm->def->name);
> +
> + while ((event_monitor_fd = open(mon->eventmonitorpath, O_RDONLY)) < 0) {
> + if (errno == EINTR) {
> + /* 100 milli seconds */
> + g_usleep(100000);
> + continue;
> + }
> + /* Any other error should be a BUG(kernel/libc/libvirtd)
> + * (ENOMEM can happen on exceeding per-user limits)
> + */
> + VIR_ERROR(_("%1$s: Failed to open the event monitor FIFO(%2$s) read end!"),
> + vm->def->name, mon->eventmonitorpath);
> + abort();
This sounds too harsh! abort() aborts whole process (libvirtd). If
opening monitor fails then we should just kill the VM and exit from the
thread.
You will find some calls to abort() throughout our code, but those are
cases where memory allocation failed at which point that's the only
reasonable thing to do. But abort()-ing on failed open() is too much.
Michal
© 2016 - 2026 Red Hat, Inc.