eathread_thread_unix.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EABase/eabase.h>
  5. #include <eathread/eathread_thread.h>
  6. #include <eathread/eathread.h>
  7. #include <eathread/eathread_callstack.h>
  8. #include <eathread/eathread_sync.h>
  9. #include "eathread/internal/eathread_global.h"
  10. #if defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE
  11. #include <new>
  12. #include <pthread.h>
  13. #include <time.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #if defined(EA_PLATFORM_WINDOWS)
  18. EA_DISABLE_ALL_VC_WARNINGS()
  19. #include <Windows.h> // Presumably we are using pthreads-win32.
  20. EA_RESTORE_ALL_VC_WARNINGS()
  21. #elif defined(EA_PLATFORM_LINUX)
  22. #include <sched.h>
  23. #include <sys/prctl.h>
  24. #include <sys/syscall.h>
  25. #include <unistd.h>
  26. #elif defined(EA_PLATFORM_APPLE)
  27. #include <unistd.h>
  28. #include <dlfcn.h>
  29. #elif defined(EA_PLATFORM_BSD) || defined(EA_PLATFORM_CONSOLE_BSD) || defined(EA_PLATFORM_FREEBSD)
  30. #include <pthread_np.h>
  31. #endif
  32. #if defined(EA_PLATFORM_LINUX)
  33. #define EA_ALLOW_POSIX_THREADS_PRIORITIES 0
  34. #else
  35. #define EA_ALLOW_POSIX_THREADS_PRIORITIES 1
  36. #endif
  37. #ifdef EA_PLATFORM_ANDROID
  38. #include <jni.h>
  39. #include "../android/com_ea_EAThread_EAThread.h"
  40. #endif
  41. namespace
  42. {
  43. #ifdef EA_PLATFORM_ANDROID
  44. void SetCurrentThreadNameJava(JNIEnv* env, const char* name);
  45. #endif
  46. // We convert a an EAThread priority (higher value implies higher priority) to a native priority
  47. // value, as some implementations of pthreads use lower values to indicate higher priority.
  48. void ConvertToNativePriority(int eathreadPriority, sched_param& param, int& policy)
  49. {
  50. using namespace EA::Thread;
  51. #if defined(EA_PLATFORM_WINDOWS)
  52. param.sched_priority = THREAD_PRIORITY_NORMAL + (nPriority - kThreadPriorityDefault);
  53. #elif defined(EA_PLATFORM_LINUX) && !defined(EA_PLATFORM_CYGWIN)
  54. // We are assuming Kernel 2.6 and later behaviour, but perhaps we should dynamically detect.
  55. // Linux supports three scheduling policies SCHED_OTHER, SCHED_RR, and SCHED_FIFO.
  56. // The process needs to be run with superuser privileges to use SCHED_RR or SCHED_FIFO.
  57. // Thread priorities for SCHED_OTHER do not exist; there is only one allowed thread priority: 0.
  58. // Thread priorities for SCHED_RR and SCHED_FIFO are limited to the range of [1, 99] (verified with Linux 2.6.17),
  59. // despite documentation on the Internet that refers to ranges of 0-99, 1-100, 1-140, etc.
  60. // Higher values in this range mean higher priority.
  61. // All of the SCHED_RR and SCHED_FIFO privileges are higher than anything running at SCHED_OTHER,
  62. // as they are considered to be real-time scheduling. A result of this is that there is no
  63. // such thing as having a thread of lower priority than normal; there are only higher real-time priorities.
  64. policy = 0;
  65. #if EA_ALLOW_POSIX_THREADS_PRIORITIES
  66. if(eathreadPriority <= kThreadPriorityDefault)
  67. #endif
  68. {
  69. #if defined(SCHED_OTHER)
  70. policy = SCHED_OTHER;
  71. #endif
  72. param.sched_priority = 0;
  73. }
  74. #if EA_ALLOW_POSIX_THREADS_PRIORITIES
  75. else
  76. {
  77. #if defined(SCHED_RR)
  78. policy = SCHED_RR;
  79. #endif
  80. param.sched_priority = (eathreadPriority - kThreadPriorityDefault);
  81. }
  82. #else
  83. EA_UNUSED(eathreadPriority);
  84. #endif
  85. #else
  86. #if defined(EA_PLATFORM_CYGWIN)
  87. policy = SCHED_OTHER;
  88. #else
  89. policy = SCHED_FIFO;
  90. #endif
  91. int nMin = sched_get_priority_min(policy);
  92. int nMax = sched_get_priority_max(policy);
  93. int adjustDir = 1;
  94. // Some implementations of Pthreads associate higher priorities with smaller
  95. // integer values. We hide this. To the user, a higher value must always
  96. // indicate higher priority.
  97. if(nMin > nMax)
  98. {
  99. adjustDir = nMax;
  100. nMax = nMin;
  101. nMin = adjustDir;
  102. adjustDir = -1; // Translate user's desire for higher priority to lower value
  103. }
  104. // native_priority = EAThread_native_priority_default +/- EAThread_user_priority
  105. // This calculation sets the default to be in the middle of low and high, which might not be so for all platforms in practice.
  106. param.sched_priority = ((nMin + nMax) / 2) + (adjustDir * eathreadPriority);
  107. if(param.sched_priority < nMin)
  108. param.sched_priority = nMin;
  109. else if(param.sched_priority > nMax)
  110. param.sched_priority = nMax;
  111. #endif
  112. }
  113. // We convert a native priority value to an EAThread priority (higher value implies higher
  114. // priority), as some implementations of pthreads use lower values to indicate higher priority.
  115. int ConvertFromNativePriority(const sched_param& param, int policy)
  116. {
  117. using namespace EA::Thread;
  118. #if defined(EA_PLATFORM_LINUX) && !defined(EA_PLATFORM_CYGWIN)
  119. EA_UNUSED(policy);
  120. return kThreadPriorityDefault + param.sched_priority; // This works for both SCHED_OTHER, SCHED_RR, and SCHED_FIFO.
  121. #else
  122. #if defined(EA_PLATFORM_WINDOWS) // In the case of windows, we know for sure that normal priority is defined by 'THREAD_PRIORITY_NORMAL'.
  123. if(param.sched_priority == THREAD_PRIORITY_NORMAL)
  124. return kThreadPriorityDefault;
  125. #elif !(defined(EA_PLATFORM_CYGWIN) || defined(CS_UNDEFINED_STRING))
  126. if(policy == SCHED_OTHER)
  127. return 0; // 0 is the only priority permitted with the SCHED_OTHER scheduling scheme.
  128. #endif
  129. // Some implementations of Pthreads associate higher priorities with smaller
  130. // integer values. We hide this. To the user, a higher value must always
  131. // indicate higher priority.
  132. // EAThread_user_priority = +/-(native_priority - EAThread_native_priority_default)
  133. const int nMin = sched_get_priority_min(policy);
  134. const int nMax = sched_get_priority_max(policy);
  135. const int nativeBasePriority = (nMin + nMax) / 2;
  136. const int adjustDir = (nMin < nMax) ? 1 : -1;
  137. return adjustDir * (param.sched_priority - nativeBasePriority);
  138. #endif
  139. }
  140. // Setup stack and/or priority of a new thread
  141. void SetupThreadAttributes(pthread_attr_t& creationAttribs, const EA::Thread::ThreadParameters* pTP)
  142. {
  143. int result = 0;
  144. EA_UNUSED( result ); //only used for assertions
  145. // We create the thread as attached, and we'll call either pthread_join or pthread_detach,
  146. // depending on whether WaitForEnd (pthread_join) is called or not (pthread_detach).
  147. if(pTP)
  148. {
  149. // Set thread stack address and/or size
  150. if(pTP->mpStack)
  151. {
  152. EAT_ASSERT(pTP->mnStackSize != 0);
  153. #if !defined(EA_PLATFORM_CYGWIN) // Some implementations of pthreads does not support pthread_attr_setstack.
  154. #if defined(PTHREAD_STACK_MIN)
  155. EAT_ASSERT((pTP->mnStackSize >= PTHREAD_STACK_MIN));
  156. #endif
  157. result = pthread_attr_setstack(&creationAttribs, (void*)pTP->mpStack, pTP->mnStackSize);
  158. EAT_ASSERT(result == 0);
  159. #endif
  160. }
  161. else if(pTP->mnStackSize)
  162. {
  163. #if defined(PTHREAD_STACK_MIN)
  164. EAT_ASSERT((pTP->mnStackSize >= PTHREAD_STACK_MIN));
  165. #endif
  166. result = pthread_attr_setstacksize(&creationAttribs, pTP->mnStackSize);
  167. EAT_ASSERT(result == 0);
  168. }
  169. // Set initial non-zero priority
  170. // Even if pTP->mnPriority == kThreadPriorityDefault, we need to run this on some platforms, as the thread priority for new threads on them isn't the same as the thread priority for the main thread.
  171. int policy = SCHED_OTHER;
  172. sched_param param;
  173. // initialize all fields of param before we start tinkering with them
  174. result = pthread_attr_getschedparam(&creationAttribs, &param);
  175. EAT_ASSERT(result == 0);
  176. ConvertToNativePriority(pTP->mnPriority, param, policy);
  177. result = pthread_attr_setschedpolicy(&creationAttribs, policy);
  178. EAT_ASSERT(result == 0);
  179. result = pthread_attr_setschedparam(&creationAttribs, &param);
  180. EAT_ASSERT(result == 0);
  181. // Unix doesn't let you specify thread CPU affinity via pthread attributes.
  182. // Instead you need to call sched_setaffinity or pthread_setaffinity_np.
  183. }
  184. }
  185. static void SetPlatformThreadAffinity(EAThreadDynamicData* pTDD)
  186. {
  187. if(pTDD->mThreadId != EA::Thread::kThreadIdInvalid) // If the thread has been created...
  188. {
  189. #if defined(EA_PLATFORM_LINUX) || defined(CS_UNDEFINED_STRING)
  190. EAT_ASSERT(pTDD && (pTDD->mThreadId != EA::Thread::kThreadIdInvalid));
  191. #if defined(EA_PLATFORM_ANDROID) // Android doesn't provide pthread_setaffinity_np.
  192. if(pTDD->mThreadPid != 0) // If the running thread has assigned its pid yet (it does so right after starting)...
  193. {
  194. int processor = (1 << pTDD->mStartupProcessor);
  195. syscall(__NR_sched_setaffinity, pTDD->mThreadPid, sizeof(processor), &processor);
  196. }
  197. // Else wait till the thread has started and let it set its own affinity.
  198. #else
  199. cpu_set_t cpus;
  200. CPU_ZERO(&cpus);
  201. CPU_SET(pTDD->mStartupProcessor, &cpus);
  202. pthread_setaffinity_np(pTDD->mThreadId, sizeof(cpus), &cpus);
  203. // We don't assert on the pthread_setaffinity_np return value, as that could be very noisy for some users.
  204. #endif
  205. #endif
  206. }
  207. // Else the thread hasn't started yet, or has already exited. Let the thread set its own
  208. // affinity when it starts.
  209. }
  210. #ifdef EA_PLATFORM_ANDROID
  211. static JavaVM* gJavaVM = NULL;
  212. static jclass gEAThreadClass = NULL;
  213. static jmethodID gSetNameMethodId = NULL;
  214. // This function needs to be called by Java code on app startup, before
  215. // the C main entrypoint is called, or very shortly thereafter. It's called
  216. // via Java with EAThread.Init(); If your Java code doesn't call EAThread.Init
  217. // then any C++ calls to Java code will fail (though those C++ calls could
  218. // manually set the JNIEnv per call).
  219. extern "C" __attribute__ ((visibility("default"))) JNIEXPORT void JNICALL Java_com_ea_EAThread_EAThread_Init(JNIEnv* env, jclass eaThreadClass)
  220. {
  221. gEAThreadClass = (jclass)env->NewGlobalRef(eaThreadClass);
  222. int getJavaVMResult = env->GetJavaVM(&gJavaVM);
  223. EA_UNUSED(getJavaVMResult);
  224. EAT_ASSERT_MSG(getJavaVMResult == 0, "Unable to get the Java VM from the JNI environment.");
  225. gSetNameMethodId = env->GetStaticMethodID(gEAThreadClass, "setCurrentThreadName", "(Ljava/lang/String;)V");
  226. EAT_ASSERT(gSetNameMethodId);
  227. }
  228. // This is called just after creation of a C/C++ thread.
  229. // The Java JNI requires you to do this, else bad things will happen.
  230. static JNIEnv* AttachJavaThread()
  231. {
  232. if(gJavaVM)
  233. {
  234. JNIEnv* env;
  235. jint resultCode = gJavaVM->AttachCurrentThread(&env, NULL);
  236. (void)resultCode;
  237. EAT_ASSERT_MSG(resultCode == 0, "Unable to attach thread");
  238. return env;
  239. }
  240. return NULL;
  241. }
  242. // This is called just before destruction of a C/C++ thread.
  243. // It is the complement of AttachJavaThread.
  244. static void DetachJavaThread()
  245. {
  246. if(gJavaVM)
  247. gJavaVM->DetachCurrentThread();
  248. }
  249. void SetCurrentThreadNameJava(JNIEnv* env, const char* name)
  250. {
  251. if(gJavaVM)
  252. {
  253. jstring threadName = env->NewStringUTF(name);
  254. env->CallStaticVoidMethod(gEAThreadClass, gSetNameMethodId, threadName);
  255. env->DeleteLocalRef(threadName);
  256. EAT_ASSERT(env->ExceptionOccurred() == NULL);
  257. if (env->ExceptionOccurred() != NULL)
  258. {
  259. env->ExceptionDescribe();
  260. env->ExceptionClear();
  261. }
  262. }
  263. }
  264. #endif
  265. } // namespace
  266. namespace EA
  267. {
  268. namespace Thread
  269. {
  270. extern Allocator* gpAllocator;
  271. const size_t kMaxThreadDynamicDataCount = 128;
  272. struct EAThreadGlobalVars
  273. {
  274. EA_PREFIX_ALIGN(8)
  275. char gThreadDynamicData[kMaxThreadDynamicDataCount][sizeof(EAThreadDynamicData)] EA_POSTFIX_ALIGN(8);
  276. AtomicInt32 gThreadDynamicDataAllocated[kMaxThreadDynamicDataCount];
  277. Mutex gThreadDynamicMutex;
  278. };
  279. EATHREAD_GLOBALVARS_CREATE_INSTANCE;
  280. EAThreadDynamicData* AllocateThreadDynamicData()
  281. {
  282. for(size_t i(0); i < kMaxThreadDynamicDataCount; i++)
  283. {
  284. if(EATHREAD_GLOBALVARS.gThreadDynamicDataAllocated[i].SetValueConditional(1, 0))
  285. return (EAThreadDynamicData*)(void*)EATHREAD_GLOBALVARS.gThreadDynamicData[i];
  286. }
  287. // This is a safety fallback mechanism. In practice it won't be used in almost all situations.
  288. if(gpAllocator)
  289. return (EAThreadDynamicData*)gpAllocator->Alloc(sizeof(EAThreadDynamicData));
  290. else
  291. return (EAThreadDynamicData*)new char[sizeof(EAThreadDynamicData)]; // We assume the returned alignment is sufficient.
  292. }
  293. void FreeThreadDynamicData(EAThreadDynamicData* pEAThreadDynamicData)
  294. {
  295. if((pEAThreadDynamicData >= (EAThreadDynamicData*)(void*)EATHREAD_GLOBALVARS.gThreadDynamicData) && (pEAThreadDynamicData < ((EAThreadDynamicData*)(void*)EATHREAD_GLOBALVARS.gThreadDynamicData + kMaxThreadDynamicDataCount)))
  296. {
  297. pEAThreadDynamicData->~EAThreadDynamicData();
  298. EATHREAD_GLOBALVARS.gThreadDynamicDataAllocated[pEAThreadDynamicData - (EAThreadDynamicData*)(void*)EATHREAD_GLOBALVARS.gThreadDynamicData].SetValue(0);
  299. }
  300. else
  301. {
  302. // Assume the data was allocated via the fallback mechanism.
  303. pEAThreadDynamicData->~EAThreadDynamicData();
  304. if(gpAllocator)
  305. gpAllocator->Free(pEAThreadDynamicData);
  306. else
  307. delete[] (char*)pEAThreadDynamicData;
  308. }
  309. }
  310. // This is a public function.
  311. EAThreadDynamicData* FindThreadDynamicData(ThreadId threadId)
  312. {
  313. for(size_t i(0); i < kMaxThreadDynamicDataCount; i++)
  314. {
  315. EAThreadDynamicData* const pTDD = (EAThreadDynamicData*)(void*)EATHREAD_GLOBALVARS.gThreadDynamicData[i];
  316. if(pTDD->mThreadId == threadId)
  317. return pTDD;
  318. }
  319. return NULL; // This is no practical way we can find the data unless thread-specific storage was involved.
  320. }
  321. #if defined(EA_PLATFORM_APPLE)
  322. EAThreadDynamicData* FindThreadDynamicData(EA::Thread::SysThreadId sysThreadId)
  323. {
  324. for (size_t i(0); i < kMaxThreadDynamicDataCount; ++i)
  325. {
  326. EAThreadDynamicData* const pTDD = (EAThreadDynamicData*)EATHREAD_GLOBALVARS.gThreadDynamicData[i];
  327. if (pTDD->mSysThreadId == sysThreadId)
  328. return pTDD;
  329. }
  330. return NULL; // This is no practical way we can find the data unless thread-specific storage was involved.
  331. }
  332. #endif
  333. }
  334. }
  335. EAThreadDynamicData::EAThreadDynamicData()
  336. : mThreadId(EA::Thread::kThreadIdInvalid),
  337. mSysThreadId(0),
  338. mThreadPid(0),
  339. mnStatus(EA::Thread::Thread::kStatusNone),
  340. mnReturnValue(0),
  341. //mpStartContext[],
  342. mpBeginThreadUserWrapper(NULL),
  343. mnRefCount(0),
  344. //mName[],
  345. mStartupProcessor(EA::Thread::kProcessorDefault),
  346. mnThreadAffinityMask(EA::Thread::kThreadAffinityMaskAny),
  347. mRunMutex(),
  348. mStartedSemaphore()
  349. {
  350. memset(mpStartContext, 0, sizeof(mpStartContext));
  351. memset(mName, 0, sizeof(mName));
  352. }
  353. EAThreadDynamicData::~EAThreadDynamicData()
  354. {
  355. if (mThreadId != EA::Thread::kThreadIdInvalid)
  356. {
  357. pthread_detach(mThreadId);
  358. }
  359. mThreadId = EA::Thread::kThreadIdInvalid;
  360. mThreadPid = 0;
  361. mSysThreadId = 0;
  362. }
  363. void EAThreadDynamicData::AddRef()
  364. {
  365. mnRefCount.Increment(); // Note that mnRefCount is an AtomicInt32.
  366. }
  367. void EAThreadDynamicData::Release()
  368. {
  369. if(mnRefCount.Decrement() == 0) // Note that mnRefCount is an AtomicInt32.
  370. EA::Thread::FreeThreadDynamicData(this);
  371. }
  372. EA::Thread::ThreadParameters::ThreadParameters()
  373. : mpStack(NULL),
  374. mnStackSize(0),
  375. mnPriority(kThreadPriorityDefault),
  376. mnProcessor(kProcessorDefault),
  377. mpName(""),
  378. mnAffinityMask(kThreadAffinityMaskAny),
  379. mbDisablePriorityBoost(false)
  380. {
  381. // Empty
  382. }
  383. EA::Thread::RunnableFunctionUserWrapper EA::Thread::Thread::sGlobalRunnableFunctionUserWrapper = NULL;
  384. EA::Thread::RunnableClassUserWrapper EA::Thread::Thread::sGlobalRunnableClassUserWrapper = NULL;
  385. EA::Thread::AtomicInt32 EA::Thread::Thread::sDefaultProcessor = kProcessorAny;
  386. EA::Thread::AtomicUint64 EA::Thread::Thread::sDefaultProcessorMask = UINT64_C(0xffffffffffffffff);
  387. EA::Thread::RunnableFunctionUserWrapper EA::Thread::Thread::GetGlobalRunnableFunctionUserWrapper()
  388. {
  389. return sGlobalRunnableFunctionUserWrapper;
  390. }
  391. void EA::Thread::Thread::SetGlobalRunnableFunctionUserWrapper(EA::Thread::RunnableFunctionUserWrapper pUserWrapper)
  392. {
  393. if(sGlobalRunnableFunctionUserWrapper)
  394. EAT_FAIL_MSG("Thread::SetGlobalRunnableFunctionUserWrapper already set."); // Can only be set once for the application.
  395. else
  396. sGlobalRunnableFunctionUserWrapper = pUserWrapper;
  397. }
  398. EA::Thread::RunnableClassUserWrapper EA::Thread::Thread::GetGlobalRunnableClassUserWrapper()
  399. {
  400. return sGlobalRunnableClassUserWrapper;
  401. }
  402. void EA::Thread::Thread::SetGlobalRunnableClassUserWrapper(EA::Thread::RunnableClassUserWrapper pUserWrapper)
  403. {
  404. if(sGlobalRunnableClassUserWrapper)
  405. EAT_FAIL_MSG("EAThread::SetGlobalRunnableClassUserWrapper already set."); // Can only be set once for the application.
  406. else
  407. sGlobalRunnableClassUserWrapper = pUserWrapper;
  408. }
  409. EA::Thread::Thread::Thread()
  410. {
  411. mThreadData.mpData = NULL;
  412. }
  413. EA::Thread::Thread::Thread(const Thread& t)
  414. : mThreadData(t.mThreadData)
  415. {
  416. if(mThreadData.mpData)
  417. mThreadData.mpData->AddRef();
  418. }
  419. EA::Thread::Thread& EA::Thread::Thread::operator=(const Thread& t)
  420. {
  421. // We don't synchronize access to mpData; we assume that the user
  422. // synchronizes it or this Thread instances is used from a single thread.
  423. if(t.mThreadData.mpData)
  424. t.mThreadData.mpData->AddRef();
  425. if(mThreadData.mpData)
  426. mThreadData.mpData->Release();
  427. mThreadData = t.mThreadData;
  428. return *this;
  429. }
  430. EA::Thread::Thread::~Thread()
  431. {
  432. // We don't synchronize access to mpData; we assume that the user
  433. // synchronizes it or this Thread instances is used from a single thread.
  434. if(mThreadData.mpData)
  435. mThreadData.mpData->Release();
  436. }
  437. static void* RunnableFunctionInternal(void* pContext)
  438. {
  439. // The parent thread is sharing memory with us and we need to
  440. // make sure our view of it is synchronized with the parent.
  441. EAReadWriteBarrier();
  442. EAThreadDynamicData* const pTDD = (EAThreadDynamicData*)pContext;
  443. EA::Thread::RunnableFunction pFunction = (EA::Thread::RunnableFunction)pTDD->mpStartContext[0];
  444. void* pCallContext = pTDD->mpStartContext[1];
  445. #if defined(EA_PLATFORM_LINUX) && defined(__NR_gettid)
  446. // Unfortunately there's no reliable way to translate a pthread_t to a
  447. // thread pid value. Thus we can know the thread's pid only via the
  448. // thread itself calling gettid().
  449. //pTDD->mThreadPid = gettid(); // Some Linux compiler distributions declare gettid(), some don't.
  450. pTDD->mThreadPid = (pid_t)syscall(__NR_gettid); // It's safest to just make the syscall directly.
  451. if(pTDD->mStartupProcessor != EA::Thread::kProcessorDefault && pTDD->mStartupProcessor != EA::Thread::kProcessorAny)
  452. SetPlatformThreadAffinity(pTDD);
  453. else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny)
  454. EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask);
  455. #elif !defined(EA_PLATFORM_CONSOLE) && !defined(EA_PLATFORM_MOBILE)
  456. pTDD->mThreadPid = getpid(); // We can't set a thread affinity with a process id.
  457. #else
  458. pTDD->mThreadPid = 0;
  459. #endif
  460. // Lock the runtime mutex which is used to allow other threads to wait on this thread with a timeout.
  461. pTDD->mRunMutex.Lock(); // Important that this be before the semaphore post.
  462. pTDD->mStartedSemaphore.Post(); // Announce that the thread has started.
  463. pTDD->mnStatus = EA::Thread::Thread::kStatusRunning;
  464. pTDD->mpStackBase = EA::Thread::GetStackBase();
  465. #ifdef EA_PLATFORM_ANDROID
  466. JNIEnv* jni = AttachJavaThread();
  467. if(pTDD->mName[0])
  468. SetCurrentThreadNameJava(jni, pTDD->mName);
  469. #elif !EATHREAD_OTHER_THREAD_NAMING_SUPPORTED
  470. // Under Unix we need to set the thread name from the thread that is being named and not from an outside thread.
  471. if(pTDD->mName[0])
  472. EA::Thread::SetThreadName(pTDD->mThreadId, pTDD->mName);
  473. #endif
  474. if(pTDD->mpBeginThreadUserWrapper)
  475. {
  476. // If user wrapper is specified, call user wrapper and pass the pFunction and pContext.
  477. EA::Thread::RunnableFunctionUserWrapper pWrapperFunction = (EA::Thread::RunnableFunctionUserWrapper)pTDD->mpBeginThreadUserWrapper;
  478. pTDD->mnReturnValue = pWrapperFunction(pFunction, pCallContext);
  479. }
  480. else
  481. pTDD->mnReturnValue = pFunction(pCallContext);
  482. #ifdef EA_PLATFORM_ANDROID
  483. DetachJavaThread();
  484. #endif
  485. void* pReturnValue = (void*)pTDD->mnReturnValue;
  486. pTDD->mnStatus = EA::Thread::Thread::kStatusEnded;
  487. pTDD->mRunMutex.Unlock();
  488. pTDD->Release();
  489. return pReturnValue;
  490. }
  491. static void* RunnableObjectInternal(void* pContext)
  492. {
  493. EAThreadDynamicData* const pTDD = (EAThreadDynamicData*)pContext;
  494. EA::Thread::IRunnable* pRunnable = (EA::Thread::IRunnable*)pTDD->mpStartContext[0];
  495. void* pCallContext = pTDD->mpStartContext[1];
  496. #if defined(EA_PLATFORM_LINUX) && defined(__NR_gettid)
  497. // Unfortunately there's no reliable way to translate a pthread_t to a
  498. // thread pid value. Thus we can know the thread's pid only via the
  499. // thread itself calling gettid().
  500. //pTDD->mThreadPid = gettid(); // Some Linux compiler distributions declare gettid(), some don't.
  501. pTDD->mThreadPid = (pid_t)syscall(__NR_gettid); // It's safest to just make the syscall directly.
  502. if(pTDD->mStartupProcessor != EA::Thread::kProcessorDefault && pTDD->mStartupProcessor != EA::Thread::kProcessorAny)
  503. SetPlatformThreadAffinity(pTDD);
  504. else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny)
  505. EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask);
  506. #elif !defined(EA_PLATFORM_CONSOLE) && !defined(EA_PLATFORM_MOBILE)
  507. pTDD->mThreadPid = getpid(); // We can't set a thread affinity with a process id.
  508. #else
  509. pTDD->mThreadPid = 0;
  510. #endif
  511. pTDD->mRunMutex.Lock(); // Important that this be before the semaphore post.
  512. pTDD->mStartedSemaphore.Post();
  513. pTDD->mnStatus = EA::Thread::Thread::kStatusRunning;
  514. #ifdef EA_PLATFORM_ANDROID
  515. JNIEnv* jni = AttachJavaThread();
  516. if(pTDD->mName[0])
  517. SetCurrentThreadNameJava(jni, pTDD->mName);
  518. #elif !EATHREAD_OTHER_THREAD_NAMING_SUPPORTED
  519. // Under Unix we need to set the thread name from the thread that is being named and not from an outside thread.
  520. if(pTDD->mName[0])
  521. EA::Thread::SetThreadName(pTDD->mThreadId, pTDD->mName);
  522. #endif
  523. if(pTDD->mpBeginThreadUserWrapper)
  524. {
  525. // If user wrapper is specified, call user wrapper and pass the pFunction and pContext.
  526. EA::Thread::RunnableClassUserWrapper pWrapperClass = (EA::Thread::RunnableClassUserWrapper)pTDD->mpBeginThreadUserWrapper;
  527. pTDD->mnReturnValue = pWrapperClass(pRunnable, pCallContext);
  528. }
  529. else
  530. pTDD->mnReturnValue = pRunnable->Run(pCallContext);
  531. #ifdef EA_PLATFORM_ANDROID
  532. DetachJavaThread();
  533. #endif
  534. void* const pReturnValue = (void*)pTDD->mnReturnValue;
  535. pTDD->mnStatus = EA::Thread::Thread::kStatusEnded;
  536. pTDD->mRunMutex.Unlock();
  537. pTDD->Release();
  538. return pReturnValue;
  539. }
  540. /// BeginThreadInternal
  541. /// Extraction of both RunnableFunction and RunnableObject EA::Thread::Begin in order to have thread initialization
  542. /// in one place
  543. static EA::Thread::ThreadId BeginThreadInternal(EAThreadData& mThreadData, void* pRunnableOrFunction, void* pContext, const EA::Thread::ThreadParameters* pTP,
  544. void* pUserWrapper, void* (*InternalThreadFunction)(void*))
  545. {
  546. using namespace EA::Thread;
  547. // The parent thread is sharing memory with us and we need to
  548. // make sure our view of it is synchronized with the parent.
  549. EAReadWriteBarrier();
  550. // Check there is an entry for the current thread context in our ThreadDynamicData array.
  551. EA::Thread::ThreadId thisThreadId = EA::Thread::GetThreadId();
  552. if(!FindThreadDynamicData(thisThreadId))
  553. {
  554. EAThreadDynamicData* pData = new(AllocateThreadDynamicData()) EAThreadDynamicData;
  555. if(pData)
  556. {
  557. pData->AddRef(); // AddRef for ourselves, to be released upon this Thread class being deleted or upon Begin being called again for a new thread.
  558. // Do no AddRef for thread execution because this is not an EAThread managed thread.
  559. pData->AddRef(); // AddRef for this function, to be released upon this function's exit.
  560. pData->mThreadId = thisThreadId;
  561. pData->mSysThreadId = GetSysThreadId();
  562. pData->mThreadPid = 0;
  563. strncpy(pData->mName, "external", EATHREAD_NAME_SIZE);
  564. pData->mName[EATHREAD_NAME_SIZE - 1] = 0;
  565. pData->mpStackBase = EA::Thread::GetStackBase();
  566. }
  567. }
  568. if(mThreadData.mpData)
  569. mThreadData.mpData->Release(); // Matches the "AddRef for ourselves" below.
  570. // We use the pData temporary throughout this function because it's possible that mThreadData.mpData could be
  571. // modified as we are executing, in particular in the case that mThreadData.mpData is destroyed and changed
  572. // during execution.
  573. EAThreadDynamicData* pData = new(AllocateThreadDynamicData()) EAThreadDynamicData; // Note that we use a special new here which doesn't use the heap.
  574. EAT_ASSERT(pData);
  575. if(pData)
  576. {
  577. mThreadData.mpData = pData;
  578. pData->AddRef(); // AddRef for ourselves, to be released upon this Thread class being deleted or upon Begin being called again for a new thread.
  579. pData->AddRef(); // AddRef for the thread, to be released upon the thread exiting.
  580. pData->AddRef(); // AddRef for this function, to be released upon this function's exit.
  581. pData->mThreadId = kThreadIdInvalid;
  582. pData->mSysThreadId = 0;
  583. pData->mThreadPid = 0;
  584. pData->mnStatus = Thread::kStatusNone;
  585. pData->mpStartContext[0] = pRunnableOrFunction;
  586. pData->mpStartContext[1] = pContext;
  587. pData->mpBeginThreadUserWrapper = pUserWrapper;
  588. pData->mStartupProcessor = pTP ? pTP->mnProcessor % EA::Thread::GetProcessorCount() : kProcessorDefault;
  589. pData->mnThreadAffinityMask = pTP ? pTP->mnAffinityMask : kThreadAffinityMaskAny;
  590. if(pTP && pTP->mpName)
  591. strncpy(pData->mName, pTP->mpName, EATHREAD_NAME_SIZE);
  592. pData->mName[EATHREAD_NAME_SIZE - 1] = 0;
  593. // Pass NULL attribute pointer if there are no special setup steps
  594. pthread_attr_t* pCreationAttribs = NULL;
  595. int result(0);
  596. pthread_attr_t creationAttribs;
  597. // SetupThreadAttributes is always called in order to create threads as detached
  598. pthread_attr_init(&creationAttribs);
  599. #ifndef EA_PLATFORM_ANDROID
  600. // Posix has stated that we should call pthread_attr_setinheritsched, otherwise the
  601. // thread priority set up in pthread_attr_t gets ignored by the newly created thread.
  602. pthread_attr_setinheritsched(&creationAttribs, PTHREAD_EXPLICIT_SCHED);
  603. #endif
  604. SetupThreadAttributes(creationAttribs, pTP);
  605. pCreationAttribs = &creationAttribs;
  606. result = pthread_create(&pData->mThreadId, pCreationAttribs, InternalThreadFunction, pData);
  607. if(result == 0) // If success...
  608. {
  609. ThreadId threadIdTemp = pData->mThreadId; // Temp value because Release below might delete pData.
  610. // If additional attributes were used, free initialization data.
  611. if(pCreationAttribs)
  612. {
  613. result = pthread_attr_destroy(pCreationAttribs);
  614. EAT_ASSERT(result == 0);
  615. }
  616. if(pData->mStartupProcessor != kProcessorDefault && pData->mStartupProcessor != EA::Thread::kProcessorAny)
  617. SetPlatformThreadAffinity(pData);
  618. else if(pData->mStartupProcessor == EA::Thread::kProcessorAny)
  619. EA::Thread::SetThreadAffinityMask(pData->mThreadId, pData->mnThreadAffinityMask);
  620. pData->Release(); // Matches AddRef for this function.
  621. return threadIdTemp;
  622. }
  623. // If additional attributes were used, free initialization data
  624. if(pCreationAttribs)
  625. {
  626. result = pthread_attr_destroy(pCreationAttribs);
  627. EAT_ASSERT(result == 0);
  628. }
  629. pData->Release(); // Matches AddRef for "cleanup" above.
  630. pData->Release(); // Matches AddRef for this Thread class above.
  631. pData->Release(); // Matches AddRef for thread above.
  632. mThreadData.mpData = NULL; // mThreadData.mpData == pData
  633. }
  634. return (ThreadId)kThreadIdInvalid;
  635. }
  636. EA::Thread::ThreadId EA::Thread::Thread::Begin(RunnableFunction pFunction, void* pContext, const ThreadParameters* pTP, RunnableFunctionUserWrapper pUserWrapper)
  637. {
  638. ThreadId threadId = BeginThreadInternal(mThreadData, reinterpret_cast<void*>((uintptr_t)pFunction), pContext, pTP, reinterpret_cast<void*>((uintptr_t)pUserWrapper), RunnableFunctionInternal);
  639. if(pTP && pTP->mnProcessor == EA::Thread::kProcessorAny)
  640. EA::Thread::Thread::SetAffinityMask(pTP->mnAffinityMask);
  641. if(pTP && pTP->mpName)
  642. SetName(pTP->mpName);
  643. return threadId;
  644. }
  645. EA::Thread::ThreadId EA::Thread::Thread::Begin(IRunnable* pRunnable, void* pContext, const ThreadParameters* pTP, RunnableClassUserWrapper pUserWrapper)
  646. {
  647. ThreadId threadId = BeginThreadInternal(mThreadData, reinterpret_cast<void*>((uintptr_t)pRunnable), pContext, pTP, reinterpret_cast<void*>((uintptr_t)pUserWrapper), RunnableObjectInternal);
  648. if(pTP && pTP->mnProcessor == EA::Thread::kProcessorAny)
  649. EA::Thread::Thread::SetAffinityMask(pTP->mnAffinityMask);
  650. if(pTP && pTP->mpName)
  651. SetName(pTP->mpName);
  652. return threadId;
  653. }
  654. EA::Thread::Thread::Status EA::Thread::Thread::WaitForEnd(const ThreadTime& timeoutAbsolute, intptr_t* pThreadReturnValue)
  655. {
  656. // In order to support timeoutAbsolute, we don't just call pthread_join, as that's an infinitely blocking call.
  657. // Instead we wait on a Mutex (with a timeout) which the running thread locked, and will unlock as it is exiting.
  658. // Only after the successful Mutex lock do we call pthread_join, as we know that it won't block for an indeterminate
  659. // amount of time (barring a thread priority inversion problem). If the user never calls WaitForEnd, then we
  660. // will eventually call pthread_detach in the EAThreadDynamicData destructor.
  661. // The mThreadData memory is shared between threads and when
  662. // reading it we must be synchronized.
  663. EAReadWriteBarrier();
  664. // A mutex lock around mpData is not needed below because mpData is never allowed to go from non-NULL to NULL.
  665. // However, there is an argument that can be made for placing a memory read barrier before reading it.
  666. if(mThreadData.mpData) // If this is non-zero then we must have created the thread.
  667. {
  668. EAT_ASSERT(mThreadData.mpData->mThreadId != kThreadIdInvalid); // WaitForEnd can't be called on a thread that hasn't been started
  669. // We must not call WaitForEnd from the thread we are waiting to end.
  670. // That would result in a deadlock, at least if the timeout was infinite.
  671. EAT_ASSERT(mThreadData.mpData->mThreadId != EA::Thread::GetThreadId());
  672. Status currentStatus = GetStatus();
  673. if(currentStatus == kStatusNone) // If the thread hasn't started yet...
  674. {
  675. // The thread has not been started yet. Wait on the semaphore (which is posted when the thread actually starts executing).
  676. Semaphore::Result result = (Semaphore::Result)mThreadData.mpData->mStartedSemaphore.Wait(timeoutAbsolute);
  677. EAT_ASSERT(result != Semaphore::kResultError);
  678. if(result >= 0) // If the Wait succeeded, as opposed to timing out...
  679. {
  680. // We know for sure that the thread status is running now.
  681. currentStatus = kStatusRunning;
  682. mThreadData.mpData->mStartedSemaphore.Post(); // Re-post the semaphore so that any other callers of WaitForEnd don't block on the Wait above.
  683. }
  684. } // fall through.
  685. if(currentStatus == kStatusRunning) // If the thread has started but not yet exited...
  686. {
  687. // Lock on the mutex (which is available when the thread is exiting)
  688. Mutex::Result result = (Mutex::Result)mThreadData.mpData->mRunMutex.Lock(timeoutAbsolute);
  689. EAT_ASSERT(result != Mutex::kResultError);
  690. if(result > 0) // If the Lock succeeded, as opposed to timing out... then the thread has exited or is in the process of exiting.
  691. {
  692. // Do a pthread join. This is a blocking call, but we know that it will end very soon,
  693. // as the mutex unlock the thread did is done right before the thread returns to the OS.
  694. // The return value of pthread_join has information that isn't currently useful to us.
  695. pthread_join(mThreadData.mpData->mThreadId, NULL);
  696. mThreadData.mpData->mThreadId = kThreadIdInvalid;
  697. // We know for sure that the thread status is ended now.
  698. currentStatus = kStatusEnded;
  699. mThreadData.mpData->mRunMutex.Unlock();
  700. }
  701. // Else the Lock timed out, which means that the thread didn't exit before we ran out of time.
  702. // In this case we need to return to the user that the status is kStatusRunning.
  703. }
  704. else
  705. {
  706. // Else currentStatus == kStatusEnded.
  707. pthread_join(mThreadData.mpData->mThreadId, NULL);
  708. mThreadData.mpData->mThreadId = kThreadIdInvalid;
  709. }
  710. if(currentStatus == kStatusEnded)
  711. {
  712. // Call GetStatus again to get the thread return value.
  713. currentStatus = GetStatus(pThreadReturnValue);
  714. }
  715. return currentStatus;
  716. }
  717. else
  718. {
  719. // Else the user hasn't started the thread yet, so we wait until the user starts it.
  720. // Ideally, what we really want to do here is wait for some kind of signal.
  721. // Instead for the time being we do a polling loop.
  722. while((!mThreadData.mpData || (mThreadData.mpData->mThreadId == kThreadIdInvalid)) && (GetThreadTime() < timeoutAbsolute))
  723. {
  724. ThreadSleep(1);
  725. EAReadWriteBarrier();
  726. EACompilerMemoryBarrier();
  727. }
  728. if(mThreadData.mpData)
  729. return WaitForEnd(timeoutAbsolute);
  730. }
  731. return kStatusNone;
  732. }
  733. EA::Thread::Thread::Status EA::Thread::Thread::GetStatus(intptr_t* pThreadReturnValue) const
  734. {
  735. if(mThreadData.mpData)
  736. {
  737. EAReadBarrier();
  738. Status status = (Status)mThreadData.mpData->mnStatus;
  739. if(pThreadReturnValue && (status == kStatusEnded))
  740. *pThreadReturnValue = mThreadData.mpData->mnReturnValue;
  741. return status;
  742. }
  743. return kStatusNone;
  744. }
  745. EA::Thread::ThreadId EA::Thread::Thread::GetId() const
  746. {
  747. // A mutex lock around mpData is not needed below because
  748. // mpData is never allowed to go from non-NULL to NULL.
  749. if(mThreadData.mpData)
  750. return mThreadData.mpData->mThreadId;
  751. return kThreadIdInvalid;
  752. }
  753. int EA::Thread::Thread::GetPriority() const
  754. {
  755. // A mutex lock around mpData is not needed below because
  756. // mpData is never allowed to go from non-NULL to NULL.
  757. if(mThreadData.mpData)
  758. {
  759. int policy;
  760. sched_param param;
  761. int result = pthread_getschedparam(mThreadData.mpData->mThreadId, &policy, &param);
  762. if(result == 0)
  763. return ConvertFromNativePriority(param, policy);
  764. return kThreadPriorityDefault;
  765. }
  766. return kThreadPriorityUnknown;
  767. }
  768. bool EA::Thread::Thread::SetPriority(int nPriority)
  769. {
  770. // A mutex lock around mpData is not needed below because
  771. // mpData is never allowed to go from non-NULL to NULL.
  772. EAT_ASSERT(nPriority != kThreadPriorityUnknown);
  773. if(mThreadData.mpData)
  774. {
  775. int policy;
  776. sched_param param;
  777. int result = pthread_getschedparam(mThreadData.mpData->mThreadId, &policy, &param);
  778. if(result == 0) // If success...
  779. {
  780. ConvertToNativePriority(nPriority, param, policy);
  781. result = pthread_setschedparam(mThreadData.mpData->mThreadId, policy, &param);
  782. }
  783. return (result == 0);
  784. }
  785. return false;
  786. }
  787. // To consider: Make it so we return a value.
  788. void EA::Thread::Thread::SetProcessor(int nProcessor)
  789. {
  790. #if defined(EA_PLATFORM_WINDOWS)
  791. if(mThreadData.mpData)
  792. {
  793. static AtomicInt32 nProcessorCount = 0;
  794. if(nProcessorCount == 0)
  795. {
  796. SYSTEM_INFO systemInfo;
  797. memset(&systemInfo, 0, sizeof(systemInfo));
  798. GetSystemInfo(&systemInfo);
  799. nProcessorCount = (int)systemInfo.dwNumberOfProcessors;
  800. }
  801. DWORD dwThreadAffinityMask;
  802. if(nProcessor < 0)
  803. dwThreadAffinityMask = 0xffffffff;
  804. else
  805. {
  806. if(nProcessor >= nProcessorCount)
  807. nProcessor %= nProcessorCount;
  808. dwThreadAffinityMask = 1 << nProcessor;
  809. }
  810. SetThreadAffinityMask(mThreadData.mpData->mThreadId, dwThreadAffinityMask);
  811. }
  812. #elif defined(EA_PLATFORM_LINUX)
  813. if(mThreadData.mpData)
  814. {
  815. mThreadData.mpData->mStartupProcessor = nProcessor; // Assign this in case the thread hasn't started yet and thus we are leaving it a message to set it when it has started.
  816. SetPlatformThreadAffinity(mThreadData.mpData);
  817. }
  818. #else
  819. EA_UNUSED(nProcessor);
  820. #endif
  821. }
  822. void EA::Thread::Thread::SetAffinityMask(EA::Thread::ThreadAffinityMask nAffinityMask)
  823. {
  824. if(mThreadData.mpData->mThreadId)
  825. {
  826. SetThreadAffinityMask(mThreadData.mpData->mThreadId, nAffinityMask);
  827. }
  828. }
  829. EA::Thread::ThreadAffinityMask EA::Thread::Thread::GetAffinityMask()
  830. {
  831. if(mThreadData.mpData->mThreadId)
  832. {
  833. return mThreadData.mpData->mnThreadAffinityMask;
  834. }
  835. return kThreadAffinityMaskAny;
  836. }
  837. void EA::Thread::Thread::Wake()
  838. {
  839. // Todo: implement this. The solution is to use a signal to wake the sleeping thread via an EINTR.
  840. // Possibly use the SIGCONT signal. Have to look into this to tell what the best approach is.
  841. }
  842. const char* EA::Thread::Thread::GetName() const
  843. {
  844. if(mThreadData.mpData)
  845. return mThreadData.mpData->mName;
  846. return "";
  847. }
  848. void EA::Thread::Thread::SetName(const char* pName)
  849. {
  850. if(mThreadData.mpData && pName)
  851. EA::Thread::SetThreadName(mThreadData.mpData->mThreadId, pName);
  852. }
  853. #if defined(EA_PLATFORM_ANDROID)
  854. namespace EA
  855. {
  856. namespace Thread
  857. {
  858. void SetCurrentThreadName(JNIEnv* env, const char* pName)
  859. {
  860. SetCurrentThreadNameJava(env, pName);
  861. }
  862. }
  863. }
  864. #endif
  865. #endif // EA_PLATFORM_XXX