1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Trait to suspend virtual hardware.
use anyhow::anyhow;
use serde::Deserialize;
use serde::Serialize;
#[derive(Copy, Clone, Serialize, Deserialize)]
pub enum DeviceState {
Awake,
Sleep,
}
/// This trait provides the functions required for a device to implement to successfully
/// suspend/resume in crosvm.
pub trait Suspendable {
/// Save the device state in an image that can be restored.
fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
Err(anyhow!(
"Suspendable::snapshot not implemented for {}",
std::any::type_name::<Self>()
))
}
/// Load a saved snapshot of an image.
fn restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()> {
Err(anyhow!(
"Suspendable::restore not implemented for {}",
std::any::type_name::<Self>()
))
}
/// Stop all threads related to the device.
/// Sleep should be idempotent.
fn sleep(&mut self) -> anyhow::Result<()> {
Err(anyhow!(
"Suspendable::sleep not implemented for {}",
std::any::type_name::<Self>()
))
}
/// Create/Resume all threads related to the device.
/// Wake should be idempotent.
fn wake(&mut self) -> anyhow::Result<()> {
Err(anyhow!(
"Suspendable::wake not implemented for {}",
std::any::type_name::<Self>()
))
}
}
// General tests that should pass on all suspendables.
// Do implement device-specific tests to validate the functionality of the device.
// Those tests are not a replacement for regular tests. Only an extension specific to the trait's
// basic functionality.
/// `dev` is the device.
/// `modfun` is the function name of the function that would modify the device. The function call
/// should modify the device so that a snapshot taken after the function call would be different
/// from a snapshot taken before the function call.
#[macro_export]
macro_rules! suspendable_tests {
($name:ident, $dev:expr, $modfun:ident) => {
mod $name {
use super::*;
#[test]
fn test_sleep_idempotent() {
let unit = &mut $dev;
let res = unit.sleep();
let res2 = unit.sleep();
match res {
Ok(()) => (),
Err(e) => println!("{}", e),
}
match res2 {
Ok(()) => (),
Err(e) => println!("idempotent: {}", e),
}
}
#[test]
fn test_snapshot_restore() {
let unit = &mut $dev;
let snap = unit.snapshot();
match snap {
Ok(snap_res) => {
let res = unit.restore(snap_res);
match res {
Ok(()) => (),
Err(e) => println!("{}", e),
}
}
Err(e) => println!("{}", e),
}
}
#[test]
fn test_sleep_snapshot() {
let unit = &mut $dev;
let sleep_result = unit.sleep();
let snap_result = unit.snapshot();
match sleep_result {
Ok(()) => (),
Err(e) => println!("{}", e),
}
match snap_result {
Ok(_res) => (),
Err(e) => println!("{}", e),
}
}
#[test]
fn test_sleep_snapshot_restore_wake() {
let unit = &mut $dev;
let sleep_result = unit.sleep();
let snap_result = unit.snapshot();
match sleep_result {
Ok(()) => (),
Err(e) => println!("{}", e),
}
match snap_result {
Ok(snap_res) => {
let res = unit.restore(snap_res);
match res {
Ok(()) => (),
Err(e) => println!("{}", e),
}
}
Err(e) => println!("{}", e),
}
let wake_res = unit.wake();
match wake_res {
Ok(()) => (),
Err(e) => println!("{}", e),
}
}
#[test]
fn test_sleep_snapshot_wake() {
let unit = &mut $dev;
let sleep_result = unit.sleep();
let snap_result = unit.snapshot();
match sleep_result {
Ok(()) => (),
Err(e) => println!("{}", e),
}
match snap_result {
Ok(_snap_res) => (),
Err(e) => println!("{}", e),
}
let wake_res = unit.wake();
match wake_res {
Ok(()) => (),
Err(e) => println!("{}", e),
}
}
#[test]
fn test_snapshot() {
let unit = &mut $dev;
let snap_result = unit.snapshot();
match snap_result {
Ok(_snap_res) => (),
Err(e) => println!("{}", e),
}
}
#[test]
fn test_suspend_mod_restore() {
let unit = &mut $dev;
let snap_result = unit.snapshot().expect("failed to take initial snapshot");
$modfun(unit);
unit.restore(snap_result.clone())
.expect("failed to restore snapshot");
let snap2_result = unit
.snapshot()
.expect("failed to take snapshot after modification");
assert_eq!(snap_result, snap2_result);
}
#[test]
fn test_suspend_mod() {
let unit = &mut $dev;
let snap_result = unit.snapshot().expect("failed to take initial snapshot");
$modfun(unit);
let snap2_result = unit
.snapshot()
.expect("failed to take snapshot after modification");
assert_ne!(snap_result, snap2_result)
}
}
};
}