-/*
- * os-event-unix.c: MonoOSEvent on Unix
+/**
+ * \file
+ * MonoOSEvent on Unix
*
* Author:
* Ludovic Henry (luhenry@microsoft.com)
static mono_lazy_init_t status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
static mono_mutex_t signal_mutex;
-static mono_cond_t signal_cond;
static void
initialize (void)
{
mono_os_mutex_init (&signal_mutex);
- mono_os_cond_init (&signal_cond);
}
void
-mono_os_event_init (MonoOSEvent *event, gboolean manual, gboolean initial)
+mono_os_event_init (MonoOSEvent *event, gboolean initial)
{
g_assert (event);
mono_lazy_initialize (&status, initialize);
- mono_os_mutex_init (&event->mutex);
- mono_os_cond_init (&event->cond);
+ event->conds = g_ptr_array_new ();
event->signalled = initial;
- event->manual = manual;
- event->set_count = (initial && !manual) ? 1 : 0;
}
void
g_assert (event);
- mono_os_mutex_destroy (&event->mutex);
- mono_os_cond_destroy (&event->cond);
+ if (event->conds->len > 0)
+ g_error ("%s: cannot destroy osevent, there are still %d threads waiting on it", __func__, event->conds->len);
+
+ g_ptr_array_free (event->conds, TRUE);
}
-static void
-mono_os_event_signal (MonoOSEvent *event, gboolean broadcast)
+static gboolean
+mono_os_event_is_signalled (MonoOSEvent *event)
{
- g_assert (event);
-
- mono_os_mutex_lock (&signal_mutex);
-
- event->signalled = TRUE;
-
- if (broadcast)
- mono_os_cond_broadcast (&event->cond);
- else
- mono_os_cond_signal (&event->cond);
-
- mono_os_cond_broadcast (&signal_cond);
-
- mono_os_mutex_unlock (&signal_mutex);
+ return event->signalled;
}
void
mono_os_event_set (MonoOSEvent *event)
{
+ gsize i;
+
g_assert (mono_lazy_is_initialized (&status));
g_assert (event);
- mono_os_mutex_lock (&event->mutex);
+ mono_os_mutex_lock (&signal_mutex);
+
+ event->signalled = TRUE;
- if (event->manual) {
- mono_os_event_signal (event, TRUE);
- } else {
- event->set_count = 1;
- mono_os_event_signal (event, FALSE);
- }
+ for (i = 0; i < event->conds->len; ++i)
+ mono_os_cond_signal ((mono_cond_t*) event->conds->pdata [i]);
- mono_os_mutex_unlock (&event->mutex);
+ mono_os_mutex_unlock (&signal_mutex);
}
void
g_assert (event);
- mono_os_mutex_lock (&event->mutex);
-
- if (event->signalled)
- event->signalled = FALSE;
-
- event->set_count = 0;
-
- mono_os_mutex_unlock (&event->mutex);
-}
-
-static gboolean
-mono_os_event_own (MonoOSEvent *event)
-{
- g_assert (event);
-
- if (!event->signalled)
- return FALSE;
-
- if (!event->manual) {
- g_assert (event->set_count > 0);
- event->set_count -= 1;
+ mono_os_mutex_lock (&signal_mutex);
- if (event->set_count == 0)
- mono_os_event_signal (event, FALSE);
- }
+ event->signalled = FALSE;
- return TRUE;
+ mono_os_mutex_unlock (&signal_mutex);
}
MonoOSEventWaitRet
-mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
+mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
{
- MonoOSEventWaitRet ret;
- gint64 start;
-
- g_assert (mono_lazy_is_initialized (&status));
-
- g_assert (event);
-
- mono_os_mutex_lock (&event->mutex);
-
- if (timeout != MONO_INFINITE_WAIT)
- start = mono_msec_ticks ();
-
- for (;;) {
- if (mono_os_event_own (event)) {
- ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0;
- goto done;
- }
-
- 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;
- }
- }
- }
-
-done:
- mono_os_mutex_unlock (&event->mutex);
-
- return ret;
+ return mono_os_event_wait_multiple (&event, 1, TRUE, timeout, alertable);
}
+typedef struct {
+ guint32 ref;
+ MonoOSEvent event;
+} OSEventWaitData;
+
static void
-mono_os_event_lock_events (MonoOSEvent **events, gsize nevents)
+signal_and_unref (gpointer user_data)
{
- gint i, j;
-
-retry:
- for (i = 0; i < nevents; ++i) {
- gint res;
+ OSEventWaitData *data;
- res = mono_os_mutex_trylock (&events [i]->mutex);
- if (res != 0) {
- for (j = i - 1; j >= 0; j--)
- mono_os_mutex_unlock (&events [j]->mutex);
+ data = (OSEventWaitData*) user_data;
- mono_thread_info_yield ();
-
- goto retry;
- }
+ mono_os_event_set (&data->event);
+ if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
+ mono_os_event_destroy (&data->event);
+ g_free (data);
}
}
-static void
-mono_os_event_unlock_events (MonoOSEvent **events, gsize nevents)
-{
- gint i;
-
- for (i = 0; i < nevents; ++i)
- mono_os_mutex_unlock (&events [i]->mutex);
-}
-
MonoOSEventWaitRet
-mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout)
+mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout, gboolean alertable)
{
MonoOSEventWaitRet ret;
+ mono_cond_t signal_cond;
+ 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]);
+
+ if (alertable) {
+ data = g_new0 (OSEventWaitData, 1);
+ data->ref = 2;
+ mono_os_event_init (&data->event, FALSE);
+
+ 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)
start = mono_msec_ticks ();
+ mono_os_cond_init (&signal_cond);
+
+ mono_os_mutex_lock (&signal_mutex);
+
+ for (i = 0; i < nevents; ++i)
+ g_ptr_array_add (events [i]->conds, &signal_cond);
+
+ if (alertable)
+ g_ptr_array_add (data->event.conds, &signal_cond);
+
for (;;) {
gint count, lowest;
gboolean signalled;
- mono_os_event_lock_events (events, nevents);
-
count = 0;
lowest = -1;
for (i = 0; i < nevents; ++i) {
- if (events [i]->signalled) {
+ if (mono_os_event_is_signalled (events [i])) {
count += 1;
if (lowest == -1)
lowest = i;
}
}
- signalled = (waitall && count == nevents) || (!waitall && count > 0);
-
- if (signalled) {
- for (i = 0; i < nevents; ++i)
- mono_os_event_own (events [i]);
- }
-
- mono_os_event_unlock_events (events, nevents);
+ if (alertable && mono_os_event_is_signalled (&data->event))
+ signalled = TRUE;
+ else if (waitall)
+ signalled = (count == nevents);
+ else /* waitany */
+ signalled = (count > 0);
if (signalled) {
ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest;
goto done;
}
- mono_os_mutex_lock (&signal_mutex);
-
- if (waitall) {
- signalled = TRUE;
- for (i = 0; i < nevents; ++i) {
- if (!events [i]->signalled) {
- signalled = FALSE;
- break;
- }
- }
- } else {
- signalled = FALSE;
- for (i = 0; i < nevents; ++i) {
- if (events [i]->signalled) {
- signalled = TRUE;
- break;
- }
- }
- }
-
- if (signalled) {
- mono_os_mutex_unlock (&signal_mutex);
- continue;
- }
-
if (timeout == MONO_INFINITE_WAIT) {
mono_os_cond_wait (&signal_cond, &signal_mutex);
} else {
elapsed = mono_msec_ticks () - start;
if (elapsed >= timeout) {
- mono_os_mutex_unlock (&signal_mutex);
-
ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
goto done;
}
res = mono_os_cond_timedwait (&signal_cond, &signal_mutex, timeout - elapsed);
if (res != 0) {
- mono_os_mutex_unlock (&signal_mutex);
-
ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
goto done;
}
}
-
- mono_os_mutex_unlock (&signal_mutex);
}
done:
+ for (i = 0; i < nevents; ++i)
+ g_ptr_array_remove (events [i]->conds, &signal_cond);
+
+ if (alertable)
+ g_ptr_array_remove (data->event.conds, &signal_cond);
+
+ mono_os_mutex_unlock (&signal_mutex);
+
+ mono_os_cond_destroy (&signal_cond);
+
+ if (alertable) {
+ 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;
}