devices/
suspendable.rs

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
7use anyhow::anyhow;
8use serde::Deserialize;
9use serde::Serialize;
10use snapshot::AnySnapshot;
11
12#[derive(Copy, Clone, Serialize, Deserialize)]
13pub 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.
20pub 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]
62macro_rules! suspendable_tests {
63    ($name:ident, $dev:expr, $modfun:ident) => {
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}