Thread.cpp 31 KB

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