/* Returns the exception thrown when invoking, if any */ static MonoObject * mono_async_invoke (ThreadPool *tp, MonoAsyncResult *ares) { ASyncCall *ac = (ASyncCall *)ares->object_data; MonoObject *res, *exc = NULL; MonoArray *out_args = NULL; HANDLE wait_event = NULL; if (ares->execution_context) { /* use captured ExecutionContext (if available) */ MONO_OBJECT_SETREF (ares, original_context, mono_thread_get_execution_context ()); mono_thread_set_execution_context (ares->execution_context); } else { ares->original_context = NULL; } if (ac == NULL) { /* Fast path from ThreadPool.*QueueUserWorkItem */ void *pa = ares->async_state; mono_runtime_delegate_invoke (ares->async_delegate, &pa, &exc); } else { MonoObject *cb_exc = NULL; ac->msg->exc = NULL; res = mono_message_invoke (ares->async_delegate, ac->msg, &exc, &out_args); MONO_OBJECT_SETREF (ac, res, res); MONO_OBJECT_SETREF (ac, msg->exc, exc); MONO_OBJECT_SETREF (ac, out_args, out_args); mono_monitor_enter ((MonoObject *) ares); ares->completed = 1; if (ares->handle != NULL) wait_event = mono_wait_handle_get_handle ((MonoWaitHandle *) ares->handle); mono_monitor_exit ((MonoObject *) ares); /* notify listeners */ if (wait_event != NULL) SetEvent (wait_event); /* call async callback if cb_method != null*/ if (ac != NULL && ac->cb_method) { void *pa = &ares; cb_exc = NULL; mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &cb_exc); MONO_OBJECT_SETREF (ac->msg, exc, cb_exc); exc = cb_exc; } else { exc = NULL; } } /* restore original thread execution context if flow isn't suppressed, i.e. non null */ if (ares->original_context) { mono_thread_set_execution_context (ares->original_context); ares->original_context = NULL; } return exc; }
MonoObject * mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc) { ASyncCall *ac; HANDLE wait_event; *exc = NULL; *out_args = NULL; /* check if already finished */ mono_monitor_enter ((MonoObject *) ares); if (ares->endinvoke_called) { *exc = (MonoObject *) mono_get_exception_invalid_operation (NULL); mono_monitor_exit ((MonoObject *) ares); return NULL; } ares->endinvoke_called = 1; /* wait until we are really finished */ if (!ares->completed) { if (ares->handle == NULL) { wait_event = CreateEvent (NULL, TRUE, FALSE, NULL); g_assert(wait_event != 0); MONO_OBJECT_SETREF (ares, handle, (MonoObject *) mono_wait_handle_new (mono_object_domain (ares), wait_event)); } else { wait_event = mono_wait_handle_get_handle ((MonoWaitHandle *) ares->handle); } mono_monitor_exit ((MonoObject *) ares); WaitForSingleObjectEx (wait_event, INFINITE, TRUE); } else { mono_monitor_exit ((MonoObject *) ares); } ac = (ASyncCall *) ares->object_data; g_assert (ac != NULL); *exc = ac->msg->exc; /* FIXME: GC add write barrier */ *out_args = ac->out_args; return ac->res; }
/* Returns the exception thrown when invoking, if any */ static MonoObject * mono_async_invoke (ThreadPool *tp, MonoAsyncResult *ares) { ASyncCall *ac = (ASyncCall *)ares->object_data; MonoObject *res, *exc = NULL; MonoArray *out_args = NULL; HANDLE wait_event = NULL; MonoInternalThread *thread = mono_thread_internal_current (); if (ares->execution_context) { /* use captured ExecutionContext (if available) */ MONO_OBJECT_SETREF (ares, original_context, mono_thread_get_execution_context ()); mono_thread_set_execution_context (ares->execution_context); } else { ares->original_context = NULL; } if (ac == NULL) { /* Fast path from ThreadPool.*QueueUserWorkItem */ void *pa = ares->async_state; /* The debugger needs this */ thread->async_invoke_method = ((MonoDelegate*)ares->async_delegate)->method; res = mono_runtime_delegate_invoke (ares->async_delegate, &pa, &exc); thread->async_invoke_method = NULL; } else { MonoObject *cb_exc = NULL; ac->msg->exc = NULL; res = mono_message_invoke (ares->async_delegate, ac->msg, &exc, &out_args); MONO_OBJECT_SETREF (ac, res, res); MONO_OBJECT_SETREF (ac, msg->exc, exc); MONO_OBJECT_SETREF (ac, out_args, out_args); mono_monitor_enter ((MonoObject *) ares); ares->completed = 1; if (ares->handle != NULL) wait_event = mono_wait_handle_get_handle ((MonoWaitHandle *) ares->handle); mono_monitor_exit ((MonoObject *) ares); /* notify listeners */ if (wait_event != NULL) SetEvent (wait_event); /* call async callback if cb_method != null*/ if (ac != NULL && ac->cb_method) { void *pa = &ares; cb_exc = NULL; thread->async_invoke_method = ac->cb_method; mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &cb_exc); thread->async_invoke_method = NULL; exc = cb_exc; } else { exc = NULL; } } /* restore original thread execution context if flow isn't suppressed, i.e. non null */ if (ares->original_context) { mono_thread_set_execution_context (ares->original_context); ares->original_context = NULL; } #if DEBUG InterlockedDecrement (&tp->njobs); #endif if (!tp->is_io) InterlockedIncrement (&tp->nexecuted); if (InterlockedDecrement (&monitor_njobs) == 0) monitor_state = MONITOR_STATE_FALLING_ASLEEP; return exc; }