diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2012-02-23 13:45:19 +0100 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-02-24 13:36:02 -0600 |
commit | 95b363b5c643d8ad81c5377726e753b84c909037 (patch) | |
tree | 59cf3cd9d5f38ef3027cf58669ea9110b3fd7a80 | |
parent | 8283c4f565a26b3415961c481d980310c83dd2b4 (diff) |
suspend: add infrastructure
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>
-rw-r--r-- | sysemu.h | 9 | ||||
-rw-r--r-- | vl.c | 67 |
2 files changed, 76 insertions, 0 deletions
@@ -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); @@ -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); |