suspend: add infrastructure
authorGerd Hoffmann <kraxel@redhat.com>
Thu, 23 Feb 2012 12:45:19 +0000 (13:45 +0100)
committerAnthony Liguori <aliguori@us.ibm.com>
Fri, 24 Feb 2012 19:36:02 +0000 (13:36 -0600)
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>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
sysemu.h
vl.c

index 9d5ce3398f281c20bf356162a99f25e23e47ace5..af7381380e8c3648d0e4e6fbfea90a5284f13e0c 100644 (file)
--- 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 cd778522366eac1f93c716fe2c4141e2d0303eb3..90baa2a62b712bce5c9c711e0ff208676415ea09 100644 (file)
--- 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);