/* * coop_cond_timedwait_alertable: * * Wait on COND/MUTEX. If ALERTABLE is non-null, the wait can be interrupted. * In that case, *ALERTABLE will be set to TRUE, and 0 is returned. */ static inline gint coop_cond_timedwait_alertable (MonoCoopCond *cond, MonoCoopMutex *mutex, guint32 timeout_ms, gboolean *alertable) { BreakCoopAlertableWaitUD *ud; int res; if (alertable) { ud = g_new0 (BreakCoopAlertableWaitUD, 1); ud->cond = cond; ud->mutex = mutex; mono_thread_info_install_interrupt (break_coop_alertable_wait, ud, alertable); if (*alertable) { g_free (ud); return 0; } } res = mono_coop_cond_timedwait (cond, mutex, timeout_ms); if (alertable) { mono_thread_info_uninstall_interrupt (alertable); if (*alertable) return 0; else { /* the interrupt token has not been taken by another * thread, so it's our responsability to free it up. */ g_free (ud); } } return res; }
static inline guint32 sleep_interruptable (guint32 ms, gboolean *alerted) { guint32 start, now, end; g_assert (INFINITE == G_MAXUINT32); g_assert (alerted); *alerted = FALSE; start = mono_msec_ticks (); if (start < G_MAXUINT32 - ms) { end = start + ms; } else { /* start + ms would overflow guint32 */ end = G_MAXUINT32; } mono_lazy_initialize (&sleep_init, sleep_initialize); mono_coop_mutex_lock (&sleep_mutex); for (now = mono_msec_ticks (); ms == INFINITE || now - start < ms; now = mono_msec_ticks ()) { mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted); if (*alerted) { mono_coop_mutex_unlock (&sleep_mutex); return WAIT_IO_COMPLETION; } if (ms < INFINITE) mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now); else mono_coop_cond_wait (&sleep_cond, &sleep_mutex); mono_thread_info_uninstall_interrupt (alerted); if (*alerted) { mono_coop_mutex_unlock (&sleep_mutex); return WAIT_IO_COMPLETION; } } mono_coop_mutex_unlock (&sleep_mutex); return 0; }
static inline guint32 sleep_interruptable (guint32 ms, gboolean *alerted) { gint64 now, end; g_assert (INFINITE == G_MAXUINT32); g_assert (alerted); *alerted = FALSE; if (ms != INFINITE) end = mono_100ns_ticks () + (ms * 1000 * 10); mono_lazy_initialize (&sleep_init, sleep_initialize); mono_coop_mutex_lock (&sleep_mutex); for (;;) { if (ms != INFINITE) { now = mono_100ns_ticks (); if (now > end) break; } mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted); if (*alerted) { mono_coop_mutex_unlock (&sleep_mutex); return WAIT_IO_COMPLETION; } if (ms != INFINITE) mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, (end - now) / 10 / 1000); else mono_coop_cond_wait (&sleep_cond, &sleep_mutex); mono_thread_info_uninstall_interrupt (alerted); if (*alerted) { mono_coop_mutex_unlock (&sleep_mutex); return WAIT_IO_COMPLETION; } } mono_coop_mutex_unlock (&sleep_mutex); return 0; }
/* * ves_icall_System_IO_KqueueMonitor_kevent_notimeout: * * Call kevent (), while handling runtime interruptions. */ int ves_icall_System_IO_KqueueMonitor_kevent_notimeout (int *kq_ptr, gpointer changelist, int nchanges, gpointer eventlist, int nevents) { int res; gboolean interrupted; mono_thread_info_install_interrupt (interrupt_kevent, kq_ptr, &interrupted); if (interrupted) { close (*kq_ptr); *kq_ptr = -1; return -1; } MONO_ENTER_GC_SAFE; res = kevent (*kq_ptr, changelist, nchanges, eventlist, nevents, NULL); MONO_EXIT_GC_SAFE; mono_thread_info_uninstall_interrupt (&interrupted); return res; }
MonoOSEventWaitRet 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 (mono_lazy_is_initialized (&status)); g_assert (events); g_assert (nevents > 0); g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS); 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; count = 0; lowest = -1; for (i = 0; i < nevents; ++i) { if (mono_os_event_is_signalled (events [i])) { count += 1; if (lowest == -1) lowest = i; } } 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; } if (timeout == MONO_INFINITE_WAIT) { mono_os_cond_wait (&signal_cond, &signal_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 (&signal_cond, &signal_mutex, timeout - elapsed); if (res != 0) { ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT; goto done; } } } 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; }