2 * os-event-unix.c: MonoOSEvent on Unix
5 * Ludovic Henry (luhenry@microsoft.com)
7 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
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;
20 static mono_cond_t signal_cond;
25 mono_os_mutex_init (&signal_mutex);
26 mono_os_cond_init (&signal_cond);
30 mono_os_event_init (MonoOSEvent *event, gboolean manual, gboolean initial)
34 mono_lazy_initialize (&status, initialize);
36 mono_os_mutex_init (&event->mutex);
37 mono_os_cond_init (&event->cond);
38 event->signalled = initial;
39 event->manual = manual;
40 event->set_count = (initial && !manual) ? 1 : 0;
44 mono_os_event_destroy (MonoOSEvent *event)
46 g_assert (mono_lazy_is_initialized (&status));
50 mono_os_mutex_destroy (&event->mutex);
51 mono_os_cond_destroy (&event->cond);
55 mono_os_event_is_signalled (MonoOSEvent *event)
57 return event->signalled;
61 mono_os_event_signal (MonoOSEvent *event, gboolean broadcast)
65 mono_os_mutex_lock (&signal_mutex);
67 event->signalled = TRUE;
70 mono_os_cond_broadcast (&event->cond);
72 mono_os_cond_signal (&event->cond);
74 mono_os_cond_broadcast (&signal_cond);
76 mono_os_mutex_unlock (&signal_mutex);
80 mono_os_event_set (MonoOSEvent *event)
82 g_assert (mono_lazy_is_initialized (&status));
86 mono_os_mutex_lock (&event->mutex);
89 mono_os_event_signal (event, TRUE);
92 mono_os_event_signal (event, FALSE);
95 mono_os_mutex_unlock (&event->mutex);
99 mono_os_event_reset (MonoOSEvent *event)
101 g_assert (mono_lazy_is_initialized (&status));
105 mono_os_mutex_lock (&event->mutex);
107 if (mono_os_event_is_signalled (event))
108 event->signalled = FALSE;
110 event->set_count = 0;
112 mono_os_mutex_unlock (&event->mutex);
116 mono_os_event_own (MonoOSEvent *event)
120 if (!mono_os_event_is_signalled (event))
123 if (!event->manual) {
124 g_assert (event->set_count > 0);
125 event->set_count -= 1;
127 if (event->set_count == 0)
128 mono_os_event_signal (event, FALSE);
135 mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
137 return mono_os_event_wait_multiple (&event, 1, TRUE, timeout);
146 signal_and_unref (gpointer user_data)
148 OSEventWaitData *data;
150 data = (OSEventWaitData*) user_data;
152 mono_os_event_set (&data->event);
153 if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
154 mono_os_event_destroy (&data->event);
160 mono_os_event_lock_events (MonoOSEvent **events, gsize nevents)
165 for (i = 0; i < nevents; ++i) {
168 res = mono_os_mutex_trylock (&events [i]->mutex);
170 for (j = i - 1; j >= 0; j--)
171 mono_os_mutex_unlock (&events [j]->mutex);
173 mono_thread_info_yield ();
181 mono_os_event_unlock_events (MonoOSEvent **events, gsize nevents)
185 for (i = 0; i < nevents; ++i)
186 mono_os_mutex_unlock (&events [i]->mutex);
190 mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout)
192 MonoOSEventWaitRet ret;
193 MonoOSEvent *innerevents [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS + 1];
194 OSEventWaitData *data;
199 g_assert (mono_lazy_is_initialized (&status));
202 g_assert (nevents > 0);
203 g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
205 for (i = 0; i < nevents; ++i)
206 g_assert (events [i]);
208 memcpy (innerevents, events, sizeof (MonoOSEvent*) * nevents);
210 data = g_new0 (OSEventWaitData, 1);
212 mono_os_event_init (&data->event, TRUE, FALSE);
214 innerevents [nevents ++] = &data->event;
217 mono_thread_info_install_interrupt (signal_and_unref, data, &alerted);
219 mono_os_event_destroy (&data->event);
221 return MONO_OS_EVENT_WAIT_RET_ALERTED;
224 if (timeout != MONO_INFINITE_WAIT)
225 start = mono_msec_ticks ();
231 mono_os_event_lock_events (innerevents, nevents);
236 for (i = 0; i < nevents - 1; ++i) {
237 if (mono_os_event_is_signalled (innerevents [i])) {
244 if (mono_os_event_is_signalled (&data->event))
247 signalled = (count == nevents - 1);
249 signalled = (count > 0);
252 for (i = 0; i < nevents - 1; ++i)
253 mono_os_event_own (innerevents [i]);
256 mono_os_event_unlock_events (innerevents, nevents);
259 ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest;
263 mono_os_mutex_lock (&signal_mutex);
265 if (mono_os_event_is_signalled (&data->event)) {
267 } else if (waitall) {
269 for (i = 0; i < nevents - 1; ++i) {
270 if (!mono_os_event_is_signalled (innerevents [i])) {
277 for (i = 0; i < nevents - 1; ++i) {
278 if (mono_os_event_is_signalled (innerevents [i])) {
286 mono_os_mutex_unlock (&signal_mutex);
290 if (timeout == MONO_INFINITE_WAIT) {
291 mono_os_cond_wait (&signal_cond, &signal_mutex);
296 elapsed = mono_msec_ticks () - start;
297 if (elapsed >= timeout) {
298 mono_os_mutex_unlock (&signal_mutex);
300 ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
304 res = mono_os_cond_timedwait (&signal_cond, &signal_mutex, timeout - elapsed);
306 mono_os_mutex_unlock (&signal_mutex);
308 ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
313 mono_os_mutex_unlock (&signal_mutex);
317 mono_thread_info_uninstall_interrupt (&alerted);
319 if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
320 mono_os_event_destroy (&data->event);
323 return MONO_OS_EVENT_WAIT_RET_ALERTED;
326 mono_os_event_destroy (&data->event);