[amd64] Fix mingw-w64 build. (#4519)
[mono-project.git] / mono / utils / os-event-unix.c
blobb4a3e2f5afdf8dc083df00f30973be0d2a4349ea
1 /*
2 * os-event-unix.c: MonoOSEvent on Unix
4 * Author:
5 * Ludovic Henry (luhenry@microsoft.com)
7 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
8 */
10 #include "os-event.h"
12 #include "atomic.h"
13 #include "mono-lazy-init.h"
14 #include "mono-threads.h"
15 #include "mono-time.h"
17 static mono_lazy_init_t status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
19 static mono_mutex_t signal_mutex;
21 static void
22 initialize (void)
24 mono_os_mutex_init (&signal_mutex);
27 void
28 mono_os_event_init (MonoOSEvent *event, gboolean initial)
30 g_assert (event);
32 mono_lazy_initialize (&status, initialize);
34 event->conds = g_ptr_array_new ();
35 event->signalled = initial;
38 void
39 mono_os_event_destroy (MonoOSEvent *event)
41 g_assert (mono_lazy_is_initialized (&status));
43 g_assert (event);
45 if (event->conds->len > 0)
46 g_error ("%s: cannot destroy osevent, there are still %d threads waiting on it", __func__, event->conds->len);
48 g_ptr_array_free (event->conds, TRUE);
51 static gboolean
52 mono_os_event_is_signalled (MonoOSEvent *event)
54 return event->signalled;
57 void
58 mono_os_event_set (MonoOSEvent *event)
60 gsize i;
62 g_assert (mono_lazy_is_initialized (&status));
64 g_assert (event);
66 mono_os_mutex_lock (&signal_mutex);
68 event->signalled = TRUE;
70 for (i = 0; i < event->conds->len; ++i)
71 mono_os_cond_signal ((mono_cond_t*) event->conds->pdata [i]);
73 mono_os_mutex_unlock (&signal_mutex);
76 void
77 mono_os_event_reset (MonoOSEvent *event)
79 g_assert (mono_lazy_is_initialized (&status));
81 g_assert (event);
83 mono_os_mutex_lock (&signal_mutex);
85 event->signalled = FALSE;
87 mono_os_mutex_unlock (&signal_mutex);
90 MonoOSEventWaitRet
91 mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
93 return mono_os_event_wait_multiple (&event, 1, TRUE, timeout, alertable);
96 typedef struct {
97 guint32 ref;
98 MonoOSEvent event;
99 } OSEventWaitData;
101 static void
102 signal_and_unref (gpointer user_data)
104 OSEventWaitData *data;
106 data = (OSEventWaitData*) user_data;
108 mono_os_event_set (&data->event);
109 if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
110 mono_os_event_destroy (&data->event);
111 g_free (data);
115 MonoOSEventWaitRet
116 mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout, gboolean alertable)
118 MonoOSEventWaitRet ret;
119 mono_cond_t signal_cond;
120 OSEventWaitData *data;
121 gboolean alerted;
122 gint64 start;
123 gint i;
125 g_assert (mono_lazy_is_initialized (&status));
127 g_assert (events);
128 g_assert (nevents > 0);
129 g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
131 for (i = 0; i < nevents; ++i)
132 g_assert (events [i]);
134 if (alertable) {
135 data = g_new0 (OSEventWaitData, 1);
136 data->ref = 2;
137 mono_os_event_init (&data->event, FALSE);
139 alerted = FALSE;
140 mono_thread_info_install_interrupt (signal_and_unref, data, &alerted);
141 if (alerted) {
142 mono_os_event_destroy (&data->event);
143 g_free (data);
144 return MONO_OS_EVENT_WAIT_RET_ALERTED;
148 if (timeout != MONO_INFINITE_WAIT)
149 start = mono_msec_ticks ();
151 mono_os_cond_init (&signal_cond);
153 mono_os_mutex_lock (&signal_mutex);
155 for (i = 0; i < nevents; ++i)
156 g_ptr_array_add (events [i]->conds, &signal_cond);
158 if (alertable)
159 g_ptr_array_add (data->event.conds, &signal_cond);
161 for (;;) {
162 gint count, lowest;
163 gboolean signalled;
165 count = 0;
166 lowest = -1;
168 for (i = 0; i < nevents; ++i) {
169 if (mono_os_event_is_signalled (events [i])) {
170 count += 1;
171 if (lowest == -1)
172 lowest = i;
176 if (alertable && mono_os_event_is_signalled (&data->event))
177 signalled = TRUE;
178 else if (waitall)
179 signalled = (count == nevents);
180 else /* waitany */
181 signalled = (count > 0);
183 if (signalled) {
184 ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest;
185 goto done;
188 if (timeout == MONO_INFINITE_WAIT) {
189 mono_os_cond_wait (&signal_cond, &signal_mutex);
190 } else {
191 gint64 elapsed;
192 gint res;
194 elapsed = mono_msec_ticks () - start;
195 if (elapsed >= timeout) {
196 ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
197 goto done;
200 res = mono_os_cond_timedwait (&signal_cond, &signal_mutex, timeout - elapsed);
201 if (res != 0) {
202 ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
203 goto done;
208 done:
209 for (i = 0; i < nevents; ++i)
210 g_ptr_array_remove (events [i]->conds, &signal_cond);
212 if (alertable)
213 g_ptr_array_remove (data->event.conds, &signal_cond);
215 mono_os_mutex_unlock (&signal_mutex);
217 mono_os_cond_destroy (&signal_cond);
219 if (alertable) {
220 mono_thread_info_uninstall_interrupt (&alerted);
221 if (alerted) {
222 if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
223 mono_os_event_destroy (&data->event);
224 g_free (data);
226 return MONO_OS_EVENT_WAIT_RET_ALERTED;
229 mono_os_event_destroy (&data->event);
230 g_free (data);
233 return ret;