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