eathread_thread.h 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #ifndef EATHREAD_EATHREAD_THREAD_H
  5. #define EATHREAD_EATHREAD_THREAD_H
  6. #include <eathread/eathread.h>
  7. #include <eathread/eathread_semaphore.h>
  8. #include <eathread/eathread_atomic.h>
  9. EA_DISABLE_ALL_VC_WARNINGS()
  10. #include <stddef.h>
  11. #include <stdlib.h>
  12. #include <type_traits>
  13. EA_RESTORE_ALL_VC_WARNINGS()
  14. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  15. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  16. #endif
  17. #if defined(EA_DLL) && defined(_MSC_VER)
  18. // Suppress warning about class 'AtomicInt32' needs to have a
  19. // dll-interface to be used by clients of class which have a templated member.
  20. //
  21. // These templates cannot be instantiated outside of the DLL. If you try, a
  22. // link error will result. This compiler warning is intended to notify users
  23. // of this.
  24. #pragma warning(push)
  25. #pragma warning(disable: 4251)
  26. #endif
  27. /////////////////////////////////////////////////////////////////////////
  28. /// ThreadData
  29. ///
  30. /// This is used internally by class Thread.
  31. /// To consider: Move this declaration into a platform-specific
  32. /// header file.
  33. /////////////////////////////////////////////////////////////////////////
  34. #if !EA_THREADS_AVAILABLE
  35. struct EAThreadDynamicData
  36. {
  37. };
  38. struct EAThreadData
  39. {
  40. EAThreadDynamicData* mpData;
  41. };
  42. #elif EA_USE_CPP11_CONCURRENCY
  43. #include <eathread/eathread_mutex.h>
  44. #include <eathread/eathread_semaphore.h>
  45. EA_DISABLE_VC_WARNING(4062 4265 4365 4836 4571 4625 4626 4628 4193 4127 4548 4350)
  46. #if EA_PLATFORM_WINDOWS
  47. #include <ctxtcall.h> // workaround for compile errors in winrt. see http://connect.microsoft.com/VisualStudio/feedback/details/730564/ppl-in-winrt-projects-fail-to-compile
  48. #endif
  49. #include <future>
  50. #include <mutex>
  51. struct EAThreadDynamicData
  52. {
  53. typedef void (*ThreadFunc)(EAThreadDynamicData* tdd, void* userFunc, void* userContext, void* userWrapperFunc);
  54. EAThreadDynamicData(EA::Thread::ThreadUniqueId uniqueThreadId, const char* pThreadName);
  55. EAThreadDynamicData(void* userFunc, void* userContext, void* userWrapperFunc, ThreadFunc threadFunc);
  56. ~EAThreadDynamicData();
  57. void AddRef();
  58. void Release();
  59. EA::Thread::AtomicInt32 mnRefCount;
  60. EA::Thread::AtomicInt32 mStatus;
  61. intptr_t mReturnValue;
  62. char mName[EATHREAD_NAME_SIZE];
  63. void* mpStackBase;
  64. EA::Thread::ThreadAffinityMask mnThreadAffinityMask;
  65. EA::Thread::ThreadUniqueId mUniqueThreadId;
  66. struct EAThreadComposite
  67. {
  68. EAThreadComposite()
  69. : mReturnPromise()
  70. , mReturnFuture(mReturnPromise.get_future())
  71. , mGetStatusFuture(mReturnFuture)
  72. {
  73. }
  74. std::promise<intptr_t> mReturnPromise;
  75. std::shared_future<intptr_t> mReturnFuture;
  76. std::shared_future<intptr_t> mGetStatusFuture;
  77. std::thread mThread;
  78. } *mpComp;
  79. private:
  80. // Disable copy and assignment
  81. EAThreadDynamicData(const EAThreadDynamicData&);
  82. EAThreadDynamicData operator=(const EAThreadDynamicData&);
  83. };
  84. struct EAThreadData
  85. {
  86. EAThreadDynamicData* mpData;
  87. };
  88. EA_RESTORE_VC_WARNING()
  89. // TODO: collapse the defines.
  90. #elif defined(EA_PLATFORM_SONY)
  91. #include <eathread/eathread_mutex.h>
  92. #include <eathread/eathread_semaphore.h>
  93. #include <kernel.h>
  94. #include <scebase.h>
  95. // Internal queue wrapper which is used to allow for a higher resolution sleep than what is provided by Sony's sleep functions
  96. // as despite the names, sceKernelSleep, sceKernelUSleep and sceKernelNanosleep are all 1 ms resolution whereas this timer is 100 microseconds
  97. struct EAThreadTimerQueue
  98. {
  99. EAThreadTimerQueue()
  100. {
  101. int result = sceKernelCreateEqueue(&mTimerEventQueue, "EAThread Timer Queue");
  102. mbEnabled = result == SCE_OK;
  103. // A timer queue will fail to be created when there are too many kernel objects open. It is a valid
  104. // use-case for the Event Queue to fail being created as the ThreadSleep function implements a fallback.
  105. //
  106. // EAT_ASSERT_FORMATTED(mbEnabled, "Failed to initialize the EAThread Timer Queue (0x%x)", result);
  107. }
  108. ~EAThreadTimerQueue()
  109. {
  110. if(mbEnabled) // only destroy the queue if it was created.
  111. sceKernelDeleteEqueue(mTimerEventQueue);
  112. mbEnabled = false;
  113. }
  114. SceKernelEqueue mTimerEventQueue;
  115. EA::Thread::AtomicUint32 mCurrentId = 0;
  116. bool mbEnabled = false;
  117. };
  118. struct EAThreadDynamicData
  119. {
  120. EAThreadDynamicData();
  121. ~EAThreadDynamicData();
  122. void AddRef();
  123. void Release();
  124. EA::Thread::ThreadId mThreadId;
  125. EA::Thread::SysThreadId mSysThreadId;
  126. pid_t mThreadPid; // For Linux this is the thread ID from gettid(). Otherwise it's the getpid() value.
  127. volatile int mnStatus;
  128. intptr_t mnReturnValue;
  129. void* mpStartContext[2];
  130. void* mpBeginThreadUserWrapper; // User-specified BeginThread function wrapper or class wrapper
  131. void* mpStackBase;
  132. EA::Thread::AtomicInt32 mnRefCount;
  133. char mName[EATHREAD_NAME_SIZE];
  134. int mStartupProcessor; // The thread affinity for the thread to set itself to after it starts. We need to do this because we currently have no way to set the affinity of another thread until after it has started.
  135. EA::Thread::Mutex mRunMutex; // Locked while the thread is running. The reason for this mutex is that it allows timeouts to be specified in the WaitForEnd function.
  136. EA::Thread::Semaphore mStartedSemaphore; // Signaled when the thread starts. This allows us to know in a thread-safe way when the thread has actually started executing.
  137. EA::Thread::ThreadAffinityMask mnThreadAffinityMask;
  138. EAThreadTimerQueue mThreadTimerQueue; // This queue allows for high resolution timer events to be submitted per thread allowing for better sleep resolution than Sony's provided sleep functions
  139. };
  140. struct EAThreadData{
  141. EAThreadDynamicData* mpData;
  142. };
  143. #elif defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE
  144. #include <pthread.h>
  145. #include <eathread/eathread_mutex.h>
  146. #include <eathread/eathread_semaphore.h>
  147. struct EAThreadDynamicData
  148. {
  149. EAThreadDynamicData();
  150. ~EAThreadDynamicData();
  151. void AddRef();
  152. void Release();
  153. EA::Thread::ThreadId mThreadId;
  154. EA::Thread::SysThreadId mSysThreadId;
  155. pid_t mThreadPid; // For Linux this is the thread ID from gettid(). Otherwise it's the getpid() value.
  156. volatile int mnStatus;
  157. intptr_t mnReturnValue;
  158. void* mpStartContext[2];
  159. void* mpBeginThreadUserWrapper; // User-specified BeginThread function wrapper or class wrapper
  160. void* mpStackBase;
  161. EA::Thread::AtomicInt32 mnRefCount;
  162. char mName[EATHREAD_NAME_SIZE];
  163. int mStartupProcessor; // DEPRECATED: The thread affinity for the thread to set itself to after it starts. We need to do this because we currently have no way to set the affinity of another thread until after it has started.
  164. EA::Thread::ThreadAffinityMask mnThreadAffinityMask; // mStartupProcessor is deprecated in favor of using the the mnThreadAffinityMask and doesn't suffer from the limitations of only specifying the value at thread startup time.
  165. EA::Thread::Mutex mRunMutex; // Locked while the thread is running. The reason for this mutex is that it allows timeouts to be specified in the WaitForEnd function.
  166. EA::Thread::Semaphore mStartedSemaphore; // Signaled when the thread starts. This allows us to know in a thread-safe way when the thread has actually started executing.
  167. };
  168. struct EAThreadData
  169. {
  170. EAThreadDynamicData* mpData;
  171. };
  172. #elif defined(EA_PLATFORM_MICROSOFT) && !EA_POSIX_THREADS_AVAILABLE
  173. struct EAThreadDynamicData
  174. {
  175. EAThreadDynamicData();
  176. ~EAThreadDynamicData();
  177. void AddRef();
  178. void Release();
  179. EA::Thread::ThreadId mhThread;
  180. unsigned int mnThreadId; // EA::Thread::SysThreadId
  181. int mnStatus;
  182. EA::Thread::ThreadAffinityMask mnThreadAffinityMask;
  183. intptr_t mnReturnValue;
  184. void* mpStartContext[3];
  185. void* mpBeginThreadUserWrapper; // User-specified BeginThread function wrapper or class wrapper
  186. void* mpStackBase;
  187. EA::Thread::AtomicInt32 mnRefCount;
  188. char mName[EATHREAD_NAME_SIZE];
  189. };
  190. struct EAThreadData
  191. {
  192. EAThreadDynamicData* mpData;
  193. };
  194. #endif
  195. namespace EA
  196. {
  197. namespace Thread
  198. {
  199. struct EATHREADLIB_API ThreadEnumData
  200. {
  201. ThreadEnumData();
  202. ~ThreadEnumData();
  203. EAThreadDynamicData* mpThreadDynamicData;
  204. void Release();
  205. };
  206. }
  207. }
  208. /////////////////////////////////////////////////////////////////////////
  209. namespace EA
  210. {
  211. namespace Thread
  212. {
  213. /// FindThreadDynamicData
  214. /// Utility functionality, not needed for most uses.
  215. EATHREADLIB_API EAThreadDynamicData* FindThreadDynamicData(ThreadId threadId);
  216. EATHREADLIB_API EAThreadDynamicData* FindThreadDynamicData(SysThreadId threadId);
  217. /// EnumerateThreads
  218. /// Enumerates known threads. For some platforms the returned thread list is limited
  219. /// to the main thread and threads created by EAThread.
  220. /// Returns the required count to enumerate all threads.
  221. /// Fills in thread data up till the supplied capacity.
  222. ///
  223. /// Example usage:
  224. /// ThreadEnumData enumData[32];
  225. /// size_t count = EA::Thread::EnumerateThreads(enumData, EAArrayCount(enumData));
  226. ///
  227. /// for(size_t i = 0; i < count; i++)
  228. /// {
  229. /// printf("Thread id: %s\n", EAThreadIdToString(enumData[i].mpThreadDynamicData->mThreadId));
  230. /// enumData[i].Release();
  231. /// }
  232. size_t EATHREADLIB_API EnumerateThreads(ThreadEnumData* pDataArray, size_t dataArrayCapacity);
  233. /// RunnableFunction
  234. /// Defines the prototype of a standalone thread function.
  235. /// The return value is of type intptr_t, which is a standard integral
  236. /// data type that is large enough to hold an int or void*.
  237. typedef intptr_t (*RunnableFunction)(void* pContext);
  238. /// IRunnable
  239. /// Defines a class whose Run function executes in a separate thread.
  240. /// An implementation of this interface can be run using a Thread class instance.
  241. struct EATHREADLIB_API IRunnable
  242. {
  243. virtual ~IRunnable() { }
  244. /// \brief Task run entry point
  245. /// The thread terminates when this method returns.
  246. /// The return value is of type intptr_t, which is a standard integral
  247. /// data type that is large enough to hold an int or void*.
  248. virtual intptr_t Run(void* pContext = NULL) = 0;
  249. };
  250. /// RunnableFunctionUserWrapper
  251. /// Defines the prototype of a user callback function when thread function is started.
  252. /// \param pContext: thread start context void* passed in from thread Thread::Begin()
  253. /// \param defaultRunnableFunction: default function Thread::Begin() normally would
  254. /// call, user must call this function with passed in pContext.
  255. ///
  256. /// Here's an example:
  257. /// \code
  258. /// int ThreadFunction(void*)
  259. /// {
  260. /// printf("Throw NULL pointer Exception.\n");
  261. /// char* pTest = NULL;
  262. /// *pTest = 1;
  263. /// return 0;
  264. /// }
  265. ///
  266. /// intptr_t MyThreadBeginWrapper(RunnableFunction defaultRunnableFunction, void* pContext)
  267. /// {
  268. /// // Do pre-start thread function stuff
  269. /// try {
  270. /// // must call defaultRunnableFunction to execute thread function, if don't then
  271. /// // thread function will never gets executed.
  272. /// intptr_t retValue = defaultRunnableFunction(pContext);
  273. /// }
  274. /// catch(...) {
  275. /// printf("Exception detected.\n");
  276. /// }
  277. ///
  278. /// // do post-start thread function stuff
  279. /// return retValue;
  280. /// }
  281. /// \endcode
  282. ///
  283. /// In your thread begin() function:
  284. /// \code
  285. /// ...
  286. /// threadIds = threads.Begin(ThreadFunction, NULL, NULL, MyThreadBeginWrapper);
  287. /// ...
  288. /// \endcode
  289. typedef intptr_t (*RunnableFunctionUserWrapper)(RunnableFunction defaultRunnableFunction, void* pContext);
  290. /// RunnableClassUserWrapper
  291. /// Defines the prototype of a user callback function when thread function is started.
  292. /// \param pContext: thread start context void* passed in from thread Thread::Begin()
  293. /// \param defaultRunnableFunction: default function Thread::Begin() normally would
  294. /// call, user must call this function with passed in pContext.
  295. ///
  296. /// Here's an example:
  297. /// \code
  298. /// class MyThreadClass
  299. /// {
  300. /// virtual intptr_t Run(void* pContext = NULL)
  301. /// {
  302. /// printf("Throw NULL pointer Exception.\n");
  303. /// char* pTest = NULL;
  304. /// *pTest = 1;
  305. /// return 0;
  306. /// }
  307. /// }
  308. ///
  309. /// intptr_t MyThreadBeginWrapper(IRunnable defaultRunnableFunction, void* pContext)
  310. /// {
  311. /// // do pre-start thread function stuff
  312. ///
  313. /// // a good example is try catch block
  314. /// try
  315. /// {
  316. /// // must call defaultRunnableFunction to execute thread function, if don't then
  317. /// // thread function will never gets executed.
  318. /// intptr_t retValue = defaultRunnableFunction->Run(pContext);
  319. /// }
  320. /// catch(...)
  321. /// {
  322. /// printf("Exception detected.\n");
  323. /// }
  324. ///
  325. /// // do post-start thread function stuff
  326. /// return retValue;
  327. /// }
  328. /// \endcode
  329. ///
  330. /// In your thread begin() function:
  331. ///
  332. /// \code
  333. /// ...
  334. /// MyThreadClass myThreadClass = new MyThreadClass();
  335. /// threadIds = threads.Begin(&myThreadClass, NULL, NULL, MyThreadBeginWrapper);
  336. /// ...
  337. /// \endcode
  338. typedef intptr_t (*RunnableClassUserWrapper)(IRunnable* defaultRunnableClass, void* pContext);
  339. /// ThreadParameters
  340. /// Used for specifying thread starting parameters. Note that we do not
  341. /// include a 'start paused' parameter. The reason for this is that such
  342. /// a thing is not portable and other mechanisms can achieve the same
  343. /// effect. Thread pause/resume in general is considered bad practice.
  344. struct EATHREADLIB_API ThreadParameters
  345. {
  346. void* mpStack; /// Pointer to stack memory. This would be the low address of the memory. A NULL value means to create a default stack. Default is NULL. Note that some platforms (such as Windows) don't support a user-supplied stack.
  347. size_t mnStackSize; /// Size of the stack memory. Default is variable, depending on the platform.
  348. int mnPriority; /// Value in the range of [kThreadPriorityMin, kThreadPriorityMax]. Default is kThreadPriorityDefault.
  349. int mnProcessor; /// 0-based index of which processor to run the thread on. A value of -1 means to use default. Default is -1. See SetThreadProcessor for caveats regarding this value.
  350. const char* mpName; /// A name to give to the thread. Useful for identifying threads in a descriptive way.
  351. EA::Thread::ThreadAffinityMask mnAffinityMask; /// A bitmask representing the cores that the thread is allowed to run on. NOTE: This affinity mask is only applied when mnProcessor is set to kProcessorAny.
  352. bool mbDisablePriorityBoost; /// Whether the system should override the default behavior of boosting the thread priority as they come out of a wait state (currently only supported on Windows).
  353. ThreadParameters();
  354. };
  355. /// Thread
  356. ///
  357. /// Note that we do not provide thread suspend and resume functions.
  358. /// The reason for this is that such things are inherently unsafe as
  359. /// you usually cannot know where the thread is executing when the
  360. /// suspension occurs. The safe alternative is to use signal or
  361. /// semaphore primitives to achieve the same thing in a safe way.
  362. ///
  363. /// For performance reasons, the thread creation functions of this
  364. /// class are themselves not thread-safe. Thus if you want to call
  365. /// the Begin functions for an instance of this class from multiple
  366. /// threads, you will need to synchronize access to the begin
  367. /// functions yourself.
  368. class EATHREADLIB_API Thread
  369. {
  370. public:
  371. enum Status
  372. {
  373. kStatusNone, /// The thread has neither started nor ended.
  374. kStatusRunning, /// The thread has started but not ended.
  375. kStatusEnded /// The thread has both started and ended.
  376. };
  377. /// Thread
  378. /// \brief Thread constructor.
  379. Thread();
  380. /// Thread
  381. /// \brief Thread copy constructor.
  382. Thread(const Thread& t);
  383. /// Thread
  384. /// \brief Thread destructor. The destructor does not take any
  385. /// action on the thread associated with it. Any threads created
  386. /// by this class will continue to run and exit normally after
  387. /// this destructor has executed.
  388. ~Thread();
  389. /// operator=
  390. /// \brief Thread assignment operator.
  391. Thread& operator=(const Thread& t);
  392. /// \brief Return global RunnableFunctionUserWrapper set by user.
  393. /// \return function pointer to RunnableFunctionUserWrapper function user
  394. /// set, if NULL, nothing is set.
  395. /// \sa RunnableFunctionUserWrapper
  396. static RunnableFunctionUserWrapper GetGlobalRunnableFunctionUserWrapper();
  397. /// \brief Set global RunnableFunctionUserWrapper. This can only be
  398. /// set once in the application life time.
  399. /// \param pUserWrapper user specified wrapper function pointer.
  400. /// \sa RunnableFunctionUserWrapper
  401. static void SetGlobalRunnableFunctionUserWrapper(RunnableFunctionUserWrapper pUserWrapper);
  402. /// \brief Return global RunnableClassUserWrapper set by user.
  403. /// \return function pointer to RunnableClassUserWrapper function user
  404. /// set, if NULL, nothing is set.
  405. /// \sa RunnableClassUserWrapper
  406. static RunnableClassUserWrapper GetGlobalRunnableClassUserWrapper();
  407. /// \brief Set global RunnableClassUserWrapper. This can only be
  408. /// set once in the application life time.
  409. /// \sa RunnableClassUserWrapper
  410. static void SetGlobalRunnableClassUserWrapper(RunnableClassUserWrapper pUserWrapper);
  411. /// Begin
  412. /// \brief Starts a thread via a RunnableFunction.
  413. /// Returns the thread id of the newly running thread.
  414. /// The pContext argument is passed to the RunnableFunction and serves
  415. /// to allow the caller to pass information to the thread.
  416. /// The pThreadParameters argument allows the caller to specify additional
  417. /// information about how to start the thread. If this parameter is NULL,
  418. /// then default settings will be chosen.
  419. /// The Begin function itself is not thread-safe. While this Thread class
  420. /// can be used to Begin multiple threads, the Begin function itself cannot
  421. /// safely be executed by multiple threads at a time. This is by design and
  422. /// allows for a simpler more efficient library.
  423. /// User can have their own RunnableFunction wrapper by specifying one in
  424. /// pUserWrapper. When pUserWrapper is used, pUserWrapper will get called
  425. /// first, then pUserWrapper function can do whatever is desired before the
  426. /// just-created thread's entry point is called.
  427. /// \sa RunnableFunctionUserWrapper
  428. ThreadId Begin(RunnableFunction pFunction, void* pContext = NULL, const ThreadParameters* pThreadParameters = NULL, RunnableFunctionUserWrapper pUserWrapper = GetGlobalRunnableFunctionUserWrapper());
  429. /// Begin
  430. /// Starts a thread via an object of the IRunnable interface.
  431. /// Returns the thread id of the newly running thread.
  432. /// The pContext argument is passed to the RunnableFunction and serves
  433. /// to allow the caller to pass information to the thread.
  434. /// The pThreadParameters argument allows the caller to specify additional
  435. /// information about how to start the thread. If this parameter is NULL,
  436. /// then default settings will be chosen.
  437. /// The Begin function itself is not thread-safe. While this Thread class
  438. /// can be used to Begin multiple threads, the Begin function itself cannot
  439. /// safely be executed by multiple threads at a time. This is by design and
  440. /// allows for a simpler more efficient library.
  441. /// User can have their own RunnableClass wrapper by specifying one pUserWrapper.
  442. /// When pUserWrapper is used, pUserWrapper will get called first, then
  443. /// pUserWrapper function can do whatever is desired before the just-created
  444. /// thread's entry point is called.
  445. /// \sa RunnableClassUserWrapper
  446. ThreadId Begin(IRunnable* pRunnable, void* pContext = NULL, const ThreadParameters* pThreadParameters = NULL, RunnableClassUserWrapper pUserWrapper = GetGlobalRunnableClassUserWrapper());
  447. /// WaitForEnd
  448. /// Waits for the thread associated with an object of this class
  449. /// to end. Returns one of enum Status to indicate the status upon
  450. /// return of this call.
  451. /// This function is similar to the Posix pthread_join function and
  452. /// the Windows WaitForSingleObject function.
  453. /// If input pThreadReturnValue is non-NULL, it will be filled in with
  454. /// the return value of the thread.
  455. /// This function must be called only by a single thread at a time.
  456. /// The resulting behaviour is undefined if multiple threads call this function.
  457. ///
  458. /// Note that the timeout is specified in absolute time and not relative time.
  459. ///
  460. /// Note also that due to the way thread scheduling works -- particularly in a
  461. /// time-sliced threading environment -- that the timeout value is a hint and
  462. /// the actual amount of time passed before the timeout occurs may be significantly
  463. /// more or less than the specified timeout time.
  464. ///
  465. Status WaitForEnd(const ThreadTime& timeoutAbsolute = kTimeoutNone, intptr_t* pThreadReturnValue = NULL);
  466. /// GetStatus
  467. /// Returns one of enum GetStatus. Note that in the most general sense
  468. /// the running status may change if the thread quit right after
  469. /// this call was made. But this function is useful if you know that
  470. /// a function was running and you want to poll for its status while
  471. /// waiting for it to exit.
  472. /// If input pThreadReturnValue is non-NULL, it will be filled in with
  473. /// the return value of the thread if the Status is kStatusEnded.
  474. /// If the Status is not kStatusEnded, pThreadReturnValue will be ignored.
  475. Status GetStatus(intptr_t* pThreadReturnValue = NULL) const;
  476. /// GetId
  477. /// Gets the Id of the thread associated with an object of this class.
  478. /// This Id is unique throughout the system. This function returns a
  479. /// value that under Posix threads would be synonymous with pthread_t
  480. /// and under Windows would be synonymous with a thread HANDLE (and not
  481. /// a Windows thread id).
  482. ThreadId GetId() const;
  483. /// GetPriority
  484. /// Gets the priority of the thread. Return kThreadPriorityUnknown if
  485. /// the thread associated with this class isn't running. If a thread
  486. /// wants to get its own priority, it can use this class member or it
  487. /// can simply use the global SetThreadPriority function and not need
  488. /// an instance of this class. If you want to manipulate the thread
  489. /// priority via the native platform interface, you can use GetId to
  490. /// get the platform-specific identifier and use that value with native APIs.
  491. ///
  492. /// This function can return any int except for kThreadPriorityUnknown, as the
  493. /// current thread's priority will always be knowable. A return value of kThreadPriorityDefault
  494. /// means that this thread is of normal (a.k.a. default) priority.
  495. /// See the documentation for thread priority constants (e.g. kThreadPriorityDefault)
  496. /// for more information about thread priority values and behaviour.
  497. int GetPriority() const;
  498. /// SetPriority
  499. /// Sets the priority of the thread. Returns false if the thread associated
  500. /// with this class isn't running. If a thread wants to set its own priority,
  501. /// it can use this class member or it can simply use the global SetThreadPriority
  502. /// function and not need an instance of this class. If you want to manipulate
  503. /// the thread priority via the native platform interface, you can use GetId to
  504. /// get the platform-specific identifier and use that value with native APIs.
  505. ///
  506. /// Accepts any integer priority value except kThreadPriorityUnknown.
  507. /// On some platforms, this function will automatically convert any invalid
  508. /// priority for that particular platform to a valid one. A normal (a.k.a. default) thread
  509. /// priority is identified by kThreadPriorityDefault.
  510. ///
  511. /// You can set the priority of a Thread object only if it has already begun.
  512. /// You can also set the priority with the Begin function via the ThreadParameters
  513. /// argument to Begin. This design is so in order to simply the implementation,
  514. /// but being able to set ThreadParameters before Begin is something that can
  515. /// be considered in the future.
  516. bool SetPriority(int priority);
  517. /// SetProcessor
  518. /// Sets the processor the given thread should run on. Valid values
  519. /// are kThreadProcessorDefault, kThreadProcessorAny, or a processor
  520. /// index in the range of [0, processor count). If the input value
  521. /// is >= the processor count, it will be reduced to be a modulo of
  522. /// the processor count. Any other invalid value will cause the processor
  523. /// to be set to zero.
  524. ///
  525. /// For some platforms you can set the processor of a Thread object only if it
  526. /// has already begun.
  527. ///
  528. /// You can also set the processor with the Begin function via the ThreadParameters
  529. /// argument to Begin. This design is so in order to simply the implementation,
  530. /// but being able to set ThreadParameters before Begin is something that can
  531. /// be considered in the future. This is the most reliable way to set the thread
  532. /// processor, as it works on all platforms.
  533. void SetProcessor(int nProcessor);
  534. /// Wake
  535. /// Wakes up a sleeping thread if it is sleeping. This necessarily can only
  536. /// be called from a thread other than the sleeping thread. You must be careful
  537. /// to not rely on this function as a synchronization primitive. For example,
  538. /// in the general case you cannot be sure that after calling Wake that the
  539. /// thread will be awake, as it is possible that right after you called Wake
  540. /// the thread immediately went back to sleep before you could do anything.
  541. /// Nevertheless, this function is useful in waking up a thread from a
  542. /// (potentially long) sleep so that it can examine data, lock a synchronization
  543. /// primitive, or simply exit.
  544. ///
  545. /// Note that this class has no member Sleep function. The reason is that a
  546. /// thread can only put itself to sleep and cannot put other threads to sleep.
  547. /// The thread should use the static Sleep function to put itself to sleep.
  548. void Wake();
  549. /// GetName
  550. /// Returns the name of the thread assigned by the SetName function.
  551. /// If the thread was not named by the SetName function, then the name is empty ("").
  552. const char* GetName() const;
  553. /// SetName
  554. /// Sets a descriptive name or the thread. On some platforms this name is passed
  555. /// on to the debugging tools so they can see this name. The name length, including
  556. /// a terminating 0 char, is limited to EATHREAD_NAME_SIZE characters. Any characters
  557. /// beyond that are ignored.
  558. ///
  559. /// You can set the name of a Thread object only if it has already begun.
  560. /// You can also set the name with the Begin function via the ThreadParameters
  561. /// argument to Begin. This design is so in order to simply the implementation,
  562. /// but being able to set ThreadParameters before Begin is something that can
  563. /// be considered in the future.
  564. ///
  565. /// Some platforms (e.g. Linux) have the restriction this function works propertly only
  566. /// when called by the same thread that you want to name. Given this situation,
  567. /// the most portable way to use this SetName function is to either always call
  568. /// it from the thread to be named or to use the ThreadParameters to give the
  569. /// thread a name before it is started and let the started thread name itself.
  570. void SetName(const char* pName);
  571. /// SetAffinityMask
  572. /// Sets an affinity mask for the thread. On some platforms, this OS feature is
  573. /// not supported. In this situation, you are at the mercy of the OS thread scheduler.
  574. ///
  575. /// Example(s):
  576. /// "00000100" -> thread is pinned to processor 2
  577. /// "01010100" -> thread is pinned to processor 2, 4, and 6.
  578. void SetAffinityMask(ThreadAffinityMask mnAffinityMask);
  579. /// GetAffinityMask
  580. /// Returns the affinity mask for this specific thread.
  581. ThreadAffinityMask GetAffinityMask();
  582. /// SetDefaultProcessor
  583. /// Sets the default processor to create threads with. To specify the processor
  584. /// for a running thread, use SetProcessor() or specify the processor in the
  585. /// thread creation ThreadParameters.
  586. ///
  587. /// If nProcessor is set to kProcessorAny, EAThread will automatically determine
  588. /// which processor to launch threads to.
  589. ///
  590. /// Please refer to SetProcessor for valid values for the nProcessor argument.
  591. static void SetDefaultProcessor(int nProcessor)
  592. { sDefaultProcessor = nProcessor; }
  593. /// GetDefaultProcessor
  594. /// Gets the default processor to create threads with.
  595. static int GetDefaultProcessor()
  596. { return sDefaultProcessor; }
  597. /// SetDefaultProcessorMask
  598. /// Sets which processors created threads should be explicitly run on.
  599. /// The default value is 0xffffffffffffffff.
  600. /// Each bit refers to the associated processor. A mask of 0xffffffffffffffff
  601. /// means to allow running on any processor, and on desktop platforms such
  602. /// as Windows it means that the OS decides what processor to use on its own.
  603. /// Not all platforms support this functionality, even if multiple processors are present.
  604. static void SetDefaultProcessorMask(uint64_t mask)
  605. { sDefaultProcessorMask.SetValue(mask); }
  606. /// GetDefaultProcessorMask
  607. /// Returns the mask set by SetDefaultProcessorMask.
  608. static uint64_t GetDefaultProcessorMask()
  609. { return sDefaultProcessorMask.GetValue(); }
  610. /// GetPlatformData
  611. /// Returns platform-specific data for this thread for debugging uses or
  612. /// other cases whereby special (and non-portable) uses are required.
  613. /// The value returned is a struct of type EAThreadData.
  614. void* GetPlatformData()
  615. { return &mThreadData; }
  616. protected:
  617. static RunnableFunctionUserWrapper sGlobalRunnableFunctionUserWrapper;
  618. static RunnableClassUserWrapper sGlobalRunnableClassUserWrapper;
  619. static EA::Thread::AtomicInt32 sDefaultProcessor;
  620. static EA::Thread::AtomicUint64 sDefaultProcessorMask;
  621. EAThreadData mThreadData;
  622. };
  623. /// ThreadFactory
  624. ///
  625. /// Implements a factory-based creation and destruction mechanism for class Thread.
  626. /// A primary use of this would be to allow the Thread implementation to reside in
  627. /// a private library while users of the class interact only with the interface
  628. /// header and the factory. The factory provides conventional create/destroy
  629. /// semantics which use global operator new, but also provides manual construction/
  630. /// destruction semantics so that the user can provide for memory allocation
  631. /// and deallocation.
  632. class EATHREADLIB_API ThreadFactory
  633. {
  634. public:
  635. static Thread* CreateThread(); // Internally implemented as: return new Thread;
  636. static void DestroyThread(Thread* pThread); // Internally implemented as: delete pThread;
  637. static size_t GetThreadSize(); // Internally implemented as: return sizeof(Thread);
  638. static Thread* ConstructThread(void* pMemory); // Internally implemented as: return new(pMemory) Thread;
  639. static void DestructThread(Thread* pThread); // Internally implemented as: pThread->~Thread();
  640. };
  641. /// MakeThread
  642. ///
  643. /// Simplify creating threads with lambdas
  644. ///
  645. template <typename F>
  646. auto MakeThread(F&& f, const EA::Thread::ThreadParameters& params = EA::Thread::ThreadParameters())
  647. {
  648. typedef std::decay_t<F> decayed_f_t;
  649. auto get_memory = []
  650. {
  651. const auto sz = sizeof(decayed_f_t);
  652. auto* pAllocator = EA::Thread::GetAllocator();
  653. if(pAllocator)
  654. return pAllocator->Alloc(sz);
  655. else
  656. return malloc(sz);
  657. };
  658. auto thread_enty = [](void* pMemory) -> intptr_t
  659. {
  660. auto free_memory = [](void* p)
  661. {
  662. auto* pAllocator = EA::Thread::GetAllocator();
  663. if(pAllocator)
  664. return pAllocator->Free(p);
  665. else
  666. return free(p);
  667. };
  668. auto* pF = reinterpret_cast<decayed_f_t*>(pMemory);
  669. (*pF)();
  670. pF->~decayed_f_t();
  671. free_memory(pF);
  672. return 0;
  673. };
  674. EA::Thread::Thread thread;
  675. thread.Begin(thread_enty, new(get_memory()) decayed_f_t(std::forward<F>(f)), &params); // deleted in the thread entry function
  676. return thread;
  677. }
  678. } // namespace Thread
  679. } // namespace EA
  680. #if defined(EA_DLL) && defined(_MSC_VER)
  681. // re-enable warning 4251 (it's a level-1 warning and should not be suppressed globally)
  682. #pragma warning(pop)
  683. #endif
  684. #endif // EATHREAD_EATHREAD_THREAD_H