1515#include "mono-error-internals.h"
1616#include <mono/utils/checked-build.h>
1717#include <mono/utils/w32subset.h>
18+ #include <mono/utils/mono-time.h>
1819
1920/* Empty handler only used to detect interrupt state of current thread. */
2021/* Needed in order to correctly avoid entering wait methods under */
@@ -61,22 +62,23 @@ win32_wait_interrupt_handler (gpointer ignored)
6162#define WIN32_ENTER_ALERTABLE_WAIT (info ) \
6263 do { \
6364 if (info) { \
64- gboolean alerted = FALSE; \
65- mono_thread_info_install_interrupt (win32_wait_interrupt_handler, NULL, &alerted ); \
66- if (alerted ) { \
65+ gboolean interrupted = FALSE; \
66+ mono_thread_info_install_interrupt (win32_wait_interrupt_handler, NULL, &interrupted ); \
67+ if (interrupted ) { \
6768 SetLastError (WAIT_IO_COMPLETION); \
6869 return WAIT_IO_COMPLETION; \
6970 } \
7071 mono_win32_enter_alertable_wait (info); \
7172 } \
7273 } while (0)
7374
74- #define WIN32_LEAVE_ALERTABLE_WAIT (info ) \
75+ #define WIN32_LEAVE_ALERTABLE_WAIT (info , alerted ) \
7576 do { \
7677 if (info) { \
77- gboolean alerted = FALSE; \
78- mono_win32_leave_alertable_wait (info); \
79- mono_thread_info_uninstall_interrupt (&alerted); \
78+ alerted = mono_win32_leave_alertable_wait (info); \
79+ gboolean interrupted; \
80+ mono_thread_info_uninstall_interrupt (&interrupted); \
81+ alerted = alerted || interrupted; \
8082 } \
8183 } while (0)
8284
@@ -93,17 +95,46 @@ win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable, B
9395 DWORD result = WAIT_FAILED ;
9496 MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL ;
9597
96- WIN32_ENTER_ALERTABLE_WAIT (info );
98+ guint64 start_ticks = 0 ;
99+ gboolean done = FALSE;
97100
98- if (cooperative ) {
99- MONO_ENTER_GC_SAFE ;
100- result = win32_wait_for_single_object_ex_interrupt_checked (info , handle , timeout , alertable );
101- MONO_EXIT_GC_SAFE ;
102- } else {
103- result = win32_wait_for_single_object_ex_interrupt_checked (info , handle , timeout , alertable );
104- }
101+ if (timeout != INFINITE && alertable )
102+ start_ticks = GINT64_TO_UINT64 (mono_msec_ticks ());
103+
104+ while (!done )
105+ {
106+ DWORD current_timeout = timeout ;
107+
108+ if (timeout != INFINITE && alertable && result == WAIT_IO_COMPLETION ) {
109+ DWORD elapsed = 0 ;
110+ guint64 current_ticks = mono_msec_ticks ();
111+
112+ if (current_ticks >= start_ticks )
113+ elapsed = GUINT64_TO_UINT32 (current_ticks - start_ticks );
114+ else
115+ elapsed = GUINT64_TO_UINT32 (G_MAXUINT64 - start_ticks + current_ticks );
116+
117+ if (elapsed > timeout )
118+ return WAIT_TIMEOUT ;
119+
120+ current_timeout = timeout - elapsed ;
121+ }
122+
123+ WIN32_ENTER_ALERTABLE_WAIT (info );
124+
125+ if (cooperative ) {
126+ MONO_ENTER_GC_SAFE ;
127+ result = win32_wait_for_single_object_ex_interrupt_checked (info , handle , current_timeout , alertable );
128+ MONO_EXIT_GC_SAFE ;
129+ } else {
130+ result = win32_wait_for_single_object_ex_interrupt_checked (info , handle , current_timeout , alertable );
131+ }
132+
133+ gboolean alerted = FALSE;
134+ WIN32_LEAVE_ALERTABLE_WAIT (info , alerted );
105135
106- WIN32_LEAVE_ALERTABLE_WAIT (info );
136+ done = !(alertable && !alerted && result == WAIT_IO_COMPLETION );
137+ }
107138
108139 return result ;
109140}
@@ -133,17 +164,46 @@ win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL wai
133164 DWORD result = WAIT_FAILED ;
134165 MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL ;
135166
136- WIN32_ENTER_ALERTABLE_WAIT (info );
167+ guint64 start_ticks = 0 ;
168+ gboolean done = FALSE;
137169
138- if (cooperative ) {
139- MONO_ENTER_GC_SAFE ;
140- result = win32_wait_for_multiple_objects_ex_interrupt_checked (info , count , handles , waitAll , timeout , alertable );
141- MONO_EXIT_GC_SAFE ;
142- } else {
143- result = win32_wait_for_multiple_objects_ex_interrupt_checked (info , count , handles , waitAll , timeout , alertable );
144- }
170+ if (timeout != INFINITE && alertable )
171+ start_ticks = GINT64_TO_UINT64 (mono_msec_ticks ());
172+
173+ while (!done )
174+ {
175+ DWORD current_timeout = timeout ;
176+
177+ if (timeout != INFINITE && alertable && result == WAIT_IO_COMPLETION ) {
178+ DWORD elapsed = 0 ;
179+ guint64 current_ticks = mono_msec_ticks ();
180+
181+ if (current_ticks >= start_ticks )
182+ elapsed = GUINT64_TO_UINT32 (current_ticks - start_ticks );
183+ else
184+ elapsed = GUINT64_TO_UINT32 (G_MAXUINT64 - start_ticks + current_ticks );
185+
186+ if (elapsed > timeout )
187+ return WAIT_TIMEOUT ;
188+
189+ current_timeout = timeout - elapsed ;
190+ }
191+
192+ WIN32_ENTER_ALERTABLE_WAIT (info );
193+
194+ if (cooperative ) {
195+ MONO_ENTER_GC_SAFE ;
196+ result = win32_wait_for_multiple_objects_ex_interrupt_checked (info , count , handles , waitAll , current_timeout , alertable );
197+ MONO_EXIT_GC_SAFE ;
198+ } else {
199+ result = win32_wait_for_multiple_objects_ex_interrupt_checked (info , count , handles , waitAll , current_timeout , alertable );
200+ }
201+
202+ gboolean alerted = FALSE;
203+ WIN32_LEAVE_ALERTABLE_WAIT (info , alerted );
145204
146- WIN32_LEAVE_ALERTABLE_WAIT (info );
205+ done = !(alertable && !alerted && result == WAIT_IO_COMPLETION );
206+ }
147207
148208 // This is not perfect, but it is the best you can do in usermode and matches CoreCLR.
149209 // i.e. handle-based instead of object-based.
0 commit comments