暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ThreadImpl.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #include "il2cpp-config.h"
  2. #if !IL2CPP_THREADS_STD && IL2CPP_THREADS_WIN32
  3. #include "ThreadImpl.h"
  4. #include "os/ThreadLocalValue.h"
  5. #include "os/Time.h"
  6. #include "utils/StringUtils.h"
  7. #include "os/Debug.h"
  8. #include "WindowsHelpers.h"
  9. namespace il2cpp
  10. {
  11. namespace os
  12. {
  13. struct ThreadImplStartData
  14. {
  15. Thread::StartFunc m_StartFunc;
  16. void* m_StartArg;
  17. volatile DWORD* m_ThreadId;
  18. };
  19. static DWORD WINAPI ThreadStartWrapper(LPVOID arg)
  20. {
  21. ThreadImplStartData startData = *(ThreadImplStartData*)arg;
  22. free(arg);
  23. *startData.m_ThreadId = GetCurrentThreadId();
  24. startData.m_StartFunc(startData.m_StartArg);
  25. return 0;
  26. }
  27. static Event* s_ThreadSleepObject = nullptr;
  28. void ThreadImpl::AllocateStaticData()
  29. {
  30. s_ThreadSleepObject = new Event();
  31. }
  32. void ThreadImpl::FreeStaticData()
  33. {
  34. delete s_ThreadSleepObject;
  35. s_ThreadSleepObject = nullptr;
  36. }
  37. ThreadImpl::ThreadImpl()
  38. : m_ThreadHandle(0), m_ThreadId(0), m_StackSize(IL2CPP_DEFAULT_STACK_SIZE), m_ApartmentState(kApartmentStateUnknown), m_Priority(kThreadPriorityNormal)
  39. , m_ConditionSemaphore(1)
  40. {
  41. }
  42. ThreadImpl::~ThreadImpl()
  43. {
  44. if (m_ThreadHandle != NULL)
  45. CloseHandle(m_ThreadHandle);
  46. }
  47. size_t ThreadImpl::Id()
  48. {
  49. return m_ThreadId;
  50. }
  51. void ThreadImpl::SetNameForDebugger(const char* name)
  52. {
  53. // http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
  54. const DWORD MS_VC_EXCEPTION = 0x406D1388;
  55. #pragma pack(push,8)
  56. typedef struct tagTHREADNAME_INFO
  57. {
  58. DWORD dwType; // Must be 0x1000.
  59. LPCSTR szName; // Pointer to name (in user addr space).
  60. DWORD dwThreadID; // Thread ID (-1=caller thread).
  61. DWORD dwFlags; // Reserved for future use, must be zero.
  62. } THREADNAME_INFO;
  63. #pragma pack(pop)
  64. THREADNAME_INFO info;
  65. info.dwType = 0x1000;
  66. info.szName = name;
  67. info.dwThreadID = static_cast<DWORD>(Id());
  68. info.dwFlags = 0;
  69. __try
  70. {
  71. RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
  72. }
  73. __except (EXCEPTION_EXECUTE_HANDLER)
  74. {
  75. }
  76. }
  77. typedef HRESULT (__stdcall *SETTHREADPROC) (HANDLE, PCWSTR);
  78. void ThreadImpl::SetName(const char* name)
  79. {
  80. SetThreadDescription(m_ThreadHandle, utils::StringUtils::Utf8ToUtf16(name).c_str());
  81. if (Debug::IsDebuggerPresent())
  82. SetNameForDebugger(name);
  83. }
  84. void ThreadImpl::SetPriority(ThreadPriority priority)
  85. {
  86. if (m_ThreadHandle == NULL)
  87. m_Priority = priority;
  88. else
  89. {
  90. int ret = ::SetThreadPriority(m_ThreadHandle, priority - 2);
  91. IL2CPP_ASSERT(ret);
  92. }
  93. }
  94. ThreadPriority ThreadImpl::GetPriority()
  95. {
  96. if (m_ThreadHandle == NULL)
  97. return m_Priority;
  98. int ret = ::GetThreadPriority(m_ThreadHandle) + 2;
  99. IL2CPP_ASSERT(ret != THREAD_PRIORITY_ERROR_RETURN);
  100. return (ThreadPriority)ret;
  101. }
  102. ErrorCode ThreadImpl::Run(Thread::StartFunc func, void* arg, int64_t affinityMask)
  103. {
  104. // It might happen that func will start executing and will try to access m_ThreadId before CreateThread gets a chance to assign it.
  105. // Therefore m_ThreadId is assigned both by this thread and from the newly created thread (race condition could go the other way too).
  106. ThreadImplStartData* startData = (ThreadImplStartData*)malloc(sizeof(ThreadImplStartData));
  107. startData->m_StartFunc = func;
  108. startData->m_StartArg = arg;
  109. startData->m_ThreadId = &m_ThreadId;
  110. // Create thread.
  111. DWORD threadId;
  112. HANDLE threadHandle = ::CreateThread(NULL, m_StackSize, &ThreadStartWrapper, startData, STACK_SIZE_PARAM_IS_A_RESERVATION, &threadId);
  113. if (!threadHandle)
  114. return kErrorCodeGenFailure;
  115. #if IL2CPP_TARGET_WINDOWS_GAMES
  116. if (affinityMask != Thread::kThreadAffinityAll)
  117. SetThreadAffinityMask(threadHandle, static_cast<DWORD_PTR>(affinityMask));
  118. #endif
  119. m_ThreadHandle = threadHandle;
  120. m_ThreadId = threadId;
  121. SetPriority(m_Priority);
  122. return kErrorCodeSuccess;
  123. }
  124. void ThreadImpl::Sleep(uint32_t ms, bool interruptible)
  125. {
  126. /// An Event that we never signal. This is used for sleeping threads in an alertable state. They
  127. /// simply wait on this object with the sleep timer as the timeout. This way we don't need a separate
  128. /// codepath for implementing sleep logic.
  129. s_ThreadSleepObject->Wait(ms, interruptible);
  130. }
  131. void ThreadImpl::CheckForUserAPCAndHandle()
  132. {
  133. m_PendingAPCsMutex.Acquire();
  134. while (!m_PendingAPCs.empty())
  135. {
  136. APCRequest apcRequest = m_PendingAPCs.front();
  137. // Remove from list. Do before calling the function to make sure the list
  138. // is up to date in case the function throws.
  139. m_PendingAPCs.erase(m_PendingAPCs.begin());
  140. // Release mutex while we call the function so that we don't deadlock
  141. // if the function starts waiting on a thread that tries queuing an APC
  142. // on us.
  143. m_PendingAPCsMutex.Release();
  144. // Call function.
  145. apcRequest.callback(apcRequest.context);
  146. // Re-acquire mutex.
  147. m_PendingAPCsMutex.Acquire();
  148. }
  149. m_PendingAPCsMutex.Release();
  150. }
  151. void ThreadImpl::SetWaitObject(WaitObject* waitObject)
  152. {
  153. // This is an unprotected write as write acccess is restricted to the
  154. // current thread.
  155. m_CurrentWaitObject = waitObject;
  156. }
  157. void ThreadImpl::QueueUserAPC(Thread::APCFunc func, void* context)
  158. {
  159. IL2CPP_ASSERT(func != NULL);
  160. // Put on queue.
  161. {
  162. m_PendingAPCsMutex.Acquire();
  163. m_PendingAPCs.push_back(APCRequest(func, context));
  164. m_PendingAPCsMutex.Release();
  165. }
  166. // Interrupt an ongoing wait, only interrupt if we have an object waiting
  167. if (m_CurrentWaitObject.load())
  168. {
  169. m_ConditionSemaphore.Release(1);
  170. }
  171. }
  172. int ThreadImpl::GetMaxStackSize()
  173. {
  174. return INT_MAX;
  175. }
  176. ThreadImpl* ThreadImpl::GetCurrentThread()
  177. {
  178. return Thread::GetCurrentThread()->m_Thread;
  179. }
  180. namespace
  181. {
  182. ApartmentState GetApartmentImpl(bool* implicit)
  183. {
  184. *implicit = false;
  185. APTTYPE type;
  186. APTTYPEQUALIFIER qualifier;
  187. const HRESULT hr = CoGetApartmentType(&type, &qualifier);
  188. if (FAILED(hr))
  189. {
  190. IL2CPP_ASSERT(CO_E_NOTINITIALIZED == hr);
  191. return kApartmentStateUnknown;
  192. }
  193. switch (type)
  194. {
  195. case APTTYPE_STA:
  196. case APTTYPE_MAINSTA:
  197. return kApartmentStateInSTA;
  198. case APTTYPE_MTA:
  199. *implicit = (APTTYPEQUALIFIER_IMPLICIT_MTA == qualifier);
  200. return kApartmentStateInMTA;
  201. case APTTYPE_NA:
  202. switch (qualifier)
  203. {
  204. case APTTYPEQUALIFIER_NA_ON_STA:
  205. case APTTYPEQUALIFIER_NA_ON_MAINSTA:
  206. return kApartmentStateInSTA;
  207. case APTTYPEQUALIFIER_NA_ON_MTA:
  208. return kApartmentStateInMTA;
  209. case APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA:
  210. *implicit = true;
  211. return kApartmentStateInMTA;
  212. }
  213. break;
  214. }
  215. IL2CPP_ASSERT(0 && "CoGetApartmentType returned unexpected value.");
  216. return kApartmentStateUnknown;
  217. }
  218. }
  219. ApartmentState ThreadImpl::GetApartment()
  220. {
  221. Assert(GetCurrentThreadId() == m_ThreadId);
  222. ApartmentState state = static_cast<ApartmentState>(m_ApartmentState & ~kApartmentStateCoInitialized);
  223. if (kApartmentStateUnknown == state)
  224. {
  225. bool implicit;
  226. state = GetApartmentImpl(&implicit);
  227. if (!implicit)
  228. m_ApartmentState = state;
  229. }
  230. return state;
  231. }
  232. ApartmentState ThreadImpl::GetExplicitApartment()
  233. {
  234. return static_cast<ApartmentState>(m_ApartmentState & ~kApartmentStateCoInitialized);
  235. }
  236. ApartmentState ThreadImpl::SetApartment(ApartmentState state)
  237. {
  238. Assert(GetCurrentThreadId() == m_ThreadId);
  239. // Unknown state uninitializes COM.
  240. if (kApartmentStateUnknown == state)
  241. {
  242. if (m_ApartmentState & kApartmentStateCoInitialized)
  243. {
  244. CoUninitialize();
  245. m_ApartmentState = kApartmentStateUnknown;
  246. }
  247. return GetApartment();
  248. }
  249. // Initialize apartment state. Ignore result of this function because it will return MTA value for both implicit and explicit apartment.
  250. // On the other hand m_ApartmentState will only be set to MTA if it was initialized explicitly with CoInitializeEx.
  251. GetApartment();
  252. ApartmentState currentState = static_cast<ApartmentState>(m_ApartmentState & ~kApartmentStateCoInitialized);
  253. if (kApartmentStateUnknown != currentState)
  254. {
  255. Assert(state == currentState);
  256. return currentState;
  257. }
  258. HRESULT hr = CoInitializeEx(nullptr, (kApartmentStateInSTA == state) ? COINIT_APARTMENTTHREADED : COINIT_MULTITHREADED);
  259. if (SUCCEEDED(hr))
  260. {
  261. m_ApartmentState = state;
  262. if (S_OK == hr)
  263. m_ApartmentState = static_cast<ApartmentState>(m_ApartmentState | kApartmentStateCoInitialized);
  264. else
  265. CoUninitialize(); // Someone has already called correct CoInitialize. Don't leave incorrect reference count.
  266. }
  267. else if (RPC_E_CHANGED_MODE == hr)
  268. {
  269. // CoInitialize has already been called with a different apartment state.
  270. m_ApartmentState = (kApartmentStateInSTA == state) ? kApartmentStateInMTA : kApartmentStateInSTA;
  271. }
  272. else
  273. {
  274. // Based on where this function is called (Init and Shutdown) we can't really recover from this, so
  275. // just abort.
  276. abort();
  277. }
  278. return GetApartment();
  279. }
  280. void ThreadImpl::SetExplicitApartment(ApartmentState state)
  281. {
  282. Assert(!(m_ApartmentState & kApartmentStateCoInitialized));
  283. m_ApartmentState = state;
  284. }
  285. size_t ThreadImpl::CurrentThreadId()
  286. {
  287. return GetCurrentThreadId();
  288. }
  289. ThreadImpl* ThreadImpl::CreateForCurrentThread()
  290. {
  291. ThreadImpl* thread = new ThreadImpl();
  292. BOOL duplicateResult = DuplicateHandle(::GetCurrentProcess(), ::GetCurrentThread(), ::GetCurrentProcess(), &thread->m_ThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
  293. Assert(duplicateResult && "DuplicateHandle failed.");
  294. thread->m_ThreadId = ::GetCurrentThreadId();
  295. return thread;
  296. }
  297. bool ThreadImpl::YieldInternal()
  298. {
  299. return SwitchToThread();
  300. }
  301. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  302. static Thread::ThreadCleanupFunc s_ThreadCleanupFunction;
  303. static ThreadLocalValue s_ThreadCleanupArguments;
  304. void ThreadImpl::SetNativeThreadCleanup(Thread::ThreadCleanupFunc cleanupFunction)
  305. {
  306. s_ThreadCleanupFunction = cleanupFunction;
  307. }
  308. void ThreadImpl::RegisterCurrentThreadForCleanup(void* arg)
  309. {
  310. s_ThreadCleanupArguments.SetValue(arg);
  311. }
  312. void ThreadImpl::UnregisterCurrentThreadForCleanup()
  313. {
  314. s_ThreadCleanupArguments.SetValue(NULL);
  315. }
  316. void ThreadImpl::OnCurrentThreadExiting()
  317. {
  318. Thread::ThreadCleanupFunc cleanupFunction = s_ThreadCleanupFunction;
  319. if (cleanupFunction == NULL)
  320. return;
  321. void* threadCleanupArgument = NULL;
  322. s_ThreadCleanupArguments.GetValue(&threadCleanupArgument);
  323. if (threadCleanupArgument != NULL)
  324. cleanupFunction(threadCleanupArgument);
  325. }
  326. #endif
  327. }
  328. }
  329. #endif