Skip to content

Commit e469619

Browse files
committed
Change: Simplified guard. No scope selection and added error types
1 parent c6e6cdd commit e469619

2 files changed

Lines changed: 48 additions & 55 deletions

File tree

av1an-core/src/sleep_guard.rs

Lines changed: 35 additions & 53 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.
@@ -37,21 +35,21 @@ impl SleepGuard {
3735
/// `app` is the application name presented to the OS, and `why` is a human
3836
/// readable reason.
3937
#[inline]
40-
pub fn acquire(scope: Scope, app: &str, why: &str) -> anyhow::Result<Self> {
38+
pub fn acquire(app: &str, why: &str) -> anyhow::Result<Self> {
4139
Ok(Self {
42-
_guard: PlatformGuard::acquire(scope, app, why)?,
40+
_guard: PlatformGuard::acquire(app, why)?,
4341
})
4442
}
4543

4644
/// Acquire using a default app name (the current executable name) and a
4745
/// generic reason.
4846
#[inline]
49-
pub fn acquire_default(scope: Scope) -> anyhow::Result<Self> {
47+
pub fn acquire_default() -> anyhow::Result<Self> {
5048
let app = std::env::current_exe()
5149
.ok()
5250
.and_then(|p| p.file_name().map(|s| s.to_string_lossy().into_owned()))
5351
.unwrap_or_else(|| "app".into());
54-
Self::acquire(scope, &app, "prevent system sleep")
52+
Self::acquire(&app, "prevent system sleep")
5553
}
5654
}
5755

@@ -67,20 +65,18 @@ enum PlatformGuard {
6765

6866
impl PlatformGuard {
6967
#[inline]
70-
fn acquire(scope: Scope, app: &str, why: &str) -> anyhow::Result<Self> {
68+
fn acquire(app: &str, why: &str) -> anyhow::Result<Self> {
7169
#[cfg(target_os = "linux")]
7270
{
73-
return Ok(Self::Linux(linux_impl::LinuxGuard::new(scope, app, why)?));
71+
return Ok(Self::Linux(linux_impl::LinuxGuard::new(app, why)?));
7472
}
7573
#[cfg(target_os = "windows")]
7674
{
77-
return Ok(Self::Windows(windows_impl::WindowsGuard::new(
78-
scope, app, why,
79-
)?));
75+
return Ok(Self::Windows(windows_impl::WindowsGuard::new(app, why)?));
8076
}
8177
#[cfg(target_os = "macos")]
8278
{
83-
return Ok(Self::Mac(mac_impl::MacGuard::new(scope, app, why)?));
79+
return Ok(Self::Mac(mac_impl::MacGuard::new(app, why)?));
8480
}
8581

8682
#[allow(unreachable_code)]
@@ -101,25 +97,22 @@ mod linux_impl {
10197
}
10298

10399
impl LinuxGuard {
104-
pub fn new(scope: Scope, app_name: &str, reason: &str) -> anyhow::Result<Self> {
105-
let conn = Connection::new_system()?;
100+
pub fn new(app_name: &str, reason: &str) -> Result<Self, SleepInhibitError> {
101+
let conn = Connection::new_system().map_err(SleepInhibitError::DBusConnection)?;
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).
118-
let (fd,): (OwnedFd,) = proxy.method_call(
119-
"org.freedesktop.login1.Manager",
120-
"Inhibit",
121-
(what, app_name, reason, "block"),
122-
)?;
109+
let (fd,): (OwnedFd,) = proxy
110+
.method_call(
111+
"org.freedesktop.login1.Manager",
112+
"Inhibit",
113+
("sleep", app_name, reason, "block"),
114+
)
115+
.map_err(SleepInhibitError::DBusConnection)?;
123116

124117
Ok(Self {
125118
_fd: fd
@@ -135,27 +128,20 @@ mod windows_impl {
135128
pub struct WindowsGuard;
136129

137130
impl WindowsGuard {
138-
pub fn new(scope: Scope, _app: &str, _reason: &str) -> anyhow::Result<Self> {
131+
pub fn new(_app: &str, _reason: &str) -> Result<Self, SleepInhibitError> {
139132
// Map scope to execution state flags.
140133
// ES_CONTINUOUS is always set to make the request sticky for this call.
141134
const ES_CONTINUOUS: u32 = 0x80000000;
142135
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-
}
136+
137+
let flags: u32 = ES_CONTINUOUS | ES_SYSTEM_REQUIRED;
154138

155139
// SAFETY: Calling documented Windows API with constant flags.
156140
let prev = unsafe { windows_sys::Win32::System::Power::SetThreadExecutionState(flags) };
157141
if prev == 0 {
158-
return Err(anyhow::anyhow!("SetThreadExecutionState failed"));
142+
return Err(SleepInhibitError::PowerManagement(
143+
"SetThreadExecutionState failed".into(),
144+
));
159145
}
160146
Ok(Self)
161147
}
@@ -206,12 +192,8 @@ mod mac_impl {
206192
}
207193

208194
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-
};
195+
pub fn new(_app: &str, why: &str) -> anyhow::Result<Self> {
196+
let assertion_type = "NoIdleSleepAssertion";
215197

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

av1an/src/main.rs

Lines changed: 13 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,18 @@ 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!(
1238+
"Failed to inhibit sleep: {}. Continuing without sleep inhibition.",
1239+
e
1240+
);
1241+
},
1242+
}
12321243

12331244
for arg in args {
12341245
Av1anContext::new(arg)?.encode_file()?;

0 commit comments

Comments
 (0)