aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sysemu.h9
-rw-r--r--vl.c67
2 files changed, 76 insertions, 0 deletions
diff --git a/sysemu.h b/sysemu.h
index 9d5ce3398f..af7381380e 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 cd77852236..90baa2a62b 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);