#include "il2cpp-config.h"
|
#include <vector>
|
#include <algorithm>
|
#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<os::Handle*> ExtractOsWaitHandles(Il2CppArray* handles)
|
{
|
uint32_t numberOfHandles = vm::Array::GetLength(handles);
|
|
std::vector<os::Handle*> 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<os::Handle*> 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<os::Handle*> 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<os::Handle*> 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 */
|