File: thread.hpp

package info (click to toggle)
rocm-hipamd 6.4.3-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 23,036 kB
  • sloc: cpp: 211,057; ansic: 35,860; sh: 755; python: 623; perl: 275; asm: 166; makefile: 27
file content (219 lines) | stat: -rw-r--r-- 6,294 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/* Copyright (c) 2008 - 2021 Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#ifndef THREAD_HPP_
#define THREAD_HPP_

#include "top.hpp"
#include "thread/semaphore.hpp"
#include "os/os.hpp"

#include <string>
#include <memory>

#if defined(_WIN32)
#define USE_DECLSPEC_THREAD 1
#if !defined(USE_DECLSPEC_THREAD)
#include <windows.h>
#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(bool passOwnership = false);

  //! 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(bool passOwnership = false);

  //! Return true is this is the host thread.
  bool isHostThread() const { return true; };
};

/*! @}
 *  @}
 */

namespace details {

#if defined(__linux__)

extern thread_local std::unique_ptr<Thread> thread_;
extern thread_local Thread* mthread_;

static inline Thread* currentThread() { return mthread_ ? mthread_ : thread_.get(); }

#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_*/