// // Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved. // #ifndef THREAD_HPP_ #define THREAD_HPP_ #include "top.hpp" #include "thread/semaphore.hpp" #include "os/os.hpp" #include #if defined(_WIN32) # define USE_DECLSPEC_THREAD 1 # if !defined(USE_DECLSPEC_THREAD) # include # endif /*!USE_DECLSPEC_THREAD*/ #endif /*_WIN32*/ namespace amd { /*! \addtogroup Threads Threading package * @{ * * \addtogroup OsThread Native Threads * @{ */ class Monitor; class Thread : public HeapObject { friend const void* Os::createOsThread(Thread*); public: enum ThreadState { CREATED, INITIALIZED, RUNNABLE, SUSPENDED, FINISHED, FAILED }; private: //! System thread handle. const void* handle_; //! The thread's name. const std::string name_; //! Current running state. volatile ThreadState state_; //! The argument passed to run() void* data_; //! \cond ignore Semaphore* created_; //!< To notify the parent thread. Semaphore* lock_; //!< For mutex support (during contention). Semaphore* suspend_; //!< For wait/suspend support. //! \endcond Monitor* selfSuspendLock_; //!< For self suspend/resume. protected: address stackBase_; //!< Main stack base. size_t stackSize_; //!< Main stack size. private: /*! \brief The start wrapper for all newly create threads. * This is called from the pthread_create start_thread. */ static void* entry(Thread* thread); /*! \brief Thread main (called from the main function). * Setup the thread for running and wait for the semaphore to be signaled. */ void* main(); //! The entry point for this thread. virtual void run(void* data) = 0; protected: //! Bring this thread to the created state. void create(); //! Set the current thread state. void setState(ThreadState state) { state_ = state; } //! Set the thread-local _thread variable (used by current()). void setCurrent(); //! Register the given memory region as a valid stack. void registerStack(address base, address top); /*! \brief Construct a new thread. * If \a spawn is false, do not create a new OS thread, instead, * bind to the currently running on. */ explicit Thread( const std::string& name, size_t stackSize = 0 /*use system default*/, bool spawn = true /* create a new Os::thread */); public: //! Return the currently running thread instance. static inline Thread* current(); //! Initialize the OsThread package. static bool init(); //! Tear down the OsThread package. static void tearDown(); //! Destroy this thread. virtual ~Thread(); //! Return the thread's name const std::string& name() const { return name_; } //! Get the system thread handle. const void* handle() const { return handle_; } //! Start the thread execution bool start(void *data = NULL); //! Resume the thread void resume(); //! Return true is this is the host thread. virtual bool isHostThread() const { return false; } //! Return true if this is a worker thread. virtual bool isWorkerThread() const { return false; } //! Get the current thread state. ThreadState state() const { return state_; } //! Return this thread's stack base. address stackBase() const { return stackBase_; } //! Return this thread's stack size. size_t stackSize() const { return stackSize_; } //! Return this thread's stack bottom. address stackBottom() const { return stackBase() - stackSize(); } //! Return this thread's contend semaphore. Semaphore& lockSemaphore() const { return *lock_; } //! Return this thread's resume semaphore. Semaphore& suspendSemaphore() const { return *suspend_; } //! Set this thread's affinity to the given cpu. void setAffinity(uint cpu_id) const { Os::setThreadAffinity(handle_, cpu_id); } //! Set this thread's affinity to the given cpu mask. void setAffinity(const Os::ThreadAffinityMask& mask) const { Os::setThreadAffinity(handle_, mask); } //! Yield to threads of the same priority of higher static void yield() { Os::yield(); } }; class HostThread : public Thread { private: //! A HostThread does not have a run function virtual void run(void* data) { ShouldNotCallThis(); } public: //! Construct a new HostThread HostThread(); //! Return true is this is the host thread. bool isHostThread() const { return true; }; }; /*! @} * @} */ namespace details { #if defined(__linux__) extern __thread Thread* thread_ __attribute__((tls_model("initial-exec"))); static inline Thread* currentThread() { return thread_; } #elif defined(_WIN32) #if defined(USE_DECLSPEC_THREAD) extern __declspec(thread) Thread* thread_; #else // !USE_DECLSPEC_THREAD extern DWORD threadIndex_; #endif // !USE_DECLSPEC_THREAD static inline Thread* currentThread() { #if defined(USE_DECLSPEC_THREAD) return thread_; #else // !USE_DECLSPEC_THREAD return (Thread*) TlsGetValue(threadIndex_); #endif // !USE_DECLSPEC_THREAD } #endif // _WIN32 } // namespace details inline Thread* Thread::current() { return details::currentThread(); } } // namespace amd #endif /*THREAD_HPP_*/