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
);