• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
15 use std::time::Duration;
16 use std::{cmp, io};
17 
18 use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
19 use windows_sys::Win32::System::IO::{
20     CreateIoCompletionPort, GetQueuedCompletionStatusEx, PostQueuedCompletionStatus, OVERLAPPED,
21     OVERLAPPED_ENTRY,
22 };
23 
24 use super::Handle;
25 use crate::sys::Overlapped;
26 use crate::{Event, Token};
27 
28 /// IOCP's HANDLE.
29 #[derive(Debug)]
30 pub(crate) struct CompletionPort {
31     handle: Handle,
32 }
33 
34 impl CompletionPort {
35     /// Creates a new CompletionPort
new() -> io::Result<CompletionPort>36     pub(crate) fn new() -> io::Result<CompletionPort> {
37         let handle = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) };
38         if handle == 0 {
39             Err(io::Error::last_os_error())
40         } else {
41             Ok(CompletionPort {
42                 handle: Handle::new(handle),
43             })
44         }
45     }
46     /// Add t to CompletionPort
add_handle<T: AsRawHandle + ?Sized>( &self, token: usize, t: &T, ) -> io::Result<()>47     pub(crate) fn add_handle<T: AsRawHandle + ?Sized>(
48         &self,
49         token: usize,
50         t: &T,
51     ) -> io::Result<()> {
52         syscall!(
53             CreateIoCompletionPort(t.as_raw_handle() as HANDLE, self.handle.raw(), token, 0),
54             ()
55         )
56     }
57 
58     /// Gets the completed events in the IOCP, and can get multiple events at
59     /// the same time. Return the set of completed events
get_results<'a>( &self, list: &'a mut [CompletionStatus], timeout: Option<Duration>, ) -> io::Result<&'a mut [CompletionStatus]>60     pub(crate) fn get_results<'a>(
61         &self,
62         list: &'a mut [CompletionStatus],
63         timeout: Option<Duration>,
64     ) -> io::Result<&'a mut [CompletionStatus]> {
65         let len = cmp::min(list.len(), u32::MAX as usize) as u32;
66         let mut removed = 0;
67         let timeout = match timeout {
68             Some(dur) => {
69                 let dur_ms = (dur + Duration::from_nanos(999_999)).as_millis();
70                 cmp::min(dur_ms, u32::MAX as u128) as u32
71             }
72             None => u32::MAX,
73         };
74 
75         syscall!(
76             GetQueuedCompletionStatusEx(
77                 self.handle.raw(),
78                 list.as_ptr() as *mut _,
79                 len,
80                 &mut removed,
81                 timeout,
82                 0,
83             ),
84             &mut list[..removed as usize]
85         )
86     }
87 
88     /// Posts an I/O completion packet to an I/O completion port.
post(&self, token: Token) -> io::Result<()>89     pub(crate) fn post(&self, token: Token) -> io::Result<()> {
90         let mut event = Event::new(token);
91         event.set_readable();
92 
93         let status = event.as_completion_status();
94         syscall!(
95             PostQueuedCompletionStatus(
96                 self.handle.raw(),
97                 status.0.dwNumberOfBytesTransferred,
98                 status.0.lpCompletionKey,
99                 status.0.lpOverlapped
100             ),
101             ()
102         )
103     }
104 }
105 
106 impl IntoRawHandle for CompletionPort {
into_raw_handle(self) -> RawHandle107     fn into_raw_handle(self) -> RawHandle {
108         self.handle.into_raw()
109     }
110 }
111 
112 /// Includes OVERLAPPED_ENTRY struct which contains operation result of IOCP
113 #[derive(Clone, Copy)]
114 pub struct CompletionStatus(OVERLAPPED_ENTRY);
115 
116 unsafe impl Send for CompletionStatus {}
117 unsafe impl Sync for CompletionStatus {}
118 
119 impl CompletionStatus {
120     /// Creates a new `CompletionStatus`.
new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> Self121     pub(crate) fn new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> Self {
122         CompletionStatus(OVERLAPPED_ENTRY {
123             dwNumberOfBytesTransferred: bytes,
124             lpCompletionKey: token,
125             lpOverlapped: overlapped as *mut _,
126             Internal: 0,
127         })
128     }
129 
130     /// Creates a CompletionStatus with 0.
zero() -> Self131     pub fn zero() -> Self {
132         Self::new(0, 0, std::ptr::null_mut())
133     }
134 
135     /// Returns dwNumberOfBytesTransferred of OVERLAPPED_ENTRY.
bytes_transferred(&self) -> u32136     pub fn bytes_transferred(&self) -> u32 {
137         self.0.dwNumberOfBytesTransferred
138     }
139 
140     /// Returns lpCompletionKey of OVERLAPPED_ENTRY.
token(&self) -> usize141     pub fn token(&self) -> usize {
142         self.0.lpCompletionKey
143     }
144 
145     /// Returns lpOverlapped of OVERLAPPED_ENTRY.
overlapped(&self) -> *mut OVERLAPPED146     pub fn overlapped(&self) -> *mut OVERLAPPED {
147         self.0.lpOverlapped
148     }
149 
150     /// Returns OVERLAPPED_ENTRY struct.
entry(&self) -> &OVERLAPPED_ENTRY151     pub fn entry(&self) -> &OVERLAPPED_ENTRY {
152         &self.0
153     }
154 }
155