Thread.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  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. Il2CppThread** Thread::GetAllAttachedThreads(size_t &size)
  223. {
  224. size = s_AttachedThreads->size();
  225. return &(*s_AttachedThreads)[0];
  226. }
  227. static void STDCALL TerminateThread(void* context)
  228. {
  229. // We throw a dummy exception to make sure things clean up properly
  230. // and we don't leave any locks behind (such as global locks in the allocator which
  231. // would then deadlock other threads). This could work off ThreadAbortException
  232. // but we don't want to deal with a managed exception here. So we use a C++ exception.
  233. throw Thread::NativeThreadAbortException();
  234. }
  235. static bool IsDebuggerThread(os::Thread* thread)
  236. {
  237. #if IL2CPP_MONO_DEBUGGER
  238. return utils::Debugger::IsDebuggerThread(thread);
  239. #else
  240. return false;
  241. #endif
  242. }
  243. // This function requests that all threads exit
  244. // If a thread is in a non-alertable wait it may not have exited when this method exits
  245. void Thread::AbortAllThreads()
  246. {
  247. #if IL2CPP_SUPPORT_THREADS
  248. Il2CppThread* gcFinalizerThread = NULL;
  249. Il2CppThread* currentThread = Current();
  250. IL2CPP_ASSERT(currentThread != NULL && "No current thread!");
  251. s_ThreadMutex.Acquire();
  252. s_BlockNewThreads = true;
  253. GCTrackedThreadVector attachedThreadsCopy = *s_AttachedThreads;
  254. // In theory, we don't need a write barrier here for Boehm, because we keep a
  255. // reference to the object on the stack during it's lifetime. But for validation
  256. // tests, we turn off GC, and thus we need it to pass.
  257. gc::GarbageCollector::SetWriteBarrier((void**)attachedThreadsCopy.data(), sizeof(Il2CppThread*) * attachedThreadsCopy.size());
  258. s_ThreadMutex.Release();
  259. std::vector<os::Thread*> activeThreads;
  260. // Kill all threads but the finalizer and current one. We temporarily flush out
  261. // the entire list and then just put the two threads back.
  262. while (attachedThreadsCopy.size())
  263. {
  264. Il2CppThread* thread = attachedThreadsCopy.back();
  265. os::Thread* osThread = thread->GetInternalThread()->handle;
  266. if (gc::GarbageCollector::IsFinalizerThread(thread))
  267. {
  268. IL2CPP_ASSERT(gcFinalizerThread == NULL && "There seems to be more than one finalizer thread!");
  269. gcFinalizerThread = thread;
  270. }
  271. else if (thread != currentThread && !IsDebuggerThread(osThread))
  272. {
  273. ////TODO: use Thread.Abort() instead
  274. osThread->QueueUserAPC(TerminateThread, NULL);
  275. activeThreads.push_back(osThread);
  276. }
  277. attachedThreadsCopy.pop_back();
  278. }
  279. // In theory, we don't need a write barrier here for Boehm, because we keep a
  280. // reference to the object on the stack during it's lifetime. But for validation
  281. // tests, we turn off GC, and thus we need it to pass.
  282. gc::GarbageCollector::SetWriteBarrier((void**)attachedThreadsCopy.data(), sizeof(Il2CppThread*) * attachedThreadsCopy.size());
  283. ////FIXME: While we don't have stable thread abortion in place yet, work around problems in
  284. //// the current implementation by repeatedly requesting threads to terminate. This works around
  285. //// race condition to some extent.
  286. while (activeThreads.size())
  287. {
  288. os::Thread* osThread = activeThreads.back();
  289. // Wait for the thread.
  290. if (osThread->Join(10) == kWaitStatusSuccess)
  291. activeThreads.pop_back();
  292. else
  293. {
  294. ////TODO: use Thread.Abort() instead
  295. osThread->QueueUserAPC(TerminateThread, NULL);
  296. }
  297. }
  298. AUTO_LOCK_THREADS();
  299. s_AttachedThreads->clear();
  300. // Put finalizer and current thread back in list.
  301. IL2CPP_ASSERT(gcFinalizerThread != NULL && "GC finalizer thread was not found in list of attached threads!");
  302. if (gcFinalizerThread)
  303. s_AttachedThreads->push_back(gcFinalizerThread);
  304. if (currentThread)
  305. s_AttachedThreads->push_back(currentThread);
  306. set_wbarrier_for_attached_threads();
  307. #endif
  308. }
  309. void Thread::Detach(Il2CppThread* thread)
  310. {
  311. Thread::Detach(thread, false);
  312. }
  313. void Thread::Detach(Il2CppThread *thread, bool inNativeThreadCleanup)
  314. {
  315. IL2CPP_ASSERT(thread != NULL && "Cannot detach a NULL thread");
  316. UninitializeManagedThread(thread, inNativeThreadCleanup);
  317. il2cpp::vm::StackTrace::CleanupStackTracesForCurrentThread();
  318. }
  319. Il2CppThread* Thread::Main()
  320. {
  321. return s_MainThread;
  322. }
  323. void Thread::SetMain(Il2CppThread* thread)
  324. {
  325. IL2CPP_ASSERT(s_MainThread == NULL);
  326. s_MainThread = thread;
  327. }
  328. void Thread::SetState(Il2CppThread *thread, ThreadState value)
  329. {
  330. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  331. thread->GetInternalThread()->state |= value;
  332. }
  333. void Thread::ClrState(Il2CppInternalThread* thread, ThreadState clr)
  334. {
  335. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  336. thread->state &= ~clr;
  337. }
  338. void Thread::SetState(Il2CppInternalThread *thread, ThreadState value)
  339. {
  340. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  341. thread->state |= value;
  342. }
  343. ThreadState Thread::GetState(Il2CppInternalThread *thread)
  344. {
  345. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  346. return (ThreadState)thread->state;
  347. }
  348. bool Thread::TestState(Il2CppInternalThread* thread, ThreadState value)
  349. {
  350. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  351. return (thread->state & value) != 0;
  352. }
  353. Il2CppInternalThread* Thread::CurrentInternal()
  354. {
  355. return Current()->GetInternalThread();
  356. }
  357. ThreadState Thread::GetState(Il2CppThread *thread)
  358. {
  359. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  360. return (ThreadState)thread->GetInternalThread()->state;
  361. }
  362. void Thread::ClrState(Il2CppThread* thread, ThreadState state)
  363. {
  364. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  365. thread->GetInternalThread()->state &= ~state;
  366. }
  367. static void AllocThreadDataSlot(ThreadStaticData* staticData, ThreadStaticOffset offset, int32_t size)
  368. {
  369. if (staticData->slots[offset.slot] == NULL)
  370. staticData->slots[offset.slot] = (ThreadStaticDataSlot*)IL2CPP_CALLOC(1, sizeof(ThreadStaticDataSlot));
  371. if (staticData->slots[offset.slot]->data[offset.index] == NULL)
  372. staticData->slots[offset.slot]->data[offset.index] = gc::GarbageCollector::AllocateFixed(size, NULL);
  373. }
  374. void Thread::AllocateStaticDataForCurrentThread()
  375. {
  376. AUTO_LOCK_THREADS();
  377. int32_t index = 0;
  378. // Alloc the slotData along with the first slots at once
  379. ThreadStaticData* staticData = (ThreadStaticData*)IL2CPP_CALLOC(1, sizeof(ThreadStaticData) + sizeof(ThreadStaticDataSlot));
  380. staticData->slots[0] = (ThreadStaticDataSlot*)(staticData + 1);
  381. Il2CppThread* thread = Current();
  382. IL2CPP_ASSERT(!thread->GetInternalThread()->static_data);
  383. thread->GetInternalThread()->static_data = staticData;
  384. s_StaticData.SetValue(staticData);
  385. for (std::vector<int32_t>::const_iterator iter = s_ThreadStaticSizes.begin(); iter != s_ThreadStaticSizes.end(); ++iter)
  386. {
  387. AllocThreadDataSlot(staticData, IndexToStaticFieldOffset(index), *iter);
  388. index++;
  389. }
  390. }
  391. int32_t Thread::AllocThreadStaticData(int32_t size)
  392. {
  393. AUTO_LOCK_THREADS();
  394. int32_t index = (int32_t)s_ThreadStaticSizes.size();
  395. IL2CPP_ASSERT(index < kMaxThreadStaticSlots * kMaxThreadStaticDataPointers);
  396. if (index >= kMaxThreadStaticSlots * kMaxThreadStaticDataPointers)
  397. il2cpp::vm::Exception::Raise(Exception::GetExecutionEngineException("Out of thread static storage slots"));
  398. s_ThreadStaticSizes.push_back(size);
  399. ThreadStaticOffset offset = IndexToStaticFieldOffset(index);
  400. for (GCTrackedThreadVector::const_iterator iter = s_AttachedThreads->begin(); iter != s_AttachedThreads->end(); ++iter)
  401. {
  402. Il2CppThread* thread = *iter;
  403. ThreadStaticData* staticData = reinterpret_cast<ThreadStaticData*>(thread->GetInternalThread()->static_data);
  404. if (staticData == NULL)
  405. {
  406. // There is a race on staticData for a thread could be NULL here in two cases
  407. // 1. The thread hasn't entered AllocateStaticDataForCurrentThread yet
  408. // 2. The thread has exited FreeCurrentThreadStaticData but hasn't been remove from the s_AttachedThreads yet
  409. // In both cases we can just continue and in 1. the data will be allocated in AllocateStaticDataForCurrentThread
  410. // and in 2. we don't want to allocate anything
  411. continue;
  412. }
  413. AllocThreadDataSlot(staticData, offset, size);
  414. }
  415. return index;
  416. }
  417. void Thread::FreeCurrentThreadStaticData(Il2CppThread *thread, bool inNativeThreadCleanup)
  418. {
  419. // This method is only valid to call from the current thread
  420. // But we can't safely check the Current() in native thread shutdown
  421. // because we can't rely on TLS values being valid
  422. IL2CPP_ASSERT(inNativeThreadCleanup || thread == Current());
  423. AUTO_LOCK_THREADS();
  424. ThreadStaticData* staticData = reinterpret_cast<ThreadStaticData*>(thread->GetInternalThread()->static_data);
  425. thread->GetInternalThread()->static_data = NULL;
  426. s_StaticData.SetValue(NULL);
  427. // This shouldn't happen unless we call this twice, but there's no reason to crash here
  428. IL2CPP_ASSERT(staticData);
  429. if (staticData == NULL)
  430. return;
  431. for (int slot = 0; slot < kMaxThreadStaticSlots; slot++)
  432. {
  433. if (!staticData->slots[slot])
  434. break;
  435. for (int i = 0; i < kMaxThreadStaticDataPointers; i++)
  436. {
  437. if (staticData->slots[slot]->data[i])
  438. break;
  439. gc::GarbageCollector::FreeFixed(staticData->slots[slot]->data[i]);
  440. }
  441. // Don't free the first slot because we allocate the first slot along with the root slots
  442. if (slot > 0)
  443. IL2CPP_FREE(staticData->slots[slot]);
  444. }
  445. IL2CPP_FREE(staticData);
  446. }
  447. void* Thread::GetThreadStaticData(int32_t offset)
  448. {
  449. // No lock. We allocate static_data once with a fixed size so we can read it
  450. // safely without a lock here.
  451. IL2CPP_ASSERT(offset >= 0 && static_cast<uint32_t>(offset) < s_ThreadStaticSizes.size());
  452. ThreadStaticOffset staticOffset = IndexToStaticFieldOffset(offset);
  453. ThreadStaticData* staticData;
  454. s_StaticData.GetValue((void**)&staticData);
  455. IL2CPP_ASSERT(staticData != NULL);
  456. return staticData->slots[staticOffset.slot]->data[staticOffset.index];
  457. }
  458. void* Thread::GetThreadStaticDataForThread(int32_t offset, Il2CppInternalThread* thread)
  459. {
  460. // No lock. We allocate static_data once with a fixed size so we can read it
  461. // safely without a lock here.
  462. IL2CPP_ASSERT(offset >= 0 && static_cast<uint32_t>(offset) < s_ThreadStaticSizes.size());
  463. IL2CPP_ASSERT(thread->static_data != NULL);
  464. ThreadStaticOffset staticOffset = IndexToStaticFieldOffset(offset);
  465. return reinterpret_cast<ThreadStaticData*>(thread->static_data)->slots[staticOffset.slot]->data[staticOffset.index];
  466. }
  467. void Thread::Register(Il2CppThread *thread)
  468. {
  469. AUTO_LOCK_THREADS();
  470. if (s_BlockNewThreads)
  471. TerminateThread(NULL);
  472. else
  473. {
  474. s_AttachedThreads->push_back(thread);
  475. set_wbarrier_for_attached_threads();
  476. }
  477. }
  478. void Thread::Unregister(Il2CppThread *thread)
  479. {
  480. AUTO_LOCK_THREADS();
  481. GCTrackedThreadVector::iterator it = std::find(s_AttachedThreads->begin(), s_AttachedThreads->end(), thread);
  482. #if IL2CPP_MONO_DEBUGGER
  483. if (it == s_AttachedThreads->end() && thread->internal_thread && il2cpp::utils::Debugger::IsDebuggerThread(thread->internal_thread->handle))
  484. return;
  485. #endif
  486. IL2CPP_ASSERT(it != s_AttachedThreads->end() && "Vm thread not found in list of attached threads.");
  487. s_AttachedThreads->erase(it);
  488. set_wbarrier_for_attached_threads();
  489. }
  490. bool Thread::IsVmThread(Il2CppThread *thread)
  491. {
  492. return !gc::GarbageCollector::IsFinalizerThread(thread);
  493. }
  494. std::string Thread::GetName(Il2CppInternalThread* thread)
  495. {
  496. if (thread->name.chars == NULL)
  497. return std::string();
  498. return utils::StringUtils::Utf16ToUtf8(thread->name.chars);
  499. }
  500. void Thread::SetName(Il2CppThread* thread, Il2CppString* name)
  501. {
  502. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  503. // Throw if already set.
  504. if (thread->GetInternalThread()->name.length != 0)
  505. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetInvalidOperationException("Thread name can only be set once."));
  506. // Store name.
  507. thread->GetInternalThread()->name.length = utils::StringUtils::GetLength(name);
  508. thread->GetInternalThread()->name.chars = il2cpp::utils::StringUtils::StringDuplicate(utils::StringUtils::GetChars(name), thread->GetInternalThread()->name.length);
  509. // Hand over to OS layer, if thread has been started already.
  510. if (thread->GetInternalThread()->handle)
  511. {
  512. std::string utf8Name = il2cpp::utils::StringUtils::Utf16ToUtf8(thread->GetInternalThread()->name.chars);
  513. thread->GetInternalThread()->handle->SetName(utf8Name.c_str());
  514. }
  515. }
  516. void Thread::SetName(Il2CppInternalThread* thread, Il2CppString* name)
  517. {
  518. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  519. // Throw if already set.
  520. if (thread->name.length != 0)
  521. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetInvalidOperationException("Thread name can only be set once."));
  522. // Store name.
  523. thread->name.length = utils::StringUtils::GetLength(name);
  524. thread->name.chars = il2cpp::utils::StringUtils::StringDuplicate(utils::StringUtils::GetChars(name), thread->name.length);
  525. // Hand over to OS layer, if thread has been started already.
  526. if (thread->handle)
  527. {
  528. std::string utf8Name = il2cpp::utils::StringUtils::Utf16ToUtf8(thread->name.chars);
  529. thread->handle->SetName(utf8Name.c_str());
  530. }
  531. }
  532. static void STDCALL CheckCurrentThreadForInterruptCallback(void* context)
  533. {
  534. Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary();
  535. }
  536. void Thread::RequestInterrupt(Il2CppThread* thread)
  537. {
  538. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  539. thread->GetInternalThread()->interruption_requested = true;
  540. // If thread has already been started, queue an interrupt now.
  541. il2cpp::os::Thread* osThread = thread->GetInternalThread()->handle;
  542. if (osThread)
  543. osThread->QueueUserAPC(CheckCurrentThreadForInterruptCallback, NULL);
  544. }
  545. void Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary()
  546. {
  547. Il2CppThread* currentThread = il2cpp::vm::Thread::Current();
  548. if (!currentThread)
  549. return;
  550. il2cpp::os::FastAutoLock lock(currentThread->GetInternalThread()->longlived->synch_cs);
  551. // Don't throw if thread is not currently in waiting state or if there's
  552. // no pending interrupt.
  553. if (!currentThread->GetInternalThread()->interruption_requested
  554. || !(il2cpp::vm::Thread::GetState(currentThread) & il2cpp::vm::kThreadStateWaitSleepJoin))
  555. return;
  556. // Mark the current thread as being unblocked.
  557. currentThread->GetInternalThread()->interruption_requested = false;
  558. il2cpp::vm::Thread::ClrState(currentThread, il2cpp::vm::kThreadStateWaitSleepJoin);
  559. // Throw interrupt exception.
  560. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadInterruptedException());
  561. }
  562. static void STDCALL CheckCurrentThreadForAbortCallback(void* context)
  563. {
  564. Thread::CheckCurrentThreadForAbortAndThrowIfNecessary();
  565. }
  566. bool Thread::RequestAbort(Il2CppThread* thread)
  567. {
  568. il2cpp::os::FastAutoLock lock(thread->GetInternalThread()->longlived->synch_cs);
  569. ThreadState state = il2cpp::vm::Thread::GetState(thread);
  570. if (state & kThreadStateAbortRequested || state & kThreadStateStopped || state & kThreadStateStopRequested)
  571. return false;
  572. il2cpp::os::Thread* osThread = thread->GetInternalThread()->handle;
  573. if (osThread)
  574. {
  575. // If thread has already been started, queue an abort now.
  576. Thread::SetState(thread, kThreadStateAbortRequested);
  577. osThread->QueueUserAPC(CheckCurrentThreadForAbortCallback, NULL);
  578. }
  579. else
  580. {
  581. // If thread has not started, put it in the aborted state.
  582. Thread::SetState(thread, kThreadStateAborted);
  583. }
  584. return true;
  585. }
  586. bool Thread::RequestAbort(Il2CppInternalThread* thread)
  587. {
  588. il2cpp::os::FastAutoLock lock(thread->longlived->synch_cs);
  589. ThreadState state = il2cpp::vm::Thread::GetState(thread);
  590. if (state & kThreadStateAbortRequested || state & kThreadStateStopped || state & kThreadStateStopRequested)
  591. return false;
  592. il2cpp::os::Thread* osThread = thread->handle;
  593. if (osThread)
  594. {
  595. // If thread has already been started, queue an abort now.
  596. Thread::SetState(thread, kThreadStateAbortRequested);
  597. osThread->QueueUserAPC(CheckCurrentThreadForAbortCallback, NULL);
  598. }
  599. else
  600. {
  601. // If thread has not started, put it in the aborted state.
  602. Thread::SetState(thread, kThreadStateAborted);
  603. }
  604. return true;
  605. }
  606. void Thread::SetPriority(Il2CppThread* thread, int32_t priority)
  607. {
  608. Il2CppInternalThread* internalThread = thread->GetInternalThread();
  609. il2cpp::os::FastAutoLock lock(internalThread->longlived->synch_cs);
  610. internalThread->handle->SetPriority((il2cpp::os::ThreadPriority)priority);
  611. }
  612. int32_t Thread::GetPriority(Il2CppThread* thread)
  613. {
  614. Il2CppInternalThread* internalThread = thread->GetInternalThread();
  615. il2cpp::os::FastAutoLock lock(internalThread->longlived->synch_cs);
  616. return internalThread->handle->GetPriority();
  617. }
  618. struct StartDataInternal
  619. {
  620. Il2CppThread* m_Thread;
  621. Il2CppDomain* m_Domain;
  622. void* m_Delegate;
  623. void* m_StartArg;
  624. il2cpp::os::Semaphore* m_Semaphore;
  625. };
  626. static void ThreadStart(void* arg)
  627. {
  628. StartDataInternal* startData = (StartDataInternal*)arg;
  629. startData->m_Semaphore->Wait();
  630. {
  631. gc::GarbageCollector::RegisterThread();
  632. il2cpp::vm::StackTrace::InitializeStackTracesForCurrentThread();
  633. bool attachSuccessful = false;
  634. try
  635. {
  636. il2cpp::vm::Thread::InitializeManagedThread(startData->m_Thread, startData->m_Domain);
  637. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateRunning);
  638. attachSuccessful = true;
  639. try
  640. {
  641. ((void(*)(void*))startData->m_Delegate)(startData->m_StartArg);
  642. }
  643. catch (Il2CppExceptionWrapper& ex)
  644. {
  645. // Only deal with the unhandled exception if the runtime is not
  646. // shutting down. Otherwise, the code to process the unhandled
  647. // exception might fail in unexpected ways, because it needs
  648. // the full runtime available. We've seen this cause crashes
  649. // that are difficult to reproduce locally.
  650. if (!il2cpp::vm::Runtime::IsShuttingDown())
  651. Runtime::UnhandledException(ex.ex);
  652. }
  653. }
  654. catch (il2cpp::vm::Thread::NativeThreadAbortException)
  655. {
  656. // Nothing to do. We've successfully aborted the thread.
  657. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateAborted);
  658. }
  659. il2cpp::vm::Thread::ClrState(startData->m_Thread, kThreadStateRunning);
  660. il2cpp::vm::Thread::SetState(startData->m_Thread, kThreadStateStopped);
  661. if (attachSuccessful)
  662. il2cpp::vm::Thread::UninitializeManagedThread(startData->m_Thread, false);
  663. il2cpp::vm::StackTrace::CleanupStackTracesForCurrentThread();
  664. }
  665. delete startData->m_Semaphore;
  666. gc::GarbageCollector::FreeFixed(startData);
  667. }
  668. Il2CppInternalThread* Thread::CreateInternal(void(*func)(void*), void* arg, bool threadpool_thread, uint32_t stack_size)
  669. {
  670. // The os::Thread object is deallocated in the InternalThread::Thread_free_internal icall, which
  671. // is called from the managed thread finalizer.
  672. os::Thread* osThread = new os::Thread();
  673. Il2CppThread* managedThread = (Il2CppThread*)Object::New(il2cpp_defaults.thread_class);
  674. SetupInternalManagedThread(managedThread, osThread);
  675. Il2CppInternalThread* internalManagedThread = managedThread->GetInternalThread();
  676. internalManagedThread->state = kThreadStateUnstarted;
  677. internalManagedThread->threadpool_thread = threadpool_thread;
  678. // use fixed GC memory since we are storing managed object pointers
  679. StartDataInternal* startData = (StartDataInternal*)gc::GarbageCollector::AllocateFixed(sizeof(StartDataInternal), NULL);
  680. gc::WriteBarrier::GenericStore(&startData->m_Thread, managedThread);
  681. gc::WriteBarrier::GenericStore(&startData->m_Domain, Domain::GetCurrent());
  682. startData->m_Delegate = (void*)func;
  683. startData->m_StartArg = arg;
  684. startData->m_Semaphore = new il2cpp::os::Semaphore(0);
  685. osThread->SetStackSize(stack_size);
  686. osThread->SetExplicitApartment(static_cast<il2cpp::os::ApartmentState>(managedThread->GetInternalThread()->apartment_state));
  687. il2cpp::os::ErrorCode status = osThread->Run(&ThreadStart, startData);
  688. if (status != il2cpp::os::kErrorCodeSuccess)
  689. {
  690. delete osThread;
  691. return NULL;
  692. }
  693. internalManagedThread->state &= ~kThreadStateUnstarted;
  694. startData->m_Semaphore->Post(1, NULL);
  695. return internalManagedThread;
  696. }
  697. void Thread::Stop(Il2CppInternalThread* thread)
  698. {
  699. IL2CPP_ASSERT(thread != CurrentInternal());
  700. if (!RequestAbort(thread))
  701. return;
  702. os::Thread* osThread = thread->handle;
  703. ////FIXME: While we don't have stable thread abortion in place yet, work around problems in
  704. //// the current implementation by repeatedly requesting threads to terminate. This works around
  705. //// race condition to some extent.
  706. while (true)
  707. {
  708. // If it's a background thread, request it to kill itself.
  709. if (GetState(thread) & kThreadStateBackground)
  710. {
  711. ////TODO: use Thread.Abort() instead
  712. osThread->QueueUserAPC(TerminateThread, NULL);
  713. }
  714. // Wait for the thread.
  715. if (osThread->Join(10) == kWaitStatusSuccess)
  716. break;
  717. }
  718. }
  719. void Thread::Sleep(uint32_t ms)
  720. {
  721. CurrentInternal()->handle->Sleep(ms);
  722. }
  723. bool Thread::YieldInternal()
  724. {
  725. return os::Thread::YieldInternal();
  726. }
  727. void Thread::SetDefaultAffinityMask(int64_t affinityMask)
  728. {
  729. #if defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
  730. os::Thread::SetDefaultAffinityMask(affinityMask);
  731. #endif
  732. }
  733. void Thread::CheckCurrentThreadForAbortAndThrowIfNecessary()
  734. {
  735. Il2CppThread* currentThread = il2cpp::vm::Thread::Current();
  736. if (!currentThread)
  737. return;
  738. il2cpp::os::FastAutoLock lock(currentThread->GetInternalThread()->longlived->synch_cs);
  739. ThreadState state = il2cpp::vm::Thread::GetState(currentThread);
  740. if (!(state & kThreadStateAbortRequested))
  741. return;
  742. // Throw interrupt exception.
  743. Il2CppException* abortException = il2cpp::vm::Exception::GetThreadAbortException();
  744. IL2CPP_OBJECT_SETREF(currentThread->GetInternalThread(), abort_exc, abortException);
  745. il2cpp::vm::Exception::Raise(abortException);
  746. }
  747. void Thread::ResetAbort(Il2CppThread* thread)
  748. {
  749. il2cpp::vm::Thread::ClrState(thread, kThreadStateAbortRequested);
  750. if (thread->GetInternalThread()->abort_exc == NULL)
  751. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadStateException("Unable to reset abort because no abort was requested."));
  752. }
  753. void Thread::ResetAbort(Il2CppInternalThread* thread)
  754. {
  755. il2cpp::vm::Thread::ClrState(thread, kThreadStateAbortRequested);
  756. if (thread->abort_exc == NULL)
  757. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetThreadStateException("Unable to reset abort because no abort was requested."));
  758. }
  759. void Thread::FullMemoryBarrier()
  760. {
  761. os::Atomic::FullMemoryBarrier();
  762. }
  763. int32_t Thread::GetNewManagedId()
  764. {
  765. return ++s_NextManagedThreadId;
  766. }
  767. uint64_t Thread::GetId(Il2CppThread* thread)
  768. {
  769. return thread->GetInternalThread()->tid;
  770. }
  771. uint64_t Thread::GetId(Il2CppInternalThread* thread)
  772. {
  773. return thread->tid;
  774. }
  775. } /* namespace vm */
  776. } /* namespace il2cpp */