mono_os_cond_destroy (&event->cond);
}
+static gboolean
+mono_os_event_is_signalled (MonoOSEvent *event)
+{
+ return event->signalled;
+}
+
static void
mono_os_event_signal (MonoOSEvent *event, gboolean broadcast)
{
mono_os_mutex_lock (&event->mutex);
- if (event->signalled)
+ if (mono_os_event_is_signalled (event))
event->signalled = FALSE;
event->set_count = 0;
{
g_assert (event);
- if (!event->signalled)
+ if (!mono_os_event_is_signalled (event))
return FALSE;
if (!event->manual) {
MonoOSEventWaitRet
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
{
- MonoOSEventWaitRet ret;
- gint64 start;
-
- g_assert (mono_lazy_is_initialized (&status));
+ return mono_os_event_wait_multiple (&event, 1, TRUE, timeout);
+}
- g_assert (event);
+typedef struct {
+ guint32 ref;
+ MonoOSEvent event;
+} OSEventWaitData;
- mono_os_mutex_lock (&event->mutex);
-
- if (timeout != MONO_INFINITE_WAIT)
- start = mono_msec_ticks ();
+static void
+signal_and_unref (gpointer user_data)
+{
+ OSEventWaitData *data;
- for (;;) {
- if (mono_os_event_own (event)) {
- ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0;
- goto done;
- }
+ data = (OSEventWaitData*) user_data;
- if (timeout == MONO_INFINITE_WAIT) {
- mono_os_cond_wait (&event->cond, &event->mutex);
- } else {
- gint64 elapsed;
- gint res;
-
- elapsed = mono_msec_ticks () - start;
- if (elapsed >= timeout) {
- ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
- goto done;
- }
-
- res = mono_os_cond_timedwait (&event->cond, &event->mutex, timeout - elapsed);
- if (res != 0) {
- ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
- goto done;
- }
- }
+ mono_os_event_set (&data->event);
+ if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
+ mono_os_event_destroy (&data->event);
+ g_free (data);
}
-
-done:
- mono_os_mutex_unlock (&event->mutex);
-
- return ret;
}
static void
mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout)
{
MonoOSEventWaitRet ret;
+ MonoOSEvent *innerevents [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS + 1];
+ OSEventWaitData *data;
+ gboolean alerted;
gint64 start;
gint i;
g_assert (nevents > 0);
g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
- if (nevents == 1)
- return mono_os_event_wait_one (events [0], timeout);
-
- for (i = 0; i < nevents; ++i) {
+ for (i = 0; i < nevents; ++i)
g_assert (events [i]);
+
+ memcpy (innerevents, events, sizeof (MonoOSEvent*) * nevents);
+
+ data = g_new0 (OSEventWaitData, 1);
+ data->ref = 2;
+ mono_os_event_init (&data->event, TRUE, FALSE);
+
+ innerevents [nevents ++] = &data->event;
+
+ alerted = FALSE;
+ mono_thread_info_install_interrupt (signal_and_unref, data, &alerted);
+ if (alerted) {
+ mono_os_event_destroy (&data->event);
+ g_free (data);
+ return MONO_OS_EVENT_WAIT_RET_ALERTED;
}
if (timeout != MONO_INFINITE_WAIT)
gint count, lowest;
gboolean signalled;
- mono_os_event_lock_events (events, nevents);
+ mono_os_event_lock_events (innerevents, nevents);
count = 0;
lowest = -1;
- for (i = 0; i < nevents; ++i) {
- if (events [i]->signalled) {
+ for (i = 0; i < nevents - 1; ++i) {
+ if (mono_os_event_is_signalled (innerevents [i])) {
count += 1;
if (lowest == -1)
lowest = i;
}
}
- signalled = (waitall && count == nevents) || (!waitall && count > 0);
+ if (mono_os_event_is_signalled (&data->event))
+ signalled = TRUE;
+ else if (waitall)
+ signalled = (count == nevents - 1);
+ else /* waitany */
+ signalled = (count > 0);
if (signalled) {
- for (i = 0; i < nevents; ++i)
- mono_os_event_own (events [i]);
+ for (i = 0; i < nevents - 1; ++i)
+ mono_os_event_own (innerevents [i]);
}
- mono_os_event_unlock_events (events, nevents);
+ mono_os_event_unlock_events (innerevents, nevents);
if (signalled) {
ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest;
mono_os_mutex_lock (&signal_mutex);
- if (waitall) {
+ if (mono_os_event_is_signalled (&data->event)) {
+ signalled = TRUE;
+ } else if (waitall) {
signalled = TRUE;
- for (i = 0; i < nevents; ++i) {
- if (!events [i]->signalled) {
+ for (i = 0; i < nevents - 1; ++i) {
+ if (!mono_os_event_is_signalled (innerevents [i])) {
signalled = FALSE;
break;
}
}
} else {
signalled = FALSE;
- for (i = 0; i < nevents; ++i) {
- if (events [i]->signalled) {
+ for (i = 0; i < nevents - 1; ++i) {
+ if (mono_os_event_is_signalled (innerevents [i])) {
signalled = TRUE;
break;
}
}
done:
+ mono_thread_info_uninstall_interrupt (&alerted);
+ if (alerted) {
+ if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
+ mono_os_event_destroy (&data->event);
+ g_free (data);
+ }
+ return MONO_OS_EVENT_WAIT_RET_ALERTED;
+ }
+
+ mono_os_event_destroy (&data->event);
+ g_free (data);
+
return ret;
}