mirror of
https://github.com/openai/codex.git
synced 2026-04-29 17:06:51 +00:00
fix: simplify macOS sleep inhibitor FFI (#12340)
Summary - simplify the macOS sleep inhibitor FFI by replacing `dlopen` / `dlsym` / `transmute` with normal IOKit extern calls and `SAFETY` comments - switch to cfg-selected platform implementations (`imp::SleepInhibitor`) instead of `Box<dyn ...>` - check in minimal IOKit bindings generated with `bindgen` and include them from the macOS backend - enable direct IOKit linkage in Bazel macOS builds by registering `IOKit` in the Bazel `osx.framework(...)` toolchain extension list - update `Cargo.lock` and `MODULE.bazel.lock` after removing the build-time `bindgen` dependency path Testing - `just fmt` - `cargo clippy -p codex-utils-sleep-inhibitor --all-targets -- -D warnings` - `cargo test -p codex-utils-sleep-inhibitor` - `bazel test //codex-rs/utils/sleep-inhibitor:all --test_output=errors` - `just bazel-lock-update` - `just bazel-lock-check` Context - follow-up to #11711 addressing Ryan's review comments - `bindgen` is used to generate the checked-in bindings file, but not at build time
This commit is contained in:
committed by
GitHub
parent
fd67aba114
commit
5b71246001
107
codex-rs/utils/sleep-inhibitor/src/macos.rs
Normal file
107
codex-rs/utils/sleep-inhibitor/src/macos.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use core_foundation::base::TCFType;
|
||||
use core_foundation::string::CFString;
|
||||
use tracing::warn;
|
||||
|
||||
#[allow(
|
||||
dead_code,
|
||||
non_camel_case_types,
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
clippy::all
|
||||
)]
|
||||
mod iokit {
|
||||
#[link(name = "IOKit", kind = "framework")]
|
||||
unsafe extern "C" {}
|
||||
|
||||
include!("iokit_bindings.rs");
|
||||
}
|
||||
|
||||
type IOPMAssertionID = iokit::IOPMAssertionID;
|
||||
type IOPMAssertionLevel = iokit::IOPMAssertionLevel;
|
||||
type IOReturn = iokit::IOReturn;
|
||||
|
||||
const ASSERTION_REASON: &str = "Codex is running an active turn";
|
||||
// Apple exposes this assertion type as a `CFSTR(...)` macro, so bindgen cannot generate a
|
||||
// reusable `CFStringRef` constant for it.
|
||||
const ASSERTION_TYPE_PREVENT_USER_IDLE_SYSTEM_SLEEP: &str = "PreventUserIdleSystemSleep";
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct SleepInhibitor {
|
||||
assertion: Option<MacSleepAssertion>,
|
||||
}
|
||||
|
||||
impl SleepInhibitor {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub(crate) fn acquire(&mut self) {
|
||||
if self.assertion.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
match MacSleepAssertion::create(ASSERTION_REASON) {
|
||||
Ok(assertion) => {
|
||||
self.assertion = Some(assertion);
|
||||
}
|
||||
Err(error) => {
|
||||
warn!(
|
||||
iokit_error = error,
|
||||
"Failed to create macOS sleep-prevention assertion"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn release(&mut self) {
|
||||
self.assertion = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MacSleepAssertion {
|
||||
id: IOPMAssertionID,
|
||||
}
|
||||
|
||||
impl MacSleepAssertion {
|
||||
fn create(name: &str) -> Result<Self, IOReturn> {
|
||||
let assertion_type = CFString::new(ASSERTION_TYPE_PREVENT_USER_IDLE_SYSTEM_SLEEP);
|
||||
let assertion_name = CFString::new(name);
|
||||
let mut id: IOPMAssertionID = 0;
|
||||
// `core-foundation` and the generated bindings each declare an opaque `__CFString` type,
|
||||
// so we cast to the bindgen pointer aliases before crossing the FFI boundary.
|
||||
let assertion_type_ref: iokit::CFStringRef = assertion_type.as_concrete_TypeRef().cast();
|
||||
let assertion_name_ref: iokit::CFStringRef = assertion_name.as_concrete_TypeRef().cast();
|
||||
let result = unsafe {
|
||||
// SAFETY: `assertion_type_ref` and `assertion_name_ref` are valid `CFStringRef`s and
|
||||
// `&mut id` is a valid out-pointer for `IOPMAssertionCreateWithName` to initialize.
|
||||
iokit::IOPMAssertionCreateWithName(
|
||||
assertion_type_ref,
|
||||
iokit::kIOPMAssertionLevelOn as IOPMAssertionLevel,
|
||||
assertion_name_ref,
|
||||
&mut id,
|
||||
)
|
||||
};
|
||||
if result == iokit::kIOReturnSuccess as IOReturn {
|
||||
Ok(Self { id })
|
||||
} else {
|
||||
Err(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MacSleepAssertion {
|
||||
fn drop(&mut self) {
|
||||
let result = unsafe {
|
||||
// SAFETY: `self.id` was returned by `IOPMAssertionCreateWithName` and this `Drop`
|
||||
// implementation releases it exactly once when the owning assertion is dropped.
|
||||
iokit::IOPMAssertionRelease(self.id)
|
||||
};
|
||||
if result != iokit::kIOReturnSuccess as IOReturn {
|
||||
warn!(
|
||||
iokit_error = result,
|
||||
"Failed to release macOS sleep-prevention assertion"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user