Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 3 additions & 24 deletions hf_xet/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion hf_xet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ tracing = "0.1"
# Unix-specific dependencies
[target.'cfg(unix)'.dependencies]
signal-hook = "0.3"
signal-hook-registry = "1.4"

# Windows-specific dependencies
[target.'cfg(windows)'.dependencies]
ctrlc = "3.4"
winapi = { version = "0.3", features = ["consoleapi", "wincon", "errhandlingapi"] }

[features]
default = ["no-default-cache"] # By default, hf_xet disables the disk cache.
Expand Down
58 changes: 49 additions & 9 deletions hf_xet/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,57 @@ fn install_sigint_handler() -> Result<(), MultithreadedRuntimeError> {
Ok(())
}

#[cfg(windows)]
extern "system" fn console_ctrl_handler(
ctrl_type: winapi::shared::minwindef::DWORD,
) -> winapi::shared::minwindef::BOOL {
use winapi::um::wincon;

// Only handle CTRL_C_EVENT
if ctrl_type == wincon::CTRL_C_EVENT {
// Check if we have active operations
let has_active_ops = {
let guard = MULTITHREADED_RUNTIME.read().unwrap();
if let Some((runtime_pid, ref runtime)) = *guard {
runtime_pid == std::process::id() && runtime.external_executor_count() > 0
} else {
false
}
};

if has_active_ops {
// We have active operations, handle it ourselves
SIGINT_DETECTED.store(true, Ordering::SeqCst);
winapi::shared::minwindef::TRUE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the key thing here. We always want to return FALSE. Returning true blocks the python signal handler from running as well.

} else {
// No active operations, let Python's handler (or default) handle it
// Return FALSE to continue handler chain
winapi::shared::minwindef::FALSE
}
} else {
// For other control events, let default handler process them
winapi::shared::minwindef::FALSE
}
}

#[cfg(windows)]
fn install_sigint_handler() -> Result<(), MultithreadedRuntimeError> {
// On Windows, use ctrlc crate.
// This sets a callback to run on Ctrl-C:
let sigint_detected_flag = SIGINT_DETECTED.clone();
ctrlc::set_handler(move || {
sigint_detected_flag.store(true, Ordering::SeqCst);
})
.map_err(|e| {
MultithreadedRuntimeError::Other(format!("Initialization Error: Unable to register SIGINT handler {e:?}"))
})?;
use winapi::um::consoleapi::SetConsoleCtrlHandler;
use winapi::um::wincon::CTRL_C_EVENT;

// Install our handler using Windows API directly (instead of ctrlc)
// Our handler checks if operations are active:
// - If active: handles Ctrl+C and returns TRUE (stops propagation)
// - If not active: returns FALSE (allows Python's handler or default to handle it)
// This way we don't need to save/restore Python's handler - we just delegate to it
unsafe {
if SetConsoleCtrlHandler(Some(console_ctrl_handler), winapi::shared::minwindef::TRUE) == 0 {
let error = winapi::um::errhandlingapi::GetLastError();
return Err(MultithreadedRuntimeError::Other(format!(
"Initialization Error: Unable to register SIGINT handler. Windows error: {error}"
)));
}
}
Ok(())
}

Expand Down
Loading