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 super::Handle;
19 use crate::sys::winapi::{
20     CreateIoCompletionPort, GetQueuedCompletionStatusEx, PostQueuedCompletionStatus, HANDLE,
21     INVALID_HANDLE_VALUE, OVERLAPPED, OVERLAPPED_ENTRY,
22 };
23 use crate::sys::Overlapped;
24 use crate::{Event, Token};
25 
26 /// IOCP's HANDLE.
27 #[derive(Debug)]
28 pub(crate) struct CompletionPort {
29     handle: Handle,
30 }
31 
32 impl CompletionPort {
33     /// Creates a new CompletionPort
new() -> io::Result<CompletionPort>34     pub(crate) fn new() -> io::Result<CompletionPort> {
35         let handle = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) };
36         if handle == 0 {
37             Err(io::Error::last_os_error())
38         } else {
39             Ok(CompletionPort {
40                 handle: Handle::new(handle),
41             })
42         }
43     }
44     /// Add t to CompletionPort
add_handle<T: AsRawHandle + ?Sized>( &self, token: usize, t: &T, ) -> io::Result<()>45     pub(crate) fn add_handle<T: AsRawHandle + ?Sized>(
46         &self,
47         token: usize,
48         t: &T,
49     ) -> io::Result<()> {
50         syscall!(
51             CreateIoCompletionPort(t.as_raw_handle() as HANDLE, self.handle.raw(), token, 0),
52             ()
53         )
54     }
55 
56     /// Gets the completed events in the IOCP, and can get multiple events at
57     /// 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]>58     pub(crate) fn get_results<'a>(
59         &self,
60         list: &'a mut [CompletionStatus],
61         timeout: Option<Duration>,
62     ) -> io::Result<&'a mut [CompletionStatus]> {
63         let len = cmp::min(list.len(), u32::MAX as usize) as u32;
64         let mut removed = 0;
65         let timeout = match timeout {
66             Some(dur) => {
67                 let dur_ms = (dur + Duration::from_nanos(999_999)).as_millis();
68                 cmp::min(dur_ms, u32::MAX as u128) as u32
69             }
70             None => u32::MAX,
71         };
72 
73         syscall!(
74             GetQueuedCompletionStatusEx(
75                 self.handle.raw(),
76                 list.as_ptr() as *mut _,
77                 len,
78                 &mut removed,
79                 timeout,
80                 0,
81             ),
82             &mut list[..removed as usize]
83         )
84     }
85 
86     /// Posts an I/O completion packet to an I/O completion port.
post(&self, token: Token) -> io::Result<()>87     pub(crate) fn post(&self, token: Token) -> io::Result<()> {
88         let mut event = Event::new(token);
89         event.set_readable();
90 
91         let status = event.as_completion_status();
92         syscall!(
93             PostQueuedCompletionStatus(
94                 self.handle.raw(),
95                 status.0.dwNumberOfBytesTransferred,
96                 status.0.lpCompletionKey,
97                 status.0.lpOverlapped
98             ),
99             ()
100         )
101     }
102 }
103 
104 impl IntoRawHandle for CompletionPort {
into_raw_handle(self) -> RawHandle105     fn into_raw_handle(self) -> RawHandle {
106         self.handle.into_raw()
107     }
108 }
109 
110 /// Includes OVERLAPPED_ENTRY struct which contains operation result of IOCP
111 #[derive(Clone, Copy)]
112 pub struct CompletionStatus(OVERLAPPED_ENTRY);
113 
114 unsafe impl Send for CompletionStatus {}
115 unsafe impl Sync for CompletionStatus {}
116 
117 impl CompletionStatus {
118     /// Creates a new `CompletionStatus`.
new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> Self119     pub(crate) fn new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> Self {
120         CompletionStatus(OVERLAPPED_ENTRY {
121             dwNumberOfBytesTransferred: bytes,
122             lpCompletionKey: token,
123             lpOverlapped: overlapped.cast::<_>(),
124             Internal: 0,
125         })
126     }
127 
128     /// Creates a CompletionStatus with 0.
zero() -> Self129     pub fn zero() -> Self {
130         Self::new(0, 0, std::ptr::null_mut())
131     }
132 
133     /// Returns dwNumberOfBytesTransferred of OVERLAPPED_ENTRY.
bytes_transferred(&self) -> u32134     pub fn bytes_transferred(&self) -> u32 {
135         self.0.dwNumberOfBytesTransferred
136     }
137 
138     /// Returns lpCompletionKey of OVERLAPPED_ENTRY.
token(&self) -> usize139     pub fn token(&self) -> usize {
140         self.0.lpCompletionKey
141     }
142 
143     /// Returns lpOverlapped of OVERLAPPED_ENTRY.
overlapped(&self) -> *mut OVERLAPPED144     pub fn overlapped(&self) -> *mut OVERLAPPED {
145         self.0.lpOverlapped
146     }
147 
148     /// Returns OVERLAPPED_ENTRY struct.
entry(&self) -> &OVERLAPPED_ENTRY149     pub fn entry(&self) -> &OVERLAPPED_ENTRY {
150         &self.0
151     }
152 }
153