1+ use std:: ffi:: { c_uint, c_void} ;
2+ use std:: time:: Duration ;
3+ use once_cell:: sync:: Lazy ;
4+ use windows_sys:: Win32 :: Foundation :: { BOOL , ERROR_TIMEOUT , FALSE , TRUE } ;
5+ use crate :: common:: { get_timeout_time, now} ;
6+ use crate :: net:: EventLoops ;
7+ use crate :: syscall:: common:: reset_errno;
8+ use crate :: syscall:: set_errno;
9+
10+ #[ must_use]
11+ pub extern "system" fn WaitOnAddress (
12+ fn_ptr : Option < & extern "system" fn ( * const c_void , * const c_void , usize , c_uint ) -> BOOL > ,
13+ address : * const c_void ,
14+ compareaddress : * const c_void ,
15+ addresssize : usize ,
16+ dwmilliseconds : c_uint
17+ ) -> BOOL {
18+ static CHAIN : Lazy < WaitOnAddressSyscallFacade < NioWaitOnAddressSyscall < RawWaitOnAddressSyscall > > > =
19+ Lazy :: new ( Default :: default) ;
20+ CHAIN . WaitOnAddress ( fn_ptr, address, compareaddress, addresssize, dwmilliseconds)
21+ }
22+
23+ trait WaitOnAddressSyscall {
24+ extern "system" fn WaitOnAddress (
25+ & self ,
26+ fn_ptr : Option < & extern "system" fn ( * const c_void , * const c_void , usize , c_uint ) -> BOOL > ,
27+ address : * const c_void ,
28+ compareaddress : * const c_void ,
29+ addresssize : usize ,
30+ dwmilliseconds : c_uint
31+ ) -> BOOL ;
32+ }
33+
34+ impl_facade ! ( WaitOnAddressSyscallFacade , WaitOnAddressSyscall ,
35+ WaitOnAddress (
36+ address: * const c_void,
37+ compareaddress: * const c_void,
38+ addresssize: usize ,
39+ dwmilliseconds: c_uint
40+ ) -> BOOL
41+ ) ;
42+
43+ #[ repr( C ) ]
44+ #[ derive( Debug , Default ) ]
45+ struct NioWaitOnAddressSyscall < I : WaitOnAddressSyscall > {
46+ inner : I ,
47+ }
48+
49+ impl < I : WaitOnAddressSyscall > WaitOnAddressSyscall for NioWaitOnAddressSyscall < I > {
50+ extern "system" fn WaitOnAddress (
51+ & self ,
52+ fn_ptr : Option < & extern "system" fn ( * const c_void , * const c_void , usize , c_uint ) -> BOOL > ,
53+ address : * const c_void ,
54+ compareaddress : * const c_void ,
55+ addresssize : usize ,
56+ dwmilliseconds : c_uint
57+ ) -> BOOL {
58+ let timeout = get_timeout_time ( Duration :: from_millis ( dwmilliseconds. into ( ) ) ) ;
59+ loop {
60+ let mut left_time = timeout. saturating_sub ( now ( ) ) ;
61+ if 0 == left_time {
62+ set_errno ( ERROR_TIMEOUT ) ;
63+ return FALSE ;
64+ }
65+ let r = self . inner . WaitOnAddress (
66+ fn_ptr,
67+ address,
68+ compareaddress,
69+ addresssize,
70+ ( left_time / 1_000_000 ) . min ( 1 ) . try_into ( ) . expect ( "overflow" ) ,
71+ ) ;
72+ if TRUE == r {
73+ reset_errno ( ) ;
74+ return r;
75+ }
76+ left_time = timeout. saturating_sub ( now ( ) ) ;
77+ if 0 == left_time {
78+ set_errno ( ERROR_TIMEOUT ) ;
79+ return FALSE ;
80+ }
81+ let wait_time = if left_time > 10_000_000 {
82+ 10_000_000
83+ } else {
84+ left_time
85+ } ;
86+ if EventLoops :: wait_event ( Some ( Duration :: new (
87+ wait_time / 1_000_000_000 ,
88+ ( wait_time % 1_000_000_000 ) as _ ,
89+ ) ) )
90+ . is_err ( )
91+ {
92+ return r;
93+ }
94+ }
95+ }
96+ }
97+
98+ impl_raw ! ( RawWaitOnAddressSyscall , WaitOnAddressSyscall , windows_sys:: Win32 :: System :: Threading ,
99+ WaitOnAddress (
100+ address: * const c_void,
101+ compareaddress: * const c_void,
102+ addresssize: usize ,
103+ dwmilliseconds: c_uint
104+ ) -> BOOL
105+ ) ;
0 commit comments