qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 3/5] add qmp time-notify event triggering system


From: Damien Hedde
Subject: [Qemu-devel] [RFC PATCH 3/5] add qmp time-notify event triggering system
Date: Fri, 28 Jun 2019 14:45:32 +0200

This adds an event triggering mechanism composed of:
 + an event that is catchable by qmp clients
 + a command to create such events

When triggered the event TIME_NOTIFICATION is signaled. Optionnaly the
virtual machine is also paused (put in debug state). The virtual machine can
then be restarted by the _cont_ command.

To create an event, an id and the deadline in virtual clock nanoseconds
should be given to the "time-notify" qmp command. The event will be
triggered at the given time which may be absolute or relative to the
current virtual clock time.

This allows to write qmp clients that can pause the vm, do some actions
then restart the vm.

This is based on the work of Frederic Konrad.

Signed-off-by: Damien Hedde <address@hidden>
---
 monitor/Makefile.objs         |   1 +
 monitor/qmp-cmd-time-notify.c | 116 ++++++++++++++++++++++++++++++++++
 monitor/trace-events          |   4 ++
 qapi/misc.json                |  48 ++++++++++++++
 4 files changed, 169 insertions(+)
 create mode 100644 monitor/qmp-cmd-time-notify.c

diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs
index e91a8581cd..f4c7293460 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1,3 +1,4 @@
 obj-y += misc.o
 common-obj-y += monitor.o qmp.o hmp.o
 common-obj-y += qmp-cmds.o hmp-cmds.o
+common-obj-y += qmp-cmd-time-notify.o
diff --git a/monitor/qmp-cmd-time-notify.c b/monitor/qmp-cmd-time-notify.c
new file mode 100644
index 0000000000..de13b2d3a1
--- /dev/null
+++ b/monitor/qmp-cmd-time-notify.c
@@ -0,0 +1,116 @@
+/*
+ * qmp-cmd-time-notify.c
+ *
+ * Copyright (c) 2016,2019 GreenSocs SAS
+ *
+ * Authors:
+ *    Fred Konrad
+ *    Damien Hedde
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-events-misc.h"
+#include "qemu/timer.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
+#include "trace.h"
+
+typedef struct TimeNotifEntry TimeNotifEntry;
+static QLIST_HEAD(, TimeNotifEntry) events = QLIST_HEAD_INITIALIZER(events);
+static QEMUTimer *timer;
+
+struct TimeNotifEntry {
+    uint64_t time_ns;
+    int64_t id;
+    bool pause;
+    QLIST_ENTRY(TimeNotifEntry) node;
+};
+
+static void mod_next_event_timer(void)
+{
+    if (QLIST_EMPTY(&events)) {
+        return;
+    }
+
+    timer_mod(timer, QLIST_FIRST(&events)->time_ns);
+}
+
+static void trigger_notif(void *opaque)
+{
+    TimeNotifEntry *entry;
+    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    bool do_stop;
+
+    entry = QLIST_FIRST(&events);
+    assert(entry && entry->time_ns <= current_time);
+    do_stop = entry->pause;
+
+    QLIST_REMOVE(entry, node);
+    qapi_event_send_time_notification(entry->id, current_time);
+    trace_qmp_time_notify_trigger(entry->id, current_time, entry->pause);
+    g_free(entry);
+
+    mod_next_event_timer();
+
+    if (do_stop) {
+        qemu_system_vmstop_request_prepare();
+        qemu_system_vmstop_request(RUN_STATE_DEBUG);
+        /*
+         * FIXME: should not return to device code in case
+         * vm_stop() has been requested.
+         */
+        cpu_stop_current();
+    }
+}
+
+void qmp_time_notify(int64_t event_id, int64_t time_ns,
+                     bool has_relative, bool relative,
+                     bool has_pause, bool pause,
+                     Error **errp)
+{
+    TimeNotifEntry *new_entry, *entry, *prev = NULL;
+
+    if (!timer) {
+        timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, trigger_notif, NULL);
+    }
+
+    if (time_ns < 0) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "time_ns",
+                "must be positive");
+    }
+
+    new_entry = g_new0(TimeNotifEntry, 1);
+    new_entry->id = event_id;
+    new_entry->time_ns = time_ns;
+    new_entry->pause = has_pause && pause;
+    if (has_relative && relative) {
+        new_entry->time_ns += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    }
+    trace_qmp_time_notify_schedule(new_entry->id, new_entry->time_ns,
+                                   new_entry->pause);
+
+    /* find the event just before the new one */
+    QLIST_FOREACH(entry, &events, node) {
+        if (entry->time_ns > new_entry->time_ns) {
+            break;
+        }
+        prev = entry;
+    }
+
+    /* then insert the new entry */
+    if (prev) {
+        QLIST_INSERT_AFTER(prev, new_entry, node);
+    } else {
+        QLIST_INSERT_HEAD(&events, new_entry, node);
+        mod_next_event_timer();
+    }
+}
diff --git a/monitor/trace-events b/monitor/trace-events
index 0365ac4d99..73f375db68 100644
--- a/monitor/trace-events
+++ b/monitor/trace-events
@@ -13,3 +13,7 @@ monitor_suspend(void *ptr, int cnt) "mon %p: %d"
 monitor_qmp_cmd_in_band(const char *id) "%s"
 monitor_qmp_cmd_out_of_band(const char *id) "%s"
 handle_qmp_command(void *mon, const char *req) "mon %p req: %s"
+
+# qmp-cmd-time-notify.c
+qmp_time_notify_trigger(int64_t id, uint64_t time, int pause) "event 
#%"PRId64" at %"PRIu64" ns pause %d"
+qmp_time_notify_schedule(int64_t id, uint64_t time, int pause) "event 
#%"PRId64" at %"PRIu64" ns pause %d"
diff --git a/qapi/misc.json b/qapi/misc.json
index 255236b96f..8e84f4d4d3 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -3195,3 +3195,51 @@
 { 'command': 'gpio-set',
   'data': { 'path': 'str', '*gpio': 'str', '*number': 'int', 'value': 'bool' }
 }
+
+##
+# @time-notify:
+#
+# Schedule a TIME_NOTIFICATION which will optionally stop qemu when triggered.
+#
+# @time_ns:  The virtual guest clock at which do the notification.
+#
+# @relative: Optional boolean telling if time_ns is relative to current time.
+#            Defaults to False.
+#
+# @event_id: An ID, to track the notification.
+#
+# @pause: Optional boolean telling whether to pause qemu when notification is
+#         hit. Defaults to False.
+#
+# Returns: nothing in case of success
+#
+# Since 4.1
+#
+# Example:
+#
+# -> { "execute": "time-notify",
+#      "arguments": { "event_id": 5,
+#                      "time_ns": 10000000,
+#                      "pause": true} }
+# <- { "return": {} }
+#
+##
+{ 'command': 'time-notify',
+  'data': {'event_id': 'int', 'time_ns': 'int', '*relative': 'bool',
+           '*pause': 'bool'}
+}
+
+##
+# @TIME_NOTIFICATION:
+#
+# Emitted when notification deadline is hit
+#
+# @time_ns:  The current virtual guest clock time.
+#
+# @event_id: The id given when setting up the notification.
+#
+# Since: 4.1
+#
+##
+{ 'event': 'TIME_NOTIFICATION',
+  'data': { 'event_id': 'int', 'time_ns': 'int'} }
-- 
2.22.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]