Skip to content

Commit 8961365

Browse files
Fix hang on TTY read
In some cases, when a underlying error happens to a TTY port between poll::wait_read_fd and unistd::read, the read function would hang waiting for some data that is never received. This commit sets the port to non-canonical mode, with VMIN = VTIME = 0. With this change, it has the effect of making reads non-blocking, returning right away. The timeout behaviour is maintained, as prior to reading we call unix::poll through poll::wait_read_fd. Fixes: #7
1 parent 0a75184 commit 8961365

File tree

2 files changed

+12
-1
lines changed

2 files changed

+12
-1
lines changed

src/posix/termios.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{DataBits, FlowControl, Parity, Result, StopBits};
55
use nix::libc;
66

77
use std::os::unix::prelude::*;
8+
use std::time::Duration;
89

910
cfg_if! {
1011
if #[cfg(any(
@@ -183,6 +184,12 @@ pub(crate) fn set_flow_control(termios: &mut Termios, flow_control: FlowControl)
183184
};
184185
}
185186

187+
pub(crate) fn set_timeout(termios: &mut Termios, timeout: Duration) {
188+
let timeout = u128::min(timeout.as_millis() / 100, u8::MAX as u128) as u8;
189+
termios.c_cc[libc::VMIN as usize] = 0;
190+
termios.c_cc[libc::VTIME as usize] = timeout;
191+
}
192+
186193
pub(crate) fn set_data_bits(termios: &mut Termios, data_bits: DataBits) {
187194
let size = match data_bits {
188195
DataBits::Five => libc::CS5,

src/posix/tty.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ impl TTYPort {
134134
nix::errno::Errno::result(unsafe { tcgetattr(fd.0, termios.as_mut_ptr()) })?;
135135
let mut termios = unsafe { termios.assume_init() };
136136

137-
// setup TTY for binary serial port access
137+
// Setup TTY for binary serial port access
138+
// Enable non-canonical mode
139+
termios.c_lflag &= !libc::ICANON;
138140
// Enable reading from the port and ignore all modem control lines
139141
termios.c_cflag |= libc::CREAD | libc::CLOCAL;
140142
// Enable raw mode which disables any implicit processing of the input or output data streams
@@ -175,6 +177,8 @@ impl TTYPort {
175177
termios::set_flow_control(&mut termios, builder.flow_control);
176178
termios::set_data_bits(&mut termios, builder.data_bits);
177179
termios::set_stop_bits(&mut termios, builder.stop_bits);
180+
// Set termios read to non-blocking, as we handle blocking ourselves (with unix::poll)
181+
termios::set_timeout(&mut termios, Duration::from_millis(0));
178182
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
179183
termios::set_baud_rate(&mut termios, builder.baud_rate);
180184
#[cfg(any(target_os = "ios", target_os = "macos"))]

0 commit comments

Comments
 (0)