@@ -49,20 +49,46 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan
49
49
Thread currentThread = Thread . CurrentThread ;
50
50
currentThread . SetWaitSleepJoinState ( ) ;
51
51
52
- #if NATIVEAOT
53
- int result ;
54
- if ( reentrantWait )
52
+ long startTime = 0 ;
53
+ if ( millisecondsTimeout != - 1 )
55
54
{
56
- Debug . Assert ( ! waitAll ) ;
57
- result = RuntimeImports . RhCompatibleReentrantWaitAny ( false , millisecondsTimeout , numHandles , pHandles ) ;
55
+ startTime = Environment . TickCount64 ;
58
56
}
59
- else
57
+
58
+ int result ;
59
+ while ( true )
60
60
{
61
- result = ( int ) Interop . Kernel32 . WaitForMultipleObjectsEx ( ( uint ) numHandles , ( IntPtr ) pHandles , waitAll ? Interop . BOOL . TRUE : Interop . BOOL . FALSE , ( uint ) millisecondsTimeout , Interop . BOOL . FALSE ) ;
62
- }
61
+ #if NATIVEAOT
62
+ if ( reentrantWait )
63
+ {
64
+ Debug . Assert ( ! waitAll ) ;
65
+ result = RuntimeImports . RhCompatibleReentrantWaitAny ( true , millisecondsTimeout , numHandles , pHandles ) ;
66
+ }
67
+ else
68
+ {
69
+ result = ( int ) Interop . Kernel32 . WaitForMultipleObjectsEx ( ( uint ) numHandles , ( IntPtr ) pHandles , waitAll ? Interop . BOOL . TRUE : Interop . BOOL . FALSE , ( uint ) millisecondsTimeout , Interop . BOOL . TRUE ) ;
70
+ }
63
71
#else
64
- int result = ( int ) Interop . Kernel32 . WaitForMultipleObjectsEx ( ( uint ) numHandles , ( IntPtr ) pHandles , waitAll ? Interop . BOOL . TRUE : Interop . BOOL . FALSE , ( uint ) millisecondsTimeout , Interop . BOOL . FALSE ) ;
72
+ result = ( int ) Interop . Kernel32 . WaitForMultipleObjectsEx ( ( uint ) numHandles , ( IntPtr ) pHandles , waitAll ? Interop . BOOL . TRUE : Interop . BOOL . FALSE , ( uint ) millisecondsTimeout , Interop . BOOL . TRUE ) ;
65
73
#endif
74
+
75
+ if ( result != Interop . Kernel32 . WAIT_IO_COMPLETION )
76
+ break ;
77
+
78
+ // Handle APC completion by adjusting timeout and retrying
79
+ if ( millisecondsTimeout != - 1 )
80
+ {
81
+ long currentTime = Environment . TickCount64 ;
82
+ long elapsed = currentTime - startTime ;
83
+ if ( elapsed >= millisecondsTimeout )
84
+ {
85
+ result = Interop . Kernel32 . WAIT_TIMEOUT ;
86
+ break ;
87
+ }
88
+ millisecondsTimeout -= ( int ) elapsed ;
89
+ startTime = currentTime ;
90
+ }
91
+ }
66
92
currentThread . ClearWaitSleepJoinState ( ) ;
67
93
68
94
if ( result == Interop . Kernel32 . WAIT_FAILED )
@@ -102,8 +128,35 @@ private static int SignalAndWaitCore(IntPtr handleToSignal, IntPtr handleToWaitO
102
128
{
103
129
Debug . Assert ( millisecondsTimeout >= - 1 ) ;
104
130
105
- int ret = ( int ) Interop . Kernel32 . SignalObjectAndWait ( handleToSignal , handleToWaitOn , ( uint ) millisecondsTimeout , Interop . BOOL . FALSE ) ;
131
+ long startTime = 0 ;
132
+ if ( millisecondsTimeout != - 1 )
133
+ {
134
+ startTime = Environment . TickCount64 ;
135
+ }
136
+
137
+ // Signal the object and wait for the first time
138
+ int ret = ( int ) Interop . Kernel32 . SignalObjectAndWait ( handleToSignal , handleToWaitOn , ( uint ) millisecondsTimeout , Interop . BOOL . TRUE ) ;
139
+
140
+ // Handle APC completion by retrying with WaitForSingleObjectEx (without signaling again)
141
+ while ( ret == Interop . Kernel32 . WAIT_IO_COMPLETION )
142
+ {
143
+ if ( millisecondsTimeout != - 1 )
144
+ {
145
+ long currentTime = Environment . TickCount64 ;
146
+ long elapsed = currentTime - startTime ;
106
147
148
+ if ( elapsed >= millisecondsTimeout )
149
+ {
150
+ ret = Interop . Kernel32 . WAIT_TIMEOUT ;
151
+ break ;
152
+ }
153
+ millisecondsTimeout -= ( int ) elapsed ;
154
+ startTime = currentTime ;
155
+ }
156
+
157
+ // For retries, only wait on the handle (don't signal again)
158
+ ret = ( int ) Interop . Kernel32 . WaitForSingleObjectEx ( handleToWaitOn , ( uint ) millisecondsTimeout , Interop . BOOL . TRUE ) ;
159
+ }
107
160
if ( ret == Interop . Kernel32 . WAIT_FAILED )
108
161
{
109
162
ThrowWaitFailedException ( Interop . Kernel32 . GetLastError ( ) ) ;
0 commit comments