Patchwork [v5,05/12] suspend: add infrastructure

login
register
mail settings
Submitter Gerd Hoffmann
Date Feb. 15, 2012, 10:28 a.m.
Message ID <1329301701-30395-6-git-send-email-kraxel@redhat.com>
Download mbox | patch
Permalink /patch/141295/
State New
Headers show

Comments

Gerd Hoffmann - Feb. 15, 2012, 10:28 a.m.
This patch adds some infrastructure to handle suspend and resume to
qemu.  First there are two functions to switch state and second there
is a suspend notifier:

 * qemu_system_suspend_request is supposed to be called when the
   guest asks for being be suspended, for example via ACPI.

 * qemu_system_wakeup_request is supposed to be called on events
   which should wake up the guest.

 * qemu_register_suspend_notifier can be used to register a notifier
   which will be called when the guest is suspended.  Machine types
   and device models can hook in there to modify state if needed.

 * qemu_register_wakeup_notifier can be used to register a notifier
   which will be called when the guest is woken up.  Machine types
   and device models can hook in there to modify state if needed.

 * qemu_system_wakeup_enable can be used to enable/disable wakeup
   events.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 sysemu.h |    9 ++++++++
 vl.c     |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)

Patch

diff --git a/sysemu.h b/sysemu.h
index 9d5ce33..af73813 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -38,7 +38,16 @@  void vm_start(void);
 void vm_stop(RunState state);
 void vm_stop_force_state(RunState state);
 
+typedef enum WakeupReason {
+    QEMU_WAKEUP_REASON_OTHER = 0,
+} WakeupReason;
+
 void qemu_system_reset_request(void);
+void qemu_system_suspend_request(void);
+void qemu_register_suspend_notifier(Notifier *notifier);
+void qemu_system_wakeup_request(WakeupReason reason);
+void qemu_system_wakeup_enable(WakeupReason reason, bool enabled);
+void qemu_register_wakeup_notifier(Notifier *notifier);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
 void qemu_system_debug_request(void);
diff --git a/vl.c b/vl.c
index 63dd725..bfdcb7c 100644
--- a/vl.c
+++ b/vl.c
@@ -1283,6 +1283,13 @@  static int shutdown_requested, shutdown_signal = -1;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
+static int suspend_requested;
+static bool is_suspended;
+static NotifierList suspend_notifiers =
+    NOTIFIER_LIST_INITIALIZER(suspend_notifiers);
+static NotifierList wakeup_notifiers =
+    NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
+static uint32_t wakeup_reason_mask = ~0;
 static RunState vmstop_requested = RUN_STATE_MAX;
 
 int qemu_shutdown_requested_get(void)
@@ -1325,6 +1332,13 @@  int qemu_reset_requested(void)
     return r;
 }
 
+static int qemu_suspend_requested(void)
+{
+    int r = suspend_requested;
+    suspend_requested = 0;
+    return r;
+}
+
 int qemu_powerdown_requested(void)
 {
     int r = powerdown_requested;
@@ -1398,6 +1412,56 @@  void qemu_system_reset_request(void)
     qemu_notify_event();
 }
 
+static void qemu_system_suspend(void)
+{
+    pause_all_vcpus();
+    notifier_list_notify(&suspend_notifiers, NULL);
+    is_suspended = true;
+}
+
+void qemu_system_suspend_request(void)
+{
+    if (is_suspended) {
+        return;
+    }
+    suspend_requested = 1;
+    cpu_stop_current();
+    qemu_notify_event();
+}
+
+void qemu_register_suspend_notifier(Notifier *notifier)
+{
+    notifier_list_add(&suspend_notifiers, notifier);
+}
+
+void qemu_system_wakeup_request(WakeupReason reason)
+{
+    if (!is_suspended) {
+        return;
+    }
+    if (!(wakeup_reason_mask & (1 << reason))) {
+        return;
+    }
+    notifier_list_notify(&wakeup_notifiers, &reason);
+    reset_requested = 1;
+    qemu_notify_event();
+    is_suspended = false;
+}
+
+void qemu_system_wakeup_enable(WakeupReason reason, bool enabled)
+{
+    if (enabled) {
+        wakeup_reason_mask |= (1 << reason);
+    } else {
+        wakeup_reason_mask &= ~(1 << reason);
+    }
+}
+
+void qemu_register_wakeup_notifier(Notifier *notifier)
+{
+    notifier_list_add(&wakeup_notifiers, notifier);
+}
+
 void qemu_system_killed(int signal, pid_t pid)
 {
     shutdown_signal = signal;
@@ -1438,6 +1502,9 @@  static bool main_loop_should_exit(void)
     if (qemu_debug_requested()) {
         vm_stop(RUN_STATE_DEBUG);
     }
+    if (qemu_suspend_requested()) {
+        qemu_system_suspend();
+    }
     if (qemu_shutdown_requested()) {
         qemu_kill_report();
         monitor_protocol_event(QEVENT_SHUTDOWN, NULL);