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