--- /dev/null
+/*
+ * 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 "ch_domain.h"
+#include "ch_events.h"
+#include "ch_process.h"
+#include "virfile.h"
+#include "virlog.h"
+
+VIR_LOG_INIT("ch.ch_events");
+
+
+static void
+virCHEventHandlerLoop(void *data)
+{
+ virCHMonitor *mon = data;
+ virDomainObj *vm = NULL;
+
+ /* Obtain a vm reference */
+ vm = virObjectRef(mon->vm);
+
+ VIR_DEBUG("%s: Event handler loop thread starting", vm->def->name);
+
+ 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 */
+ }
+
+ 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);
+}
--- /dev/null
+/*
+ * 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);
#include <config.h>
+#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include "datatypes.h"
#include "ch_conf.h"
+#include "ch_events.h"
#include "ch_interface.h"
#include "ch_monitor.h"
#include "domain_interface.h"
g_autoptr(virCHMonitor) mon = NULL;
g_autoptr(virCommand) cmd = NULL;
int socket_fd = 0;
+ int event_monitor_fd;
if (virCHMonitorInitialize() < 0)
return NULL;
if (!(mon = virObjectLockableNew(virCHMonitorClass)))
return NULL;
+ /* avoid VIR_FORCE_CLOSE()-ing garbage fd value in virCHMonitorClose */
+ mon->eventmonitorfd = -1;
+
if (!vm->def) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("VM is not defined"));
/* prepare to launch Cloud-Hypervisor socket */
mon->socketpath = g_strdup_printf("%s/%s-socket", cfg->stateDir, vm->def->name);
- mon->eventmonitorpath = g_strdup_printf("%s/%s-event-monitor",
- cfg->stateDir, vm->def->name);
if (g_mkdir_with_parents(cfg->stateDir, 0777) < 0) {
virReportSystemError(errno,
_("Cannot create socket directory '%1$s'"),
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);
virCommandSetOutputFD(cmd, &logfile);
virCommandSetErrorFD(cmd, &logfile);
if (virCommandRunAsync(cmd, &mon->pid) < 0)
return NULL;
- /* get a curl handle */
- mon->handle = curl_easy_init();
+ /* open the reader end of fifo before start Event Handler */
+ 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);
+ /* CH process(Writer) is blocked at this point as EventHandler(Reader)
+ * fails to open the FIFO.
+ */
+ return NULL;
+ }
+ mon->eventmonitorfd = event_monitor_fd;
+ VIR_DEBUG("%s: Opened the event monitor FIFO(%s)", vm->def->name, mon->eventmonitorpath);
/* 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);
}
g_clear_pointer(&mon->socketpath, g_free);
}
+ virCHStopEventHandler(mon);
+ if (mon->eventmonitorfd >= 0) {
+ VIR_FORCE_CLOSE(mon->eventmonitorfd);
+ }
if (mon->eventmonitorpath) {
if (virFileRemove(mon->eventmonitorpath, -1, -1) < 0) {
VIR_WARN("Unable to remove CH event monitor file '%s'",