Skip to content

Commit

Permalink
[threads] Make OSEvent alertable to fix bug #51653
Browse files Browse the repository at this point in the history
  • Loading branch information
luhenry committed Feb 7, 2017
1 parent ede498b commit a1568a7
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 38 deletions.
4 changes: 0 additions & 4 deletions mono/metadata/icall.c
Expand Up @@ -6646,10 +6646,6 @@ ves_icall_System_Environment_Exit (int result)
/* Suspend all managed threads since the runtime is going away */
mono_thread_suspend_all_other_threads ();

//FIXME shutdown is, weirdly enough, abortible in gc.c so we add this hack for now, see https://bugzilla.xamarin.com/show_bug.cgi?id=51653
mono_threads_begin_abort_protected_block ();
mono_thread_info_clear_self_interrupt ();

mono_runtime_quit ();
#endif

Expand Down
2 changes: 1 addition & 1 deletion mono/metadata/threads.c
Expand Up @@ -5002,7 +5002,7 @@ self_suspend_internal (void)
event = thread->suspended;

MONO_ENTER_GC_SAFE;
res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
MONO_EXIT_GC_SAFE;
}
Expand Down
4 changes: 2 additions & 2 deletions mono/utils/mono-threads.c
Expand Up @@ -1655,7 +1655,7 @@ mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeo
{
MonoOSEventWaitRet res;

res = mono_os_event_wait_one (&thread_handle->event, timeout);
res = mono_os_event_wait_one (&thread_handle->event, timeout, alertable);
if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0)
return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0;
else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
Expand Down Expand Up @@ -1683,7 +1683,7 @@ mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize
if (background_change_event)
thread_events [nhandles ++] = background_change_event;

res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout);
res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout, alertable);
if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1)
return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0);
else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
Expand Down
54 changes: 30 additions & 24 deletions mono/utils/os-event-unix.c
Expand Up @@ -88,9 +88,9 @@ mono_os_event_reset (MonoOSEvent *event)
}

MonoOSEventWaitRet
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
{
return mono_os_event_wait_multiple (&event, 1, TRUE, timeout);
return mono_os_event_wait_multiple (&event, 1, TRUE, timeout, alertable);
}

typedef struct {
Expand All @@ -113,7 +113,7 @@ signal_and_unref (gpointer user_data)
}

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;
Expand All @@ -131,16 +131,18 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
for (i = 0; i < nevents; ++i)
g_assert (events [i]);

data = g_new0 (OSEventWaitData, 1);
data->ref = 2;
mono_os_event_init (&data->event, FALSE);
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;
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)
Expand All @@ -153,7 +155,8 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
for (i = 0; i < nevents; ++i)
g_ptr_array_add (events [i]->conds, &signal_cond);

g_ptr_array_add (data->event.conds, &signal_cond);
if (alertable)
g_ptr_array_add (data->event.conds, &signal_cond);

for (;;) {
gint count, lowest;
Expand All @@ -170,7 +173,7 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
}
}

if (mono_os_event_is_signalled (&data->event))
if (alertable && mono_os_event_is_signalled (&data->event))
signalled = TRUE;
else if (waitall)
signalled = (count == nevents);
Expand Down Expand Up @@ -206,23 +209,26 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
for (i = 0; i < nevents; ++i)
g_ptr_array_remove (events [i]->conds, &signal_cond);

g_ptr_array_remove (data->event.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);

mono_thread_info_uninstall_interrupt (&alerted);
if (alerted) {
if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
mono_os_event_destroy (&data->event);
g_free (data);
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;
}
return MONO_OS_EVENT_WAIT_RET_ALERTED;
}

mono_os_event_destroy (&data->event);
g_free (data);
mono_os_event_destroy (&data->event);
g_free (data);
}

return ret;
}
10 changes: 5 additions & 5 deletions mono/utils/os-event-win32.c
Expand Up @@ -64,14 +64,14 @@ mono_os_event_reset (MonoOSEvent *event)
}

MonoOSEventWaitRet
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
{
DWORD res;

g_assert (event);
g_assert (event->handle);

res = WaitForSingleObjectEx (event->handle, timeout, TRUE);
res = WaitForSingleObjectEx (event->handle, timeout, alertable);
if (res == WAIT_OBJECT_0)
return MONO_OS_EVENT_WAIT_RET_SUCCESS_0;
else if (res == WAIT_IO_COMPLETION)
Expand All @@ -85,7 +85,7 @@ mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout)
}

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)
{
DWORD res;
gpointer handles [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS];
Expand All @@ -96,15 +96,15 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);

if (nevents == 1)
return mono_os_event_wait_one (events [0], timeout);
return mono_os_event_wait_one (events [0], timeout, alertable);

for (i = 0; i < nevents; ++i) {
g_assert (events [i]);
g_assert (events [i]->handle);
handles [i] = events [i]->handle;
}

res = WaitForMultipleObjectsEx (nevents, handles, waitall, timeout, TRUE);
res = WaitForMultipleObjectsEx (nevents, handles, waitall, timeout, alertable);
if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS)
return MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + (res - WAIT_OBJECT_0);
else if (res == WAIT_IO_COMPLETION)
Expand Down
4 changes: 2 additions & 2 deletions mono/utils/os-event.h
Expand Up @@ -45,9 +45,9 @@ void
mono_os_event_reset (MonoOSEvent *event);

MonoOSEventWaitRet
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout);
mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable);

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

#endif /* _MONO_UTILS_OS_EVENT_H_ */

0 comments on commit a1568a7

Please sign in to comment.