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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. #include "il2cpp-config.h"
  2. #include "os/Mutex.h"
  3. #include "os/Thread.h"
  4. #include "os/ThreadLocalValue.h"
  5. #include "os/Time.h"
  6. #include "os/Semaphore.h"
  7. #include "vm/Domain.h"
  8. #include "vm/Exception.h"
  9. #include "vm/Object.h"
  10. #include "vm/Profiler.h"
  11. #include "vm/Runtime.h"
  12. #include "vm/StackTrace.h"
  13. #include "vm/Thread.h"
  14. #include "vm/String.h"
  15. #include "gc/Allocator.h"
  16. #include "gc/GarbageCollector.h"
  17. #include "gc/GCHandle.h"
  18. #include "gc/WriteBarrier.h"
  19. #include "utils/Memory.h"
  20. #include "utils/StringUtils.h"
  21. #include "vm-utils/Debugger.h"
  22. #include "il2cpp-class-internals.h"
  23. #include "il2cpp-object-internals.h"
  24. #include <algorithm>
  25. #include "Baselib.h"
  26. #include "Cpp/Atomic.h"
  27. #include "Cpp/ReentrantLock.h"
  28. namespace il2cpp
  29. {
  30. namespace vm
  31. {
  32. Il2CppThread* Thread::s_MainThread = NULL;
  33. typedef std::vector<Il2CppThread*, il2cpp::gc::Allocator<Il2CppThread*> > GCTrackedThreadVector;
  34. // we need to allocate this ourselves so the CRT does not initialize it and try to allocate GC memory on startup before the GC is initialized
  35. static GCTrackedThreadVector* s_AttachedThreads;
  36. static bool s_BlockNewThreads = false;
  37. #define AUTO_LOCK_THREADS() il2cpp::os::FastAutoLock lock(&s_ThreadMutex)
  38. static baselib::ReentrantLock s_ThreadMutex;
  39. static std::vector<int32_t> s_ThreadStaticSizes;
  40. static il2cpp::os::ThreadLocalValue s_CurrentThread;
  41. static il2cpp::os::ThreadLocalValue s_StaticData; // Cache the static thread data in a local TLS slot for faster lookup
  42. static baselib::atomic<int32_t> s_NextManagedThreadId = {0};
  43. /*
  44. Thread static data is stored in a two level lookup so we can grow the size at runtime
  45. without requiring a lock on looking up static data
  46. We pre-allocate a fixed number of slot pointers - kMaxThreadStaticSlots at startup.
  47. Each of these slots can hold kMaxThreadStaticDataPointers data pointer. These slots
  48. are allocated as needed.
  49. */
  50. const int32_t kMaxThreadStaticSlots = 1024;
  51. const int32_t kMaxThreadStaticDataPointers = 1024;
  52. struct ThreadStaticOffset
  53. {
  54. uint32_t slot;
  55. uint32_t index;
  56. };
  57. static ThreadStaticOffset IndexToStaticFieldOffset(int32_t index)
  58. {
  59. static_assert(kMaxThreadStaticSlots <= 0xFFFF, "Only 65535 base thread static slots are supported");
  60. static_assert(kMaxThreadStaticDataPointers <= 0xFFFF, "Only 65535 thread static slots are supported");
  61. uint32_t value = (uint32_t)index;
  62. ThreadStaticOffset offset;
  63. offset.slot = value >> 16;
  64. offset.index = value & 0xFFFF;
  65. return offset;
  66. }
  67. struct ThreadStaticDataSlot
  68. {
  69. void* data[kMaxThreadStaticSlots];
  70. };
  71. struct ThreadStaticData
  72. {
  73. ThreadStaticDataSlot* slots[kMaxThreadStaticSlots];
  74. };
  75. static void
  76. set_wbarrier_for_attached_threads()
  77. {
  78. gc::GarbageCollector::SetWriteBarrier((void**)s_AttachedThreads->data(), sizeof(Il2CppThread*) * s_AttachedThreads->size());
  79. }
  80. static void
  81. thread_cleanup_on_cancel(void* arg)
  82. {
  83. Thread::Detach((Il2CppThread*)arg, true);
  84. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  85. il2cpp::os::Thread* osThread = ((Il2CppThread*)arg)->GetInternalThread()->handle;
  86. osThread->SignalExited();
  87. #endif
  88. }
  89. void Thread::Initialize()
  90. {
  91. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  92. os::Thread::SetNativeThreadCleanup(&thread_cleanup_on_cancel);
  93. #endif
  94. #if IL2CPP_ENABLE_RELOAD
  95. s_BlockNewThreads = false;
  96. #endif
  97. s_AttachedThreads = new GCTrackedThreadVector();
  98. }
  99. void Thread::Uninitialize()
  100. {
  101. IL2CPP_ASSERT(Current() == Main());
  102. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  103. os::Thread::SetNativeThreadCleanup(NULL);
  104. #endif
  105. delete s_AttachedThreads;
  106. s_AttachedThreads = NULL;
  107. s_MainThread = NULL;
  108. }
  109. Il2CppThread* Thread::Attach(Il2CppDomain *domain)
  110. {
  111. Il2CppThread* managedThread = Current();
  112. if (managedThread != NULL)
  113. return managedThread;
  114. gc::GarbageCollector::RegisterThread();
  115. StackTrace::InitializeStackTracesForCurrentThread();
  116. // Get/create OS thread representing the current thread. For pre-existing threads such as
  117. // the main thread, this will create an OS thread instance on demand. For threads that have
  118. // been started through our OS layer, there will already be an instance.
  119. os::Thread* osThread = os::Thread::GetOrCreateCurrentThread();
  120. // Create managed object representing the current thread.
  121. managedThread = (Il2CppThread*)Object::New(il2cpp_defaults.thread_class);
  122. SetupInternalManagedThread(managedThread, osThread);
  123. managedThread->GetInternalThread()->state = kThreadStateRunning;
  124. InitializeManagedThread(managedThread, domain);
  125. return managedThread;
  126. }
  127. void Thread::SetupInternalManagedThread(Il2CppThread* thread, os::Thread* osThread)
  128. {
  129. Il2CppInternalThread* internalManagedThread = (Il2CppInternalThread*)Object::New(il2cpp_defaults.internal_thread_class);
  130. internalManagedThread->handle = osThread;
  131. internalManagedThread->tid = osThread->Id();
  132. internalManagedThread->managed_id = GetNewManagedId();
  133. // The synch_cs object is deallocated in the InternalThread::Thread_free_internal icall, which
  134. // is called from the managed thread finalizer.
  135. internalManagedThread->longlived = (Il2CppLongLivedThreadData*)IL2CPP_MALLOC(sizeof(Il2CppLongLivedThreadData));
  136. internalManagedThread->longlived->synch_cs = new baselib::ReentrantLock;
  137. internalManagedThread->apartment_state = il2cpp::os::kApartmentStateUnknown;
  138. gc::WriteBarrier::GenericStore(&thread->internal_thread, internalManagedThread);
  139. }
  140. void Thread::InitializeManagedThread(Il2CppThread* thread, Il2CppDomain* domain)
  141. {
  142. #if IL2CPP_SUPPORT_THREADS
  143. IL2CPP_ASSERT(thread->GetInternalThread()->handle != NULL);
  144. IL2CPP_ASSERT(thread->GetInternalThread()->longlived->synch_cs != NULL);
  145. #endif
  146. #if IL2CPP_MONO_DEBUGGER
  147. utils::Debugger::AllocateThreadLocalData();
  148. #endif
  149. s_CurrentThread.SetValue(thread);
  150. Domain::ContextSet(domain->default_context);
  151. Register(thread);
  152. AllocateStaticDataForCurrentThread();
  153. #if IL2CPP_MONO_DEBUGGER
  154. utils::Debugger::ThreadStarted((uintptr_t)thread->GetInternalThread()->tid);
  155. #endif
  156. #if IL2CPP_ENABLE_PROFILER
  157. vm::Profiler::ThreadStart(((unsigned long)thread->GetInternalThread()->tid));
  158. #endif
  159. // Sync thread name.
  160. if (thread->GetInternalThread()->name.chars)
  161. {
  162. std::string utf8Name = il2cpp::utils::StringUtils::Utf16ToUtf8(thread->GetInternalThread()->name.chars);
  163. thread->GetInternalThread()->handle->SetName(utf8Name.c_str());
  164. }
  165. // Sync thread apartment state.
  166. thread->GetInternalThread()->apartment_state = thread->GetInternalThread()->handle->GetApartment();
  167. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  168. // register us for platform specific cleanup attempt in case thread is not exited cleanly
  169. os::Thread::RegisterCurrentThreadForCleanup(thread);
  170. #endif
  171. // If an interrupt has been requested before the thread was started, re-request
  172. // the interrupt now.
  173. if (thread->GetInternalThread()->interruption_requested)
  174. RequestInterrupt(thread);
  175. }
  176. void Thread::UninitializeManagedThread(Il2CppThread* thread)
  177. {
  178. Thread::UninitializeManagedThread(thread, false);
  179. }
  180. void Thread::UninitializeManagedThread(Il2CppThread *thread, bool inNativeThreadCleanup)
  181. {
  182. // This method is only valid to call from the current thread
  183. // But we can't safely check the Current() in native thread shutdown
  184. // because we can't rely on TLS values being valid
  185. IL2CPP_ASSERT(inNativeThreadCleanup || thread == Current());
  186. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  187. // unregister from special cleanup since we are doing it now
  188. os::Thread::UnregisterCurrentThreadForCleanup();
  189. #endif
  190. if (!gc::GarbageCollector::UnregisterThread())
  191. IL2CPP_ASSERT(0 && "gc::GarbageCollector::UnregisterThread failed");
  192. #if IL2CPP_ENABLE_PROFILER
  193. vm::Profiler::ThreadEnd(((unsigned long)thread->GetInternalThread()->tid));
  194. #endif
  195. #if IL2CPP_MONO_DEBUGGER
  196. // Only raise the event for the debugger if there is a current thread at the OS thread level.
  197. // The debugger code will try to take a lock, which requires a current thread. If this
  198. // thread is being detached by a call from thread_cleanup_on_cancel, then there might
  199. // not be a current thread, as pthreads does not privide TLS entries in thread destructors.
  200. if (os::Thread::HasCurrentThread())
  201. utils::Debugger::ThreadStopped((uintptr_t)thread->GetInternalThread()->tid);
  202. #endif
  203. FreeCurrentThreadStaticData(thread, inNativeThreadCleanup);
  204. // Call Unregister after all access to managed objects (Il2CppThread and Il2CppInternalThread)
  205. // is complete. Unregister will remove the managed thread object from the GC tracked vector of
  206. // attached threads, and allow it to be finalized and re-used. If runtime code accesses it
  207. // after a call to Unregister, there will be a race condition between the GC and the runtime
  208. // code for access to that object.
  209. Unregister(thread);
  210. #if IL2CPP_MONO_DEBUGGER
  211. utils::Debugger::FreeThreadLocalData();
  212. #endif
  213. os::Thread::DetachCurrentThread();
  214. s_CurrentThread.SetValue(NULL);
  215. }
  216. Il2CppThread* Thread::Current()
  217. {
  218. void* value = NULL;
  219. s_CurrentThread.GetValue(&value);
  220. return (Il2CppThread*)value;
  221. }
  222. static void STDCALL TerminateThread(void* context)
  223. {
  224. // We throw a dummy exception to make sure things clean up properly
  225. // and we don't leave any locks behind (such as global locks in the allocator which
  226. // would then deadlock other threads). This could work off ThreadAbortException
  227. // but we don't want to deal with a managed exception here. So we use a C++ exception.
  228. throw Thread::NativeThreadAbortException();
  229. }
  230. static bool IsDebuggerThread(os::Thread* thread)
  231. {
  232. #if IL2CPP_MONO_DEBUGGER
  233. return utils::Debugger::IsDebuggerThread(thread);
  234. #else
  235. return false;
  236. #endif
  237. }
  238. // This function requests that all threads exit
  239. // If a thread is in a non-alertable wait it may not have exited when this method exits
  240. void Thread::AbortAllThreads()
  241. {
  242. #if IL2CPP_SUPPORT_THREADS
  243. Il2CppThread* gcFinalizerThread = NULL;
  244. Il2CppThread* currentThread = Current();
  245. IL2CPP_ASSERT(currentThread != NULL && "No current thread!");
  246. s_ThreadMutex.Acquire();
  247. s_BlockNewThreads = true;
  248. GCTrackedThreadVector attachedThreadsCopy = *s_AttachedThreads;
  249. // In theory, we don't need a write barrier here for Boehm, because we keep a
  250. // reference to the object on the stack during it's lifetime. But for validation
  251. // tests, we turn off GC, and thus we need it to pass.
  252. gc::GarbageCollector::SetWriteBarrier((void**)attachedThreadsCopy.data(), sizeof(Il2CppThread*) * attachedThreadsCopy.size());
  253. s_ThreadMutex.Release();
  254. std::vector<os::Thread*> activeThreads;
  255. // Kill all threads but the finalizer and current one. We temporarily flush out
  256. // the entire list and then just put the two threads back.
  257. while (attachedThreadsCopy.size())
  258. {
  259. Il2CppThread* thread = attachedThreadsCopy.back();
  260. os::Thread* osThread = thread->GetInternalThread()->handle;
  261. if (gc::GarbageCollector::IsFinalizerThread(thread))
  262. {
  263. IL2CPP_ASSERT(gcFinalizerThread == NULL && "There seems to be more than one finalizer thread!");
  264. gcFinalizerThread = thread;
  265. }
  266. else if (thread != currentThread && !IsDebuggerThread(osThread))
  267. {
  268. ////TODO: use Thread.Abort() instead
  269. osThread->QueueUserAPC(TerminateThread, NULL);
  270. activeThreads.push_back(osThread);
  271. }
  272. attachedThreadsCopy.pop_back();
  273. }
  274. // In theory, we don't need a write barrier here for Boehm, because we keep a
  275. // reference to the object on the stack during it's lifetime. But for validation
  276. // tests, we turn off GC, and thus we need it to pass.
  277. gc::GarbageCollector::SetWriteBarrier((void**)attachedThreadsCopy.data(), sizeof(Il2CppThread*) * attachedThreadsCopy.size());
  278. ////FIXME: While we don't have stable thread abortion in place yet, work around problems in
  279. //// the current implementation by repeatedly requesting threads to terminate. This works around
  280. //// race condition to some extent.
  281. while (activeThreads.size())
  282. {
  283. os::Thread* osThread = activeThreads.back();
  284. // Wait for the thread.
  285. if (osThread->Join(10) == kWaitStatusSuccess)
  286. activeThreads.pop_back();
  287. else
  288. {
  289. ////TODO: use Thread.Abort() instead
  290. osThread->QueueUserAPC(TerminateThread, NULL);
  291. }
  292. }
  293. AUTO_LOCK_THREADS();
  294. s_AttachedThreads->clear();
  295. // Put finalizer and current thread back in list.
  296. IL2CPP_ASSERT(gcFinalizerThread != NULL && "GC finalizer thread was not found in list of attached threads!");
  297. if (gcFinalizerThread)
  298. s_AttachedThreads->push_back(gcFinalizerThread);
  299. if (currentThread)
  300. s_AttachedThreads->push_back(currentThread);
  301. set_wbarrier_for_attached_threads();
  302. #endif
  303. }
  304. void Thread::Detach(Il2CppThread* thread)
  305. {
  306. Thread::Detach(thread, false);
  307. }
  308. void Thread::Detach(Il2CppThread *thread, bool inNativeThreadCleanup)
  309. {
  310. IL2CPP_ASSERT(thread != NULL && "Cannot detach a NULL thread");
  311. UninitializeManagedThread(thread, inNativeThreadCleanup);
  312. il2cpp::vm::StackTrace::CleanupStackTracesForCurrentThread();
  313. }
  314. Il2CppThread* Thread::Main()
  315. {
  316. return s_MainThread;
  317. }
  318. void Thread::SetMain(Il2CppThread* thread)
  319. {
  320. IL2CPP_ASSERT(s_MainThread == NULL);
  321. s_MainThread = thread;
  322. }
  323. void Thread::SetState(Il2CppThread *thread, ThreadState value)
  324. {
  325. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  326. thread->GetInternalThread()->state |= value;
  327. }
  328. void Thread::ClrState(Il2CppInternalThread* thread, ThreadState clr)
  329. {
  330. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  331. thread->state &= ~clr;
  332. }
  333. void Thread::SetState(Il2CppInternalThread *thread, ThreadState value)
  334. {
  335. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  336. thread->state |= value;
  337. }
  338. ThreadState Thread::GetState(Il2CppInternalThread *thread)
  339. {
  340. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  341. return (ThreadState)thread->state;
  342. }
  343. bool Thread::TestState(Il2CppInternalThread* thread, ThreadState value)
  344. {
  345. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  346. return (thread->state & value) != 0;
  347. }
  348. Il2CppInternalThread* Thread::CurrentInternal()
  349. {
  350. return Current()->GetInternalThread();
  351. }
  352. ThreadState Thread::GetState(Il2CppThread *thread)
  353. {
  354. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  355. return (ThreadState)thread->GetInternalThread()->state;
  356. }
  357. void Thread::ClrState(Il2CppThread* thread, ThreadState state)
  358. {
  359. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  360. thread->GetInternalThread()->state &= ~state;
  361. }
  362. static void AllocThreadDataSlot(ThreadStaticData* staticData, ThreadStaticOffset offset, int32_t size)
  363. {
  364. if (staticData->slots[offset.slot] == NULL)
  365. staticData->slots[offset.slot] = (ThreadStaticDataSlot*)IL2CPP_CALLOC(1, sizeof(ThreadStaticDataSlot));
  366. if (staticData->slots[offset.slot]->data[offset.index] == NULL)
  367. staticData->slots[offset.slot]->data[offset.index] = gc::GarbageCollector::AllocateFixed(size, NULL);
  368. }
  369. void Thread::AllocateStaticDataForCurrentThread()
  370. {
  371. AUTO_LOCK_THREADS();
  372. int32_t index = 0;
  373. // Alloc the slotData along with the first slots at once
  374. ThreadStaticData* staticData = (ThreadStaticData*)IL2CPP_CALLOC(1, sizeof(ThreadStaticData) + sizeof(ThreadStaticDataSlot));
  375. staticData->slots[0] = (ThreadStaticDataSlot*)(staticData + 1);
  376. Il2CppThread* thread = Current();
  377. IL2CPP_ASSERT(!thread->GetInternalThread()->static_data);
  378. thread->GetInternalThread()->static_data = staticData;
  379. s_StaticData.SetValue(staticData);
  380. for (std::vector<int32_t>::const_iterator iter = s_ThreadStaticSizes.begin(); iter != s_ThreadStaticSizes.end(); ++iter)
  381. {
  382. AllocThreadDataSlot(staticData, IndexToStaticFieldOffset(index), *iter);
  383. index++;
  384. }
  385. }
  386. int32_t Thread::AllocThreadStaticData(int32_t size)
  387. {
  388. AUTO_LOCK_THREADS();
  389. int32_t index = (int32_t)s_ThreadStaticSizes.size();
  390. IL2CPP_ASSERT(index < kMaxThreadStaticSlots * kMaxThreadStaticDataPointers);
  391. if (index >= kMaxThreadStaticSlots * kMaxThreadStaticDataPointers)
  392. il2cpp::vm::Exception::Raise(Exception::GetExecutionEngineException("Out of thread static storage slots"));
  393. s_ThreadStaticSizes.push_back(size);
  394. ThreadStaticOffset offset = IndexToStaticFieldOffset(index);
  395. for (GCTrackedThreadVector::const_iterator iter = s_AttachedThreads->begin(); iter != s_AttachedThreads->end(); ++iter)
  396. {
  397. Il2CppThread* thread = *iter;
  398. ThreadStaticData* staticData = reinterpret_cast<ThreadStaticData*>(thread->GetInternalThread()->static_data);
  399. if (staticData == NULL)
  400. {
  401. // There is a race on staticData for a thread could be NULL here in two cases
  402. // 1. The thread hasn't entered AllocateStaticDataForCurrentThread yet
  403. // 2. The thread has exited FreeCurrentThreadStaticData but hasn't been remove from the s_AttachedThreads yet
  404. // In both cases we can just continue and in 1. the data will be allocated in AllocateStaticDataForCurrentThread
  405. // and in 2. we don't want to allocate anything
  406. continue;
  407. }
  408. AllocThreadDataSlot(staticData, offset, size);
  409. }
  410. return index;
  411. }
  412. void Thread::FreeCurrentThreadStaticData(Il2CppThread *thread, bool inNativeThreadCleanup)
  413. {
  414. // This method is only valid to call from the current thread
  415. // But we can't safely check the Current() in native thread shutdown
  416. // because we can't rely on TLS values being valid
  417. IL2CPP_ASSERT(inNativeThreadCleanup || thread == Current());
  418. AUTO_LOCK_THREADS();
  419. ThreadStaticData* staticData = reinterpret_cast<ThreadStaticData*>(thread->GetInternalThread()->static_data);
  420. thread->GetInternalThread()->static_data = NULL;
  421. s_StaticData.SetValue(NULL);
  422. // This shouldn't happen unless we call this twice, but there's no reason to crash here
  423. IL2CPP_ASSERT(staticData);
  424. if (staticData == NULL)
  425. return;
  426. for (int slot = 0; slot < kMaxThreadStaticSlots; slot++)
  427. {
  428. if (!staticData->slots[slot])
  429. break;
  430. for (int i = 0; i < kMaxThreadStaticDataPointers; i++)
  431. {
  432. if (!staticData->slots[slot]->data[i])
  433. break;
  434. gc::GarbageCollector::FreeFixed(staticData->slots[slot]->data[i]);
  435. }
  436. // Don't free the first slot because we allocate the first slot along with the root slots
  437. if (slot > 0)
  438. IL2CPP_FREE(staticData->slots[slot]);
  439. }
  440. IL2CPP_FREE(staticData);
  441. }
  442. void* Thread::GetThreadStaticData(int32_t offset)
  443. {
  444. // No lock. We allocate static_data once with a fixed size so we can read it
  445. // safely without a lock here.
  446. IL2CPP_ASSERT(offset >= 0 && static_cast<uint32_t>(offset) < s_ThreadStaticSizes.size());
  447. ThreadStaticOffset staticOffset = IndexToStaticFieldOffset(offset);
  448. ThreadStaticData* staticData;
  449. s_StaticData.GetValue((void**)&staticData);
  450. IL2CPP_ASSERT(staticData != NULL);
  451. return staticData->slots[staticOffset.slot]->data[staticOffset.index];
  452. }
  453. void* Thread::GetThreadStaticDataForThread(int32_t offset, Il2CppInternalThread* thread)
  454. {
  455. // No lock. We allocate static_data once with a fixed size so we can read it
  456. // safely without a lock here.
  457. IL2CPP_ASSERT(offset >= 0 && static_cast<uint32_t>(offset) < s_ThreadStaticSizes.size());
  458. IL2CPP_ASSERT(thread->static_data != NULL);
  459. ThreadStaticOffset staticOffset = IndexToStaticFieldOffset(offset);
  460. return reinterpret_cast<ThreadStaticData*>(thread->static_data)->slots[staticOffset.slot]->data[staticOffset.index];
  461. }
  462. void Thread::Register(Il2CppThread *thread)
  463. {
  464. AUTO_LOCK_THREADS();
  465. if (s_BlockNewThreads)
  466. TerminateThread(NULL);
  467. else
  468. {
  469. s_AttachedThreads->push_back(thread);
  470. set_wbarrier_for_attached_threads();
  471. }
  472. }
  473. void Thread::Unregister(Il2CppThread *thread)
  474. {
  475. AUTO_LOCK_THREADS();
  476. GCTrackedThreadVector::iterator it = std::find(s_AttachedThreads->begin(), s_AttachedThreads->end(), thread);
  477. #if IL2CPP_MONO_DEBUGGER
  478. if (it == s_AttachedThreads->end() && thread->internal_thread && il2cpp::utils::Debugger::IsDebuggerThread(thread->internal_thread->handle))
  479. return;
  480. #endif
  481. IL2CPP_ASSERT(it != s_AttachedThreads->end() && "Vm thread not found in list of attached threads.");
  482. s_AttachedThreads->erase(it);
  483. set_wbarrier_for_attached_threads();
  484. }
  485. bool Thread::IsVmThread(Il2CppThread *thread)
  486. {
  487. return !gc::GarbageCollector::IsFinalizerThread(thread);
  488. }
  489. std::string Thread::GetName(Il2CppInternalThread* thread)
  490. {
  491. if (thread->name.chars == NULL)
  492. return std::string();
  493. return utils::StringUtils::Utf16ToUtf8(thread->name.chars);
  494. }
  495. void Thread::SetName(Il2CppThread* thread, Il2CppString* name)
  496. {
  497. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  498. // Throw if already set.
  499. if (thread->GetInternalThread()->name.length != 0)
  500. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetInvalidOperationException("Thread name can only be set once."));
  501. // Store name.
  502. thread->GetInternalThread()->name.length = utils::StringUtils::GetLength(name);
  503. thread->GetInternalThread()->name.chars = il2cpp::utils::StringUtils::StringDuplicate(utils::StringUtils::GetChars(name), thread->GetInternalThread()->name.length);
  504. // Hand over to OS layer, if thread has been started already.
  505. if (thread->GetInternalThread()->handle)
  506. {
  507. std::string utf8Name = il2cpp::utils::StringUtils::Utf16ToUtf8(thread->GetInternalThread()->name.chars);
  508. thread->GetInternalThread()->handle->SetName(utf8Name.c_str());
  509. }
  510. }
  511. void Thread::SetName(Il2CppInternalThread* thread, Il2CppString* name)
  512. {
  513. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  514. // Throw if already set.
  515. if (thread->name.length != 0)
  516. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetInvalidOperationException("Thread name can only be set once."));
  517. // Store name.
  518. thread->name.length = utils::StringUtils::GetLength(name);
  519. thread->name.chars = il2cpp::utils::StringUtils::StringDuplicate(utils::StringUtils::GetChars(name), thread->name.length);
  520. // Hand over to OS layer, if thread has been started already.
  521. if (thread->handle)
  522. {
  523. std::string utf8Name = il2cpp::utils::StringUtils::Utf16ToUtf8(thread->name.chars);
  524. thread->handle->SetName(utf8Name.c_str());
  525. }
  526. }
  527. static void STDCALL CheckCurrentThreadForInterruptCallback(void* context)
  528. {
  529. Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary();
  530. }
  531. void Thread::RequestInterrupt(Il2CppThread* thread)
  532. {
  533. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  534. thread->GetInternalThread()->interruption_requested = true;
  535. // If thread has already been started, queue an interrupt now.
  536. il2cpp::os::Thread* osThread = thread->GetInternalThread()->handle;
  537. if (osThread)
  538. osThread->QueueUserAPC(CheckCurrentThreadForInterruptCallback, NULL);
  539. }
  540. void Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary()
  541. {
  542. Il2CppThread* currentThread = il2cpp::vm::Thread::Current();
  543. if (!currentThread)
  544. return;
  545. il2cpp::os::FastAutoLock lock(currentThread->GetInternalThread()->longlived->synch_cs);
  546. // Don't throw if thread is not currently in waiting state or if there's
  547. // no pending interrupt.
  548. if (!currentThread->GetInternalThread()->interruption_requested
  549. || !(il2cpp::vm::Thread::GetState(currentThread) & il2cpp::vm::kThreadStateWaitSleepJoin))
  550. return;
  551. // Mark the current thread as being unblocked.
  552. currentThread->GetInternalThread()->interruption_requested = false;
  553. il2cpp::vm::Thread::ClrState(currentThread, il2cpp::vm::kThreadStateWaitSleepJoin);
  554. // Throw interrupt exception.
  555. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadInterruptedException());
  556. }
  557. static void STDCALL CheckCurrentThreadForAbortCallback(void* context)
  558. {
  559. Thread::CheckCurrentThreadForAbortAndThrowIfNecessary();
  560. }
  561. bool Thread::RequestAbort(Il2CppThread* thread)
  562. {
  563. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  564. ThreadState state = il2cpp::vm::Thread::GetState(thread);
  565. if (state & kThreadStateAbortRequested || state & kThreadStateStopped || state & kThreadStateStopRequested)
  566. return false;
  567. il2cpp::os::Thread* osThread = thread->GetInternalThread()->handle;
  568. if (osThread)
  569. {
  570. // If thread has already been started, queue an abort now.
  571. Thread::SetState(thread, kThreadStateAbortRequested);
  572. osThread->QueueUserAPC(CheckCurrentThreadForAbortCallback, NULL);
  573. }
  574. else
  575. {
  576. // If thread has not started, put it in the aborted state.
  577. Thread::SetState(thread, kThreadStateAborted);
  578. }
  579. return true;
  580. }
  581. bool Thread::RequestAbort(Il2CppInternalThread* thread)
  582. {
  583. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  584. ThreadState state = il2cpp::vm::Thread::GetState(thread);
  585. if (state & kThreadStateAbortRequested || state & kThreadStateStopped || state & kThreadStateStopRequested)
  586. return false;
  587. il2cpp::os::Thread* osThread = thread->handle;
  588. if (osThread)
  589. {
  590. // If thread has already been started, queue an abort now.
  591. Thread::SetState(thread, kThreadStateAbortRequested);
  592. osThread->QueueUserAPC(CheckCurrentThreadForAbortCallback, NULL);
  593. }
  594. else
  595. {
  596. // If thread has not started, put it in the aborted state.
  597. Thread::SetState(thread, kThreadStateAborted);
  598. }
  599. return true;
  600. }
  601. void Thread::SetPriority(Il2CppThread* thread, int32_t priority)
  602. {
  603. Il2CppInternalThread* internalThread = thread->GetInternalThread();
  604. il2cpp::os::FastAutoLock lock(internalThread->longlived->synch_cs);
  605. internalThread->handle->SetPriority((il2cpp::os::ThreadPriority)priority);
  606. }
  607. int32_t Thread::GetPriority(Il2CppThread* thread)
  608. {
  609. Il2CppInternalThread* internalThread = thread->GetInternalThread();
  610. il2cpp::os::FastAutoLock lock(internalThread->longlived->synch_cs);
  611. return internalThread->handle->GetPriority();
  612. }
  613. struct StartDataInternal
  614. {
  615. Il2CppThread* m_Thread;
  616. Il2CppDomain* m_Domain;
  617. void* m_Delegate;
  618. void* m_StartArg;
  619. il2cpp::os::Semaphore* m_Semaphore;
  620. };
  621. static void ThreadStart(void* arg)
  622. {
  623. StartDataInternal* startData = (StartDataInternal*)arg;
  624. startData->m_Semaphore->Wait();
  625. {
  626. gc::GarbageCollector::RegisterThread();
  627. il2cpp::vm::StackTrace::InitializeStackTracesForCurrentThread();
  628. bool attachSuccessful = false;
  629. try
  630. {
  631. il2cpp::vm::Thread::InitializeManagedThread(startData->m_Thread, startData->m_Domain);
  632. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateRunning);
  633. attachSuccessful = true;
  634. try
  635. {
  636. ((void(*)(void*))startData->m_Delegate)(startData->m_StartArg);
  637. }
  638. catch (Il2CppExceptionWrapper& ex)
  639. {
  640. // Only deal with the unhandled exception if the runtime is not
  641. // shutting down. Otherwise, the code to process the unhandled
  642. // exception might fail in unexpected ways, because it needs
  643. // the full runtime available. We've seen this cause crashes
  644. // that are difficult to reproduce locally.
  645. if (!il2cpp::vm::Runtime::IsShuttingDown())
  646. Runtime::UnhandledException(ex.ex);
  647. }
  648. }
  649. catch (il2cpp::vm::Thread::NativeThreadAbortException)
  650. {
  651. // Nothing to do. We've successfully aborted the thread.
  652. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateAborted);
  653. }
  654. il2cpp::vm::Thread::ClrState(startData->m_Thread, kThreadStateRunning);
  655. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateStopped);
  656. if (attachSuccessful)
  657. il2cpp::vm::Thread::UninitializeManagedThread(startData->m_Thread, false);
  658. il2cpp::vm::StackTrace::CleanupStackTracesForCurrentThread();
  659. }
  660. delete startData->m_Semaphore;
  661. gc::GarbageCollector::FreeFixed(startData);
  662. }
  663. Il2CppInternalThread* Thread::CreateInternal(void(*func)(void*), void* arg, bool threadpool_thread, uint32_t stack_size)
  664. {
  665. // The os::Thread object is deallocated in the InternalThread::Thread_free_internal icall, which
  666. // is called from the managed thread finalizer.
  667. os::Thread* osThread = new os::Thread();
  668. Il2CppThread* managedThread = (Il2CppThread*)Object::New(il2cpp_defaults.thread_class);
  669. SetupInternalManagedThread(managedThread, osThread);
  670. Il2CppInternalThread* internalManagedThread = managedThread->GetInternalThread();
  671. internalManagedThread->state = kThreadStateUnstarted;
  672. internalManagedThread->threadpool_thread = threadpool_thread;
  673. // use fixed GC memory since we are storing managed object pointers
  674. StartDataInternal* startData = (StartDataInternal*)gc::GarbageCollector::AllocateFixed(sizeof(StartDataInternal), NULL);
  675. gc::WriteBarrier::GenericStore(&startData->m_Thread, managedThread);
  676. gc::WriteBarrier::GenericStore(&startData->m_Domain, Domain::GetCurrent());
  677. startData->m_Delegate = (void*)func;
  678. startData->m_StartArg = arg;
  679. startData->m_Semaphore = new il2cpp::os::Semaphore(0);
  680. osThread->SetStackSize(stack_size);
  681. osThread->SetExplicitApartment(static_cast<il2cpp::os::ApartmentState>(managedThread->GetInternalThread()->apartment_state));
  682. il2cpp::os::ErrorCode status = osThread->Run(&ThreadStart, startData);
  683. if (status != il2cpp::os::kErrorCodeSuccess)
  684. {
  685. delete osThread;
  686. return NULL;
  687. }
  688. internalManagedThread->state &= ~kThreadStateUnstarted;
  689. startData->m_Semaphore->Post(1, NULL);
  690. return internalManagedThread;
  691. }
  692. void Thread::Stop(Il2CppInternalThread* thread)
  693. {
  694. IL2CPP_ASSERT(thread != CurrentInternal());
  695. if (!RequestAbort(thread))
  696. return;
  697. os::Thread* osThread = thread->handle;
  698. ////FIXME: While we don't have stable thread abortion in place yet, work around problems in
  699. //// the current implementation by repeatedly requesting threads to terminate. This works around
  700. //// race condition to some extent.
  701. while (true)
  702. {
  703. // If it's a background thread, request it to kill itself.
  704. if (GetState(thread) & kThreadStateBackground)
  705. {
  706. ////TODO: use Thread.Abort() instead
  707. osThread->QueueUserAPC(TerminateThread, NULL);
  708. }
  709. // Wait for the thread.
  710. if (osThread->Join(10) == kWaitStatusSuccess)
  711. break;
  712. }
  713. }
  714. void Thread::Sleep(uint32_t ms)
  715. {
  716. CurrentInternal()->handle->Sleep(ms);
  717. }
  718. bool Thread::YieldInternal()
  719. {
  720. return os::Thread::YieldInternal();
  721. }
  722. void Thread::SetDefaultAffinityMask(int64_t affinityMask)
  723. {
  724. #if defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
  725. os::Thread::SetDefaultAffinityMask(affinityMask);
  726. #endif
  727. }
  728. void Thread::CheckCurrentThreadForAbortAndThrowIfNecessary()
  729. {
  730. Il2CppThread* currentThread = il2cpp::vm::Thread::Current();
  731. if (!currentThread)
  732. return;
  733. il2cpp::os::FastAutoLock lock(currentThread->GetInternalThread()->longlived->synch_cs);
  734. ThreadState state = il2cpp::vm::Thread::GetState(currentThread);
  735. if (!(state & kThreadStateAbortRequested))
  736. return;
  737. // Throw interrupt exception.
  738. Il2CppException* abortException = il2cpp::vm::Exception::GetThreadAbortException();
  739. IL2CPP_OBJECT_SETREF(currentThread->GetInternalThread(), abort_exc, abortException);
  740. il2cpp::vm::Exception::Raise(abortException);
  741. }
  742. void Thread::ResetAbort(Il2CppThread* thread)
  743. {
  744. il2cpp::vm::Thread::ClrState(thread, kThreadStateAbortRequested);
  745. if (thread->GetInternalThread()->abort_exc == NULL)
  746. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadStateException("Unable to reset abort because no abort was requested."));
  747. }
  748. void Thread::ResetAbort(Il2CppInternalThread* thread)
  749. {
  750. il2cpp::vm::Thread::ClrState(thread, kThreadStateAbortRequested);
  751. if (thread->abort_exc == NULL)
  752. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadStateException("Unable to reset abort because no abort was requested."));
  753. }
  754. void Thread::FullMemoryBarrier()
  755. {
  756. os::Atomic::FullMemoryBarrier();
  757. }
  758. int32_t Thread::GetNewManagedId()
  759. {
  760. return ++s_NextManagedThreadId;
  761. }
  762. uint64_t Thread::GetId(Il2CppThread* thread)
  763. {
  764. return thread->GetInternalThread()->tid;
  765. }
  766. uint64_t Thread::GetId(Il2CppInternalThread* thread)
  767. {
  768. return thread->tid;
  769. }
  770. } /* namespace vm */
  771. } /* namespace il2cpp */