thread.h revision 69759eaa6fd4386f1e6d8748052ad221087b3476
1// Copyright 2011 Google Inc. All Rights Reserved.
2// Author: cshapiro@google.com (Carl Shapiro)
3
4#ifndef ART_SRC_THREAD_H_
5#define ART_SRC_THREAD_H_
6
7#include <pthread.h>
8#include <list>
9
10#include "src/globals.h"
11#include "src/jni_internal.h"
12#include "src/logging.h"
13#include "src/macros.h"
14#include "src/offsets.h"
15#include "src/runtime.h"
16
17#include "jni.h"
18
19namespace art {
20
21class Object;
22class Runtime;
23class StackHandleBlock;
24class Thread;
25class ThreadList;
26
27class Mutex {
28 public:
29  virtual ~Mutex() {}
30
31  void Lock();
32
33  bool TryLock();
34
35  void Unlock();
36
37  const char* GetName() { return name_; }
38
39  Thread* GetOwner() { return owner_; }
40
41  static Mutex* Create(const char* name);
42
43 public:  // TODO: protected
44  explicit Mutex(const char* name) : name_(name), owner_(NULL) {}
45
46  void SetOwner(Thread* thread) { owner_ = thread; }
47
48 private:
49  const char* name_;
50
51  Thread* owner_;
52
53  pthread_mutex_t lock_impl_;
54
55  DISALLOW_COPY_AND_ASSIGN(Mutex);
56};
57
58class MutexLock {
59 public:
60  explicit MutexLock(Mutex *mu) : mu_(mu) {
61    mu_->Lock();
62  }
63  ~MutexLock() { mu_->Unlock(); }
64 private:
65  Mutex* const mu_;
66  DISALLOW_COPY_AND_ASSIGN(MutexLock);
67};
68
69// Stack handle blocks are allocated within the bridge frame between managed
70// and native code.
71class StackHandleBlock {
72 public:
73  // Number of references contained within this SHB
74  size_t NumberOfReferences() {
75    return number_of_references_;
76  }
77
78  // Link to previous SHB or NULL
79  StackHandleBlock* Link() {
80    return link_;
81  }
82
83  // Offset of length within SHB, used by generated code
84  static size_t NumberOfReferencesOffset() {
85    return OFFSETOF_MEMBER(StackHandleBlock, number_of_references_);
86  }
87
88  // Offset of link within SHB, used by generated code
89  static size_t LinkOffset() {
90    return OFFSETOF_MEMBER(StackHandleBlock, link_);
91  }
92
93 private:
94  StackHandleBlock() {}
95
96  size_t number_of_references_;
97  StackHandleBlock* link_;
98
99  DISALLOW_COPY_AND_ASSIGN(StackHandleBlock);
100};
101
102class Thread {
103 public:
104  enum State {
105    kUnknown = -1,
106    kNew,
107    kRunnable,
108    kBlocked,
109    kWaiting,
110    kTimedWaiting,
111    kNative,
112    kTerminated,
113  };
114
115  static const size_t kDefaultStackSize = 64 * KB;
116
117  // Creates a new thread.
118  static Thread* Create(size_t stack_size);
119
120  // Creates a new thread from the calling thread.
121  static Thread* Attach();
122
123  static Thread* Current() {
124    void* thread = pthread_getspecific(Thread::pthread_key_self_);
125    return reinterpret_cast<Thread*>(thread);
126  }
127
128  uint32_t GetId() const {
129    return id_;
130  }
131
132  pid_t GetNativeId() const {
133    return native_id_;
134  }
135
136  bool IsExceptionPending() const {
137    return false;  // TODO exception_ != NULL;
138  }
139
140  Object* GetException() const {
141    return exception_;
142  }
143
144  void SetException(Object* new_exception) {
145    CHECK(new_exception != NULL);
146    // TODO: CHECK(exception_ == NULL);
147    exception_ = new_exception;  // TODO
148  }
149
150  void ClearException() {
151    exception_ = NULL;
152  }
153
154  void SetName(const char* name);
155
156  void Suspend();
157
158  bool IsSuspended();
159
160  void Resume();
161
162  static bool Init();
163
164  Runtime* GetRuntime() const {
165    return runtime_;
166  }
167
168  State GetState() {
169    return state_;
170  }
171
172  void SetState(State new_state) {
173    state_ = new_state;
174  }
175
176  // Offset of state within Thread, used by generated code
177  static ThreadOffset StateOffset() {
178    return ThreadOffset(OFFSETOF_MEMBER(Thread, state_));
179  }
180
181  // JNI methods
182  JniEnvironment* GetJniEnv() const {
183    return jni_env_;
184  }
185
186  // Offset of JNI environment within Thread, used by generated code
187  static ThreadOffset JniEnvOffset() {
188    return ThreadOffset(OFFSETOF_MEMBER(Thread, jni_env_));
189  }
190
191  // Offset of top stack handle block within Thread, used by generated code
192  static ThreadOffset TopShbOffset() {
193    return ThreadOffset(OFFSETOF_MEMBER(Thread, top_shb_));
194  }
195
196  // Number of references allocated in StackHandleBlocks on this thread
197  size_t NumShbHandles() {
198    size_t count = 0;
199    for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
200      count += cur->NumberOfReferences();
201    }
202    return count;
203  }
204
205 private:
206  Thread() :
207    id_(1234), top_shb_(NULL), exception_(NULL) {
208    jni_env_ = new JniEnvironment();
209  }
210
211  ~Thread() {
212    delete jni_env_;
213  }
214
215  void InitCpu();
216
217  // Managed thread id.
218  uint32_t id_;
219
220  // Top of linked list of stack handle blocks or NULL for none
221  StackHandleBlock* top_shb_;
222
223  // Every thread may have an associated JNI environment
224  JniEnvironment* jni_env_;
225
226  State state_;
227
228  // Native (kernel) thread id.
229  pid_t native_id_;
230
231  // Native thread handle.
232  pthread_t handle_;
233
234  // Initialized to "this". On certain architectures (such as x86) reading
235  // off of Thread::Current is easy but getting the address of Thread::Current
236  // is hard. This field can be read off of Thread::Current to give the address.
237  Thread* self_;
238
239  Runtime* runtime_;
240
241  // The pending exception or NULL.
242  Object* exception_;
243
244  // The inclusive base of the control stack.
245  byte* stack_base_;
246
247  // The exclusive limit of the control stack.
248  byte* stack_limit_;
249
250  // TLS key used to retrieve the VM thread object.
251  static pthread_key_t pthread_key_self_;
252
253  DISALLOW_COPY_AND_ASSIGN(Thread);
254};
255std::ostream& operator<<(std::ostream& os, const Thread::State& state);
256
257class ThreadList {
258 public:
259  static const int kMaxId = 0xFFFF;
260  static const int kInvalidId = 0;
261  static const int kMainId = 1;
262
263  static ThreadList* Create();
264
265  ~ThreadList();
266
267  void Register(Thread* thread);
268
269  void Unregister(Thread* thread);
270
271  void Lock() {
272    lock_->Lock();
273  }
274
275  void Unlock() {
276    lock_->Unlock();
277  };
278
279 private:
280  ThreadList();
281
282  std::list<Thread*> list_;
283
284  Mutex* lock_;
285
286  DISALLOW_COPY_AND_ASSIGN(ThreadList);
287};
288
289class ThreadListLock {
290 public:
291  ThreadListLock(ThreadList* thread_list, Thread* current_thread)
292      : thread_list_(thread_list) {
293    if (current_thread == NULL) {  // try to get it from TLS
294      current_thread = Thread::Current();
295    }
296    Thread::State old_state;
297    if (current_thread != NULL) {
298      old_state = current_thread->GetState();
299      current_thread->SetState(Thread::kWaiting);  // TODO: VMWAIT
300    } else {
301      // happens during VM shutdown
302      old_state = Thread::kUnknown;  // TODO: something else
303    }
304    thread_list_->Lock();
305    if (current_thread != NULL) {
306      current_thread->SetState(old_state);
307    }
308  }
309
310  ~ThreadListLock() {
311    thread_list_->Unlock();
312  }
313
314 private:
315  ThreadList* thread_list_;
316
317  DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
318};
319
320}  // namespace art
321
322#endif  // ART_SRC_THREAD_H_
323