Skip to content

Commit eb72865

Browse files
committed
Change: Simplified guard. No scope selection and added error types
1 parent 7526f8b commit eb72865

File tree

2 files changed

+44
-57
lines changed

2 files changed

+44
-57
lines changed

av1an-core/src/sleep_guard.rs

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Cross-platform sleep inhibition guard (maximized safety).
1+
//! Cross-platform sleep inhibition guard.
22
//
33
//! This module exposes a small RAII guard that prevents the system (or just
44
//! the idle subsystem) from going to sleep while it is alive.
@@ -13,16 +13,14 @@
1313
//!
1414
//! Drop the guard to release the inhibition.
1515
16-
/// What to keep awake.
17-
#[derive(Clone, Copy, Debug)]
18-
pub enum Scope {
19-
/// Block system sleep (idle suspend). On Linux this maps to `"sleep"`;
20-
/// on macOS this uses a system/idle assertion; on Windows it sets
21-
/// `ES_SYSTEM_REQUIRED`.
22-
System,
23-
/// Block *idle* actions only (no suspend; mostly screen blank, idle sleep).
24-
/// On Linux this maps to `"idle"`.
25-
IdleOnly,
16+
#[derive(Debug, thiserror::Error)]
17+
pub enum SleepInhibitError {
18+
#[error("D-Bus connection failed: {0}")]
19+
DBusConnection(#[from] dbus::Error),
20+
#[error("Power management API failed: {0}")]
21+
PowerManagement(String),
22+
#[error("Sleep inhibition not supported on this platform")]
23+
UnsupportedPlatform,
2624
}
2725

2826
/// RAII guard that holds a platform-specific sleep inhibition.
@@ -34,24 +32,23 @@ pub struct SleepGuard {
3432
impl SleepGuard {
3533
/// Acquire a system sleep inhibitor.
3634
///
37-
/// `app` is the application name presented to the OS, and `why` is a human
38-
/// readable reason.
35+
/// `app` is the application name presented to the OS, and `why` is a human readable reason.
3936
#[inline]
40-
pub fn acquire(scope: Scope, app: &str, why: &str) -> anyhow::Result<Self> {
37+
pub fn acquire(app: &str, why: &str) -> anyhow::Result<Self> {
4138
Ok(Self {
42-
_guard: PlatformGuard::acquire(scope, app, why)?,
39+
_guard: PlatformGuard::acquire(app, why)?,
4340
})
4441
}
4542

4643
/// Acquire using a default app name (the current executable name) and a
4744
/// generic reason.
4845
#[inline]
49-
pub fn acquire_default(scope: Scope) -> anyhow::Result<Self> {
46+
pub fn acquire_default() -> anyhow::Result<Self> {
5047
let app = std::env::current_exe()
5148
.ok()
5249
.and_then(|p| p.file_name().map(|s| s.to_string_lossy().into_owned()))
5350
.unwrap_or_else(|| "app".into());
54-
Self::acquire(scope, &app, "prevent system sleep")
51+
Self::acquire(&app, "prevent system sleep")
5552
}
5653
}
5754

@@ -67,20 +64,18 @@ enum PlatformGuard {
6764

6865
impl PlatformGuard {
6966
#[inline]
70-
fn acquire(scope: Scope, app: &str, why: &str) -> anyhow::Result<Self> {
67+
fn acquire(app: &str, why: &str) -> anyhow::Result<Self> {
7168
#[cfg(target_os = "linux")]
7269
{
73-
return Ok(Self::Linux(linux_impl::LinuxGuard::new(scope, app, why)?));
70+
return Ok(Self::Linux(linux_impl::LinuxGuard::new(app, why)?));
7471
}
7572
#[cfg(target_os = "windows")]
7673
{
77-
return Ok(Self::Windows(windows_impl::WindowsGuard::new(
78-
scope, app, why,
79-
)?));
74+
return Ok(Self::Windows(windows_impl::WindowsGuard::new(app, why)?));
8075
}
8176
#[cfg(target_os = "macos")]
8277
{
83-
return Ok(Self::Mac(mac_impl::MacGuard::new(scope, app, why)?));
78+
return Ok(Self::Mac(mac_impl::MacGuard::new(app, why)?));
8479
}
8580

8681
#[allow(unreachable_code)]
@@ -101,29 +96,23 @@ mod linux_impl {
10196
}
10297

10398
impl LinuxGuard {
104-
pub fn new(scope: Scope, app_name: &str, reason: &str) -> anyhow::Result<Self> {
105-
let conn = Connection::new_system()?;
99+
pub fn new(app_name: &str, reason: &str) -> Result<Self, SleepInhibitError> {
100+
let conn = Connection::new_system()
101+
.map_err(|e| SleepInhibitError::DBusConnection(e))?;
102+
106103
let proxy = conn.with_proxy(
107104
"org.freedesktop.login1",
108105
"/org/freedesktop/login1",
109106
std::time::Duration::from_secs(5),
110107
);
111108

112-
let what = match scope {
113-
Scope::System => "sleep",
114-
Scope::IdleOnly => "idle",
115-
};
116-
117-
// Call Inhibit(what, who, why, mode) -> unix fd (OwnedFd closes on drop).
118109
let (fd,): (OwnedFd,) = proxy.method_call(
119110
"org.freedesktop.login1.Manager",
120111
"Inhibit",
121-
(what, app_name, reason, "block"),
122-
)?;
112+
("sleep", app_name, reason, "block"),
113+
).map_err(|e| SleepInhibitError::DBusConnection(e))?;
123114

124-
Ok(Self {
125-
_fd: fd
126-
})
115+
Ok(Self { _fd: fd })
127116
}
128117
}
129118
}
@@ -135,27 +124,21 @@ mod windows_impl {
135124
pub struct WindowsGuard;
136125

137126
impl WindowsGuard {
138-
pub fn new(scope: Scope, _app: &str, _reason: &str) -> anyhow::Result<Self> {
127+
pub fn new(_app: &str, _reason: &str) -> Result<Self, SleepInhibitError>
128+
{
139129
// Map scope to execution state flags.
140130
// ES_CONTINUOUS is always set to make the request sticky for this call.
141131
const ES_CONTINUOUS: u32 = 0x80000000;
142132
const ES_SYSTEM_REQUIRED: u32 = 0x00000001;
143-
const ES_DISPLAY_REQUIRED: u32 = 0x00000002;
144-
145-
let mut flags: u32 = ES_CONTINUOUS;
146-
match scope {
147-
Scope::System => {
148-
flags |= ES_SYSTEM_REQUIRED;
149-
},
150-
Scope::IdleOnly => {
151-
flags |= ES_DISPLAY_REQUIRED;
152-
},
153-
}
133+
134+
let flags: u32 = ES_CONTINUOUS | ES_SYSTEM_REQUIRED;
154135

155136
// SAFETY: Calling documented Windows API with constant flags.
156137
let prev = unsafe { windows_sys::Win32::System::Power::SetThreadExecutionState(flags) };
157138
if prev == 0 {
158-
return Err(anyhow::anyhow!("SetThreadExecutionState failed"));
139+
return Err(SleepInhibitError::PowerManagement(
140+
"SetThreadExecutionState failed".into()
141+
));
159142
}
160143
Ok(Self)
161144
}
@@ -206,12 +189,8 @@ mod mac_impl {
206189
}
207190

208191
impl MacGuard {
209-
pub fn new(scope: Scope, _app: &str, why: &str) -> anyhow::Result<Self> {
210-
// Map scope to IOPM assertion type.
211-
let assertion_type = match scope {
212-
Scope::System => "NoIdleSleepAssertion",
213-
Scope::IdleOnly => "NoDisplaySleepAssertion",
214-
};
192+
pub fn new(_app: &str, why: &str) -> anyhow::Result<Self> {
193+
let assertion_type = "NoIdleSleepAssertion";
215194

216195
let mut id: IOPMAssertionID = 0;
217196
// SAFETY: FFI call with well-formed CFStrings that live across the call.

av1an/src/main.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use av1an_core::{
1313
hash_path,
1414
into_vec,
1515
read_in_dir,
16-
sleep_guard::{Scope, SleepGuard},
16+
sleep_guard::SleepGuard,
1717
vapoursynth::{get_vapoursynth_plugins, VSZipVersion},
1818
Av1anContext,
1919
ChunkMethod,
@@ -1228,7 +1228,15 @@ pub fn run() -> anyhow::Result<()> {
12281228
let args = parse_cli(cli_options)?;
12291229

12301230
// enable keep awake during encodes
1231-
let _guard = SleepGuard::acquire(Scope::System, "av1an", "Encoding video")?;
1231+
let mut _guard;
1232+
match SleepGuard::acquire("av1an", "Encoding video") {
1233+
Ok(guard) => {
1234+
_guard = guard;
1235+
}
1236+
Err(e) => {
1237+
println!("Failed to inhibit sleep: {}. Continuing without sleep inhibition.", e);
1238+
}
1239+
}
12321240

12331241
for arg in args {
12341242
Av1anContext::new(arg)?.encode_file()?;

0 commit comments

Comments
 (0)