mirror of
https://github.com/esp-rs/espflash.git
synced 2026-03-10 15:50:30 +00:00
[MacOS]: Fix hanging terminal (#947)
* fix: Monitor hang for macos * docs: Update changelog
This commit is contained in:
parent
23c7419585
commit
ac5fc82837
@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
|
||||
- [Windows] Fixed a crash in monitor when espflash is connected via USB Serial/JTAG, and the user is typing into the monitor but the device is not reading serial input. (#943)
|
||||
- [Linux] Fixed espflash hanging when espflash is connected via USB Serial/JTAG, and the user is typing into the monitor but the device is not reading serial input. (#944)
|
||||
- [Linux/MacOS] Fixed espflash hanging when espflash is connected via USB Serial/JTAG, and the user is typing into the monitor but the device is not reading serial input. (#944, #945)
|
||||
|
||||
|
||||
### Removed
|
||||
|
||||
|
||||
@ -177,6 +177,8 @@ impl InputHandler {
|
||||
self.flush_deadline = None;
|
||||
#[cfg(target_os = "linux")]
|
||||
let _timer = linux::arm_timeout_workaround(Duration::from_millis(100));
|
||||
#[cfg(target_os = "macos")]
|
||||
let _timer = macos::arm_timeout_workaround(Duration::from_millis(100));
|
||||
serial.flush().ignore_timeout().into_diagnostic()?;
|
||||
}
|
||||
|
||||
@ -292,6 +294,74 @@ mod linux {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos {
|
||||
use std::time::Duration;
|
||||
|
||||
use libc::{self, ITIMER_REAL, SIGALRM, c_int, itimerval, sigaction, sigemptyset, timeval};
|
||||
|
||||
pub struct Workaround {
|
||||
previous_action: sigaction,
|
||||
previous_timer: itimerval,
|
||||
}
|
||||
|
||||
impl Drop for Workaround {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// Restore previous signal action
|
||||
libc::sigaction(SIGALRM, &self.previous_action, std::ptr::null_mut());
|
||||
|
||||
// Restore previous timer (or cancel if none was set)
|
||||
libc::setitimer(ITIMER_REAL, &self.previous_timer, std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a one-shot interval timer that will deliver SIGALRM after
|
||||
/// `timeout`. The timer and signal handler are restored when the
|
||||
/// returned object is dropped.
|
||||
pub fn arm_timeout_workaround(timeout: Duration) -> Workaround {
|
||||
unsafe extern "C" fn handle_signal(_signal: c_int) {}
|
||||
|
||||
unsafe {
|
||||
// Install a simple handler for SIGALRM and capture the previous one
|
||||
let mut new_action: sigaction = std::mem::zeroed();
|
||||
sigemptyset(&mut new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
// On macOS, `sa_sigaction` is a function pointer stored as usize
|
||||
new_action.sa_sigaction = handle_signal as usize;
|
||||
|
||||
let mut old_action: sigaction = std::mem::zeroed();
|
||||
libc::sigaction(SIGALRM, &new_action, &mut old_action);
|
||||
|
||||
// Arm a one-shot real-time interval timer (ITIMER_REAL → SIGALRM)
|
||||
let timeout_tv = duration_to_timeval(timeout);
|
||||
let new_timer = itimerval {
|
||||
it_interval: timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
},
|
||||
it_value: timeout_tv,
|
||||
};
|
||||
|
||||
let mut old_timer: itimerval = std::mem::zeroed();
|
||||
libc::setitimer(ITIMER_REAL, &new_timer, &mut old_timer);
|
||||
|
||||
Workaround {
|
||||
previous_action: old_action,
|
||||
previous_timer: old_timer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn duration_to_timeval(d: Duration) -> timeval {
|
||||
timeval {
|
||||
tv_sec: d.as_secs() as libc::time_t,
|
||||
tv_usec: d.subsec_micros() as libc::suseconds_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ErrorExt {
|
||||
fn ignore_timeout(self) -> Self;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user