No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ThreadImpl.cpp 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "il2cpp-config.h"
  2. #if !IL2CPP_THREADS_STD && IL2CPP_THREADS_PTHREAD
  3. #include <limits>
  4. #include <unistd.h>
  5. #include <map>
  6. #include <pthread.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #if IL2CPP_TARGET_LINUX
  10. #include <sys/prctl.h>
  11. #include <sys/resource.h>
  12. #endif
  13. #include "ThreadImpl.h"
  14. #include "PosixHelpers.h"
  15. namespace il2cpp
  16. {
  17. namespace os
  18. {
  19. #define ASSERT_CALLED_ON_CURRENT_THREAD \
  20. IL2CPP_ASSERT(pthread_equal (pthread_self (), m_Handle) && "Must be called on current thread!");
  21. static Event* s_ThreadSleepObject = nullptr;
  22. void ThreadImpl::AllocateStaticData()
  23. {
  24. s_ThreadSleepObject = new Event();
  25. }
  26. void ThreadImpl::FreeStaticData()
  27. {
  28. delete s_ThreadSleepObject;
  29. s_ThreadSleepObject = nullptr;
  30. }
  31. ThreadImpl::ThreadImpl()
  32. : m_Handle(0)
  33. , m_StartFunc(NULL)
  34. , m_StartArg(NULL)
  35. , m_CurrentWaitObject(NULL)
  36. , m_StackSize(IL2CPP_DEFAULT_STACK_SIZE)
  37. , m_ConditionSemaphore(1)
  38. {
  39. }
  40. ThreadImpl::~ThreadImpl()
  41. {
  42. }
  43. ErrorCode ThreadImpl::Run(Thread::StartFunc func, void* arg, int64_t affinityMask)
  44. {
  45. // Store state for run wrapper.
  46. m_StartFunc = func;
  47. m_StartArg = arg;
  48. // Initialize thread attributes.
  49. pthread_attr_t attr;
  50. int s = pthread_attr_init(&attr);
  51. if (s)
  52. return kErrorCodeGenFailure;
  53. #if defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
  54. #if IL2CPP_THREAD_HAS_CPU_SET
  55. if (affinityMask != Thread::kThreadAffinityAll)
  56. {
  57. cpu_set_t cpuset;
  58. CPU_ZERO(&cpuset);
  59. for (int i = 0; i < 64; ++i)
  60. {
  61. if (affinityMask & (1 << i))
  62. CPU_SET(i, &cpuset);
  63. }
  64. pthread_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
  65. }
  66. else
  67. {
  68. // set create default core affinity
  69. pthread_attr_setaffinity_np(&attr, 0, NULL);
  70. }
  71. #else
  72. pthread_attr_setaffinity_np(&attr, 0, NULL);
  73. #endif // IL2CPP_THREAD_HAS_CPU_SET
  74. #endif // defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
  75. #if defined(IL2CPP_ENABLE_PLATFORM_THREAD_STACKSIZE)
  76. pthread_attr_setstacksize(&attr, m_StackSize);
  77. #endif
  78. // Create thread.
  79. pthread_t threadId;
  80. s = pthread_create(&threadId, &attr, &ThreadStartWrapper, this);
  81. if (s)
  82. return kErrorCodeGenFailure;
  83. // Destroy thread attributes.
  84. s = pthread_attr_destroy(&attr);
  85. if (s)
  86. return kErrorCodeGenFailure;
  87. // We're up and running.
  88. m_Handle = threadId;
  89. return kErrorCodeSuccess;
  90. }
  91. void* ThreadImpl::ThreadStartWrapper(void* arg)
  92. {
  93. ThreadImpl* thread = reinterpret_cast<ThreadImpl*>(arg);
  94. // Also set handle here. No matter which thread proceeds first,
  95. // we need to make sure the handle is set.
  96. thread->m_Handle = pthread_self();
  97. // Detach this thread since we will manage calling Join at the VM level
  98. // if necessary. Detaching it also prevents use from running out of thread
  99. // handles for background threads that are never joined.
  100. int returnValue = pthread_detach(thread->m_Handle);
  101. IL2CPP_ASSERT(returnValue == 0);
  102. (void)returnValue;
  103. // Run user code.
  104. thread->m_StartFunc(thread->m_StartArg);
  105. return 0;
  106. }
  107. uint64_t ThreadImpl::Id()
  108. {
  109. return posix::PosixThreadIdToThreadId(m_Handle);
  110. }
  111. void ThreadImpl::SetName(const char* name)
  112. {
  113. // Can only be set on current thread on OSX and Linux.
  114. if (pthread_self() != m_Handle)
  115. return;
  116. #if IL2CPP_TARGET_DARWIN
  117. pthread_setname_np(name);
  118. #elif IL2CPP_TARGET_LINUX || IL2CPP_TARGET_ANDROID || IL2CPP_ENABLE_PLATFORM_THREAD_RENAME
  119. if (pthread_setname_np(m_Handle, name) == ERANGE)
  120. {
  121. char buf[16]; // TASK_COMM_LEN=16
  122. strncpy(buf, name, sizeof(buf));
  123. buf[sizeof(buf) - 1] = '\0';
  124. pthread_setname_np(m_Handle, buf);
  125. }
  126. #endif
  127. }
  128. void ThreadImpl::SetStackSize(size_t newsize)
  129. {
  130. // if newsize is zero we use the per-platform default value for size of stack
  131. if (newsize == 0)
  132. {
  133. newsize = IL2CPP_DEFAULT_STACK_SIZE;
  134. }
  135. m_StackSize = newsize;
  136. }
  137. int ThreadImpl::GetMaxStackSize()
  138. {
  139. #if IL2CPP_TARGET_DARWIN || IL2CPP_TARGET_LINUX
  140. struct rlimit lim;
  141. /* If getrlimit fails, we don't enforce any limits. */
  142. if (getrlimit(RLIMIT_STACK, &lim))
  143. return INT_MAX;
  144. /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
  145. if (lim.rlim_max > (rlim_t)INT_MAX)
  146. return INT_MAX;
  147. return (int)lim.rlim_max;
  148. #else
  149. return INT_MAX;
  150. #endif
  151. }
  152. void ThreadImpl::SetPriority(ThreadPriority priority)
  153. {
  154. ////TODO
  155. }
  156. ThreadPriority ThreadImpl::GetPriority()
  157. {
  158. /// TODO
  159. return kThreadPriorityNormal;
  160. }
  161. void ThreadImpl::QueueUserAPC(Thread::APCFunc function, void* context)
  162. {
  163. IL2CPP_ASSERT(function != NULL);
  164. // Put on queue.
  165. {
  166. m_PendingAPCsMutex.Acquire();
  167. m_PendingAPCs.push_back(APCRequest(function, context));
  168. m_PendingAPCsMutex.Release();
  169. }
  170. // Interrupt an ongoing wait, only interrupt if we have an object waiting
  171. if (m_CurrentWaitObject.load())
  172. {
  173. m_ConditionSemaphore.Release(1);
  174. }
  175. }
  176. void ThreadImpl::CheckForUserAPCAndHandle()
  177. {
  178. ASSERT_CALLED_ON_CURRENT_THREAD;
  179. m_PendingAPCsMutex.Acquire();
  180. while (!m_PendingAPCs.empty())
  181. {
  182. APCRequest apcRequest = m_PendingAPCs.front();
  183. // Remove from list. Do before calling the function to make sure the list
  184. // is up to date in case the function throws.
  185. m_PendingAPCs.erase(m_PendingAPCs.begin());
  186. // Release mutex while we call the function so that we don't deadlock
  187. // if the function starts waiting on a thread that tries queuing an APC
  188. // on us.
  189. m_PendingAPCsMutex.Release();
  190. // Call function.
  191. apcRequest.callback(apcRequest.context);
  192. // Re-acquire mutex.
  193. m_PendingAPCsMutex.Acquire();
  194. }
  195. m_PendingAPCsMutex.Release();
  196. }
  197. void ThreadImpl::SetWaitObject(WaitObject* waitObject)
  198. {
  199. // Cannot set wait objects on threads other than the current thread.
  200. ASSERT_CALLED_ON_CURRENT_THREAD;
  201. // This is an unprotected write as write acccess is restricted to the
  202. // current thread.
  203. m_CurrentWaitObject = waitObject;
  204. }
  205. void ThreadImpl::Sleep(uint32_t milliseconds, bool interruptible)
  206. {
  207. /// An Event that we never signal. This is used for sleeping threads in an alertable state. They
  208. /// simply wait on this object with the sleep timer as the timeout. This way we don't need a separate
  209. /// codepath for implementing sleep logic.
  210. s_ThreadSleepObject->Wait(milliseconds, interruptible);
  211. }
  212. uint64_t ThreadImpl::CurrentThreadId()
  213. {
  214. return posix::PosixThreadIdToThreadId(pthread_self());
  215. }
  216. ThreadImpl* ThreadImpl::GetCurrentThread()
  217. {
  218. return Thread::GetCurrentThread()->m_Thread;
  219. }
  220. ThreadImpl* ThreadImpl::CreateForCurrentThread()
  221. {
  222. ThreadImpl* thread = new ThreadImpl();
  223. thread->m_Handle = pthread_self();
  224. return thread;
  225. }
  226. bool ThreadImpl::YieldInternal()
  227. {
  228. return sched_yield() == 0;
  229. }
  230. #if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
  231. static pthread_key_t s_CleanupKey;
  232. static Thread::ThreadCleanupFunc s_CleanupFunc;
  233. static void CleanupThreadIfCanceled(void* arg)
  234. {
  235. Thread::ThreadCleanupFunc cleanupFunc = s_CleanupFunc;
  236. if (cleanupFunc)
  237. cleanupFunc(arg);
  238. }
  239. void ThreadImpl::SetNativeThreadCleanup(Thread::ThreadCleanupFunc cleanupFunction)
  240. {
  241. if (cleanupFunction)
  242. {
  243. IL2CPP_ASSERT(!s_CleanupFunc);
  244. s_CleanupFunc = cleanupFunction;
  245. int result = pthread_key_create(&s_CleanupKey, &CleanupThreadIfCanceled);
  246. IL2CPP_ASSERT(!result);
  247. NO_UNUSED_WARNING(result);
  248. }
  249. else
  250. {
  251. IL2CPP_ASSERT(s_CleanupFunc);
  252. int result = pthread_key_delete(s_CleanupKey);
  253. IL2CPP_ASSERT(!result);
  254. NO_UNUSED_WARNING(result);
  255. s_CleanupFunc = NULL;
  256. }
  257. }
  258. void ThreadImpl::RegisterCurrentThreadForCleanup(void* arg)
  259. {
  260. IL2CPP_ASSERT(s_CleanupFunc);
  261. pthread_setspecific(s_CleanupKey, arg);
  262. }
  263. void ThreadImpl::UnregisterCurrentThreadForCleanup()
  264. {
  265. IL2CPP_ASSERT(s_CleanupFunc);
  266. void* data = pthread_getspecific(s_CleanupKey);
  267. if (data != NULL)
  268. pthread_setspecific(s_CleanupKey, NULL);
  269. }
  270. #endif
  271. }
  272. }
  273. #endif