Skip to content

Commit 636c881

Browse files
committed
Use overlapped IO for COM
1 parent 7dde076 commit 636c881

File tree

2 files changed

+111
-45
lines changed

2 files changed

+111
-45
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ regex = "1.5.5"
3434
version = "0.3.9"
3535
features = [
3636
"cguid", "commapi", "errhandlingapi", "fileapi", "guiddef", "handleapi", "minwinbase",
37-
"minwindef", "ntdef", "setupapi", "winbase", "winerror", "winnt",
37+
"minwindef", "ntdef", "setupapi", "winbase", "winerror", "winnt", "ioapiset", "synchapi"
3838
]
3939

4040
[dependencies]

src/windows/com.rs

Lines changed: 110 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,58 @@ use winapi::um::winbase::*;
1212
use winapi::um::winnt::{
1313
DUPLICATE_SAME_ACCESS, FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE,
1414
};
15+
use winapi::shared::winerror::{ERROR_IO_PENDING, ERROR_OPERATION_ABORTED};
16+
use winapi::shared::ntdef::NULL;
17+
use winapi::um::synchapi::CreateEventW;
18+
use winapi::um::minwinbase::OVERLAPPED;
19+
use winapi::um::ioapiset::GetOverlappedResult;
20+
use winapi::um::errhandlingapi::GetLastError;
1521

1622
use crate::windows::dcb;
1723
use crate::{
1824
ClearBuffer, DataBits, Error, ErrorKind, FlowControl, Parity, Result, SerialPort,
1925
SerialPortBuilder, StopBits,
2026
};
2127

28+
struct OverlappedHandle(pub HANDLE);
29+
30+
impl OverlappedHandle {
31+
#[inline]
32+
fn new() -> io::Result<Self> {
33+
match unsafe { CreateEventW(ptr::null_mut(), TRUE, FALSE, ptr::null_mut()) } {
34+
NULL => Err(io::Error::last_os_error()),
35+
handle => Ok(Self(handle))
36+
}
37+
}
38+
39+
#[inline]
40+
fn close(self) {
41+
//drop
42+
}
43+
44+
#[inline]
45+
fn create_overlapped(&self) -> OVERLAPPED {
46+
OVERLAPPED {
47+
Internal: 0,
48+
InternalHigh: 0,
49+
u: unsafe {
50+
MaybeUninit::zeroed().assume_init()
51+
},
52+
hEvent: self.0,
53+
}
54+
55+
}
56+
}
57+
58+
impl Drop for OverlappedHandle {
59+
#[inline(always)]
60+
fn drop(&mut self) {
61+
unsafe {
62+
CloseHandle(self.0);
63+
}
64+
}
65+
}
66+
2267
/// A serial port implementation for Windows COM ports
2368
///
2469
/// The port will be closed when the value is dropped. However, this struct
@@ -63,7 +108,7 @@ impl COMPort {
63108
0,
64109
ptr::null_mut(),
65110
OPEN_EXISTING,
66-
FILE_ATTRIBUTE_NORMAL,
111+
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
67112
0 as HANDLE,
68113
)
69114
};
@@ -105,27 +150,20 @@ impl COMPort {
105150
///
106151
/// This function returns an error if the serial port couldn't be cloned.
107152
pub fn try_clone_native(&self) -> Result<COMPort> {
108-
let process_handle: HANDLE = unsafe { GetCurrentProcess() };
109-
let mut cloned_handle: HANDLE = INVALID_HANDLE_VALUE;
110-
unsafe {
111-
DuplicateHandle(
112-
process_handle,
113-
self.handle,
114-
process_handle,
115-
&mut cloned_handle,
116-
0,
117-
TRUE,
118-
DUPLICATE_SAME_ACCESS,
119-
);
120-
if cloned_handle != INVALID_HANDLE_VALUE {
121-
Ok(COMPort {
122-
handle: cloned_handle,
123-
port_name: self.port_name.clone(),
124-
timeout: self.timeout,
125-
})
126-
} else {
127-
Err(super::error::last_os_error())
128-
}
153+
// duplicate communications device handle
154+
let mut duplicate_handle = INVALID_HANDLE_VALUE;
155+
let process = unsafe { GetCurrentProcess() };
156+
let res = unsafe {
157+
DuplicateHandle(process, self.handle, process, &mut duplicate_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)
158+
};
159+
160+
match res {
161+
0 => Err(super::error::last_os_error()),
162+
_ => Ok(COMPort {
163+
handle: duplicate_handle,
164+
port_name: self.port_name.clone(),
165+
timeout: self.timeout,
166+
})
129167
}
130168
}
131169

@@ -178,48 +216,76 @@ impl FromRawHandle for COMPort {
178216

179217
impl io::Read for COMPort {
180218
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
181-
let mut len: DWORD = 0;
219+
let mut read_size = buf.len();
220+
221+
let bytes_to_read = self.bytes_to_read()? as usize;
222+
223+
if self.timeout.as_millis() == 0 && bytes_to_read < read_size {
224+
read_size = bytes_to_read;
225+
}
226+
if read_size == 0 {
227+
return Ok(0);
228+
}
182229

183-
match unsafe {
230+
let evt_handle = OverlappedHandle::new()?;
231+
let mut overlapped = evt_handle.create_overlapped();
232+
let mut len: DWORD = 0;
233+
let read_result = unsafe {
184234
ReadFile(
185235
self.handle,
186236
buf.as_mut_ptr() as LPVOID,
187-
buf.len() as DWORD,
237+
read_size as DWORD,
188238
&mut len,
189-
ptr::null_mut(),
239+
&mut overlapped,
190240
)
191-
} {
192-
0 => Err(io::Error::last_os_error()),
193-
_ => {
194-
if len != 0 {
195-
Ok(len as usize)
196-
} else {
197-
Err(io::Error::new(
198-
io::ErrorKind::TimedOut,
199-
"Operation timed out",
200-
))
201-
}
202-
}
241+
};
242+
let last_error = unsafe { GetLastError() };
243+
if read_result == 0 && last_error != ERROR_IO_PENDING && last_error != ERROR_OPERATION_ABORTED {
244+
return Err(io::Error::last_os_error());
245+
}
246+
let overlapped_result = unsafe { GetOverlappedResult(self.handle, &mut overlapped, &mut len, TRUE) };
247+
evt_handle.close();
248+
let last_error = unsafe { GetLastError() };
249+
if overlapped_result == 0 && last_error != ERROR_OPERATION_ABORTED {
250+
return Err(io::Error::last_os_error());
251+
}
252+
if len != 0 {
253+
Ok(len as usize)
254+
} else {
255+
Err(io::Error::new(
256+
io::ErrorKind::TimedOut,
257+
"Operation timed out",
258+
))
203259
}
204260
}
205261
}
206262

207263
impl io::Write for COMPort {
208264
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
265+
let evt_handle = OverlappedHandle::new()?;
266+
let mut overlapped = evt_handle.create_overlapped();
209267
let mut len: DWORD = 0;
210-
211-
match unsafe {
268+
let write_result = unsafe {
212269
WriteFile(
213270
self.handle,
214271
buf.as_ptr() as LPVOID,
215272
buf.len() as DWORD,
216273
&mut len,
217-
ptr::null_mut(),
274+
&mut overlapped,
218275
)
219-
} {
220-
0 => Err(io::Error::last_os_error()),
221-
_ => Ok(len as usize),
276+
};
277+
let last_error = unsafe { GetLastError() };
278+
if write_result == 0 && last_error != ERROR_IO_PENDING && last_error != ERROR_OPERATION_ABORTED {
279+
return Err(io::Error::last_os_error());
280+
}
281+
let overlapped_result = unsafe { GetOverlappedResult(self.handle, &mut overlapped, &mut len, TRUE) };
282+
evt_handle.close();
283+
284+
let last_error = unsafe { GetLastError() };
285+
if overlapped_result == 0 && last_error != ERROR_OPERATION_ABORTED {
286+
return Err(io::Error::last_os_error());
222287
}
288+
Ok(len as usize)
223289
}
224290

225291
fn flush(&mut self) -> io::Result<()> {

0 commit comments

Comments
 (0)