#include "il2cpp-config.h" #include #include #include "icalls/mscorlib/System.Threading/WaitHandle.h" #include "os/Mutex.h" #include "os/Thread.h" #include "vm/Thread.h" #include "vm/Exception.h" #include "vm/Array.h" #include "vm/WaitHandle.h" namespace il2cpp { namespace icalls { namespace mscorlib { namespace System { namespace Threading { std::vector ExtractOsWaitHandles(Il2CppArray* handles) { uint32_t numberOfHandles = vm::Array::GetLength(handles); std::vector osWaitHandles(numberOfHandles); for (uint32_t i = 0; i < numberOfHandles; ++i) { Il2CppObject* handle = il2cpp_array_get(handles, Il2CppObject*, i); Il2CppWaitHandle* waitHandle = (Il2CppWaitHandle*)handle; osWaitHandles[i] = vm::WaitHandle::GetPlatformHandle(waitHandle); } return osWaitHandles; } int32_t WaitHandle::WaitAny_internal(Il2CppArray* handles, int32_t ms, bool exitContext) { std::vector osWaitHandles = ExtractOsWaitHandles(handles); vm::ThreadStateSetter state(vm::kThreadStateWaitSleepJoin); return os::Handle::WaitAny(osWaitHandles, ms); } bool WaitHandle::WaitOne_internal(Il2CppObject* unused, intptr_t handlePtr, int32_t ms, bool exitContext) { il2cpp::os::Handle* handle = (il2cpp::os::Handle*)handlePtr; vm::ThreadStateSetter state(vm::kThreadStateWaitSleepJoin); // Check for pending interrupt before we go waiting. il2cpp::vm::Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary(); if (ms == -1) return handle->Wait(); return handle->Wait((uint32_t)ms); } bool WaitHandle::WaitAll_internal(Il2CppArray* handles, int32_t ms, bool exitContext) { std::vector osWaitHandles = ExtractOsWaitHandles(handles); vm::ThreadStateSetter state(vm::kThreadStateWaitSleepJoin); return os::Handle::WaitAll(osWaitHandles, ms); } bool WaitHandle::SignalAndWait_Internal(intptr_t toSignal, intptr_t toWaitOn, int32_t ms, bool exitContext) { os::Handle* toSignalOsHandle = (os::Handle*)toSignal; toSignalOsHandle->Signal(); return WaitOne_internal(NULL, toWaitOn, ms, exitContext); } int32_t WaitHandle::SignalAndWait_Internal40(intptr_t toSignal, intptr_t toWaitOn, int32_t ms) { return SignalAndWait_Internal(toSignal, toWaitOn, ms, false) ? 0 : 1; } #define MANAGED_WAIT_FAILED 0x7fffffff #define MANAGED_WAIT_OBJECT_0 0x00000000 #define MANAGED_WAIT_TIMEOUT 258 #define MANAGED_WAIT_ABANDONED_0 0x00000080L static int32_t map_native_wait_result_to_managed(UnityPalWaitStatus val, int32_t numobjects) { switch (val) { case kWaitStatusSuccess: return MANAGED_WAIT_OBJECT_0 + val; case kWaitStatusAbandoned: return MANAGED_WAIT_ABANDONED_0 + val; case kWaitStatusFailure: return MANAGED_WAIT_FAILED; case kWaitStatusTimeout: return MANAGED_WAIT_TIMEOUT; default: return MANAGED_WAIT_FAILED; } } int32_t WaitHandle::Wait_internal(void* *handles, int32_t numhandles, bool waitall, int32_t timeouts) { vm::ThreadStateSetter state(vm::kThreadStateWaitSleepJoin); if (numhandles == 1) { os::WaitStatus status = ((os::Handle**)handles)[0]->Wait((uint32_t)timeouts, true); // The managed code expects either success or timeout from this function, so // throw away any other error codes. if (status != kWaitStatusSuccess) status = kWaitStatusTimeout; return map_native_wait_result_to_managed(status, 1); } std::vector osWaitHandles((os::Handle**)handles, (os::Handle**)handles + numhandles); if (waitall) { if (os::Handle::WaitAll(osWaitHandles, timeouts)) { return map_native_wait_result_to_managed(kWaitStatusSuccess, numhandles); } else { return map_native_wait_result_to_managed(kWaitStatusTimeout, numhandles); } } else return os::Handle::WaitAny(osWaitHandles, timeouts); } } /* namespace Threading */ } /* namespace System */ } /* namespace mscorlib */ } /* namespace icalls */ } /* namespace il2cpp */