thread.cc revision a5780dad67556297c8ca5f2608c53b193e6c4514
1// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "src/thread.h"
4
5#include <algorithm>
6#include <cerrno>
7#include <list>
8#include <pthread.h>
9#include <sys/mman.h>
10
11#include "src/runtime.h"
12#include "src/utils.h"
13
14namespace art {
15
16pthread_key_t Thread::pthread_key_self_;
17
18Mutex* Mutex::Create(const char* name) {
19  Mutex* mu = new Mutex(name);
20  int result = pthread_mutex_init(&mu->lock_impl_, NULL);
21  CHECK(result == 0);
22  return mu;
23}
24
25void Mutex::Lock() {
26  int result = pthread_mutex_lock(&lock_impl_);
27  CHECK_EQ(result, 0);
28  SetOwner(Thread::Current());
29}
30
31bool Mutex::TryLock() {
32  int result = pthread_mutex_lock(&lock_impl_);
33  if (result == EBUSY) {
34    return false;
35  } else {
36    CHECK_EQ(result, 0);
37    SetOwner(Thread::Current());
38    return true;
39  }
40}
41
42void Mutex::Unlock() {
43  CHECK(GetOwner() == Thread::Current());
44  int result = pthread_mutex_unlock(&lock_impl_);
45  CHECK_EQ(result, 0);
46  SetOwner(Thread::Current());
47}
48
49void* ThreadStart(void *arg) {
50  LOG(FATAL) << "Unimplemented";
51  return NULL;
52}
53
54Thread* Thread::Create(size_t stack_size) {
55  int prot = PROT_READ | PROT_WRITE;
56  // TODO: require the stack size to be page aligned?
57  size_t length = RoundUp(stack_size, 0x1000);
58  void* stack_limit = mmap(NULL, length, prot, MAP_PRIVATE, -1, 0);
59  if (stack_limit == MAP_FAILED) {
60    LOG(FATAL) << "mmap";
61    return false;
62  }
63
64  Thread* new_thread = new Thread;
65  new_thread->stack_limit_ = static_cast<byte*>(stack_limit);
66  new_thread->stack_base_ = new_thread->stack_limit_ + length;
67
68  pthread_attr_t attr;
69  int result = pthread_attr_init(&attr);
70  CHECK_EQ(result, 0);
71
72  result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
73  CHECK_EQ(result, 0);
74
75  pthread_t handle;
76  result = pthread_create(&handle, &attr, ThreadStart, new_thread);
77  CHECK_EQ(result, 0);
78
79  result = pthread_attr_destroy(&attr);
80  CHECK_EQ(result, 0);
81
82  return new_thread;
83}
84
85Thread* Thread::Attach() {
86  Thread* thread = new Thread;
87
88  thread->stack_limit_ = reinterpret_cast<byte*>(-1);  // TODO: getrlimit
89  uintptr_t addr = reinterpret_cast<uintptr_t>(&thread);  // TODO: ask pthreads
90  uintptr_t stack_base = RoundUp(addr, 4096);
91  thread->stack_base_ = reinterpret_cast<byte*>(stack_base);
92  // TODO: set the stack size
93
94  thread->handle_ = pthread_self();
95
96  thread->state_ = kRunnable;
97
98  errno = pthread_setspecific(Thread::pthread_key_self_, thread);
99  if (errno != 0) {
100      PLOG(FATAL) << "pthread_setspecific failed";
101  }
102
103  return thread;
104}
105
106static void ThreadExitCheck(void* arg) {
107  LG << "Thread exit check";
108}
109
110bool Thread::Init() {
111  // Allocate a TLS slot.
112  if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
113    PLOG(WARNING) << "pthread_key_create failed";
114    return false;
115  }
116
117  // Double-check the TLS slot allocation.
118  if (pthread_getspecific(pthread_key_self_) != NULL) {
119    LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
120    return false;
121  }
122
123  // TODO: initialize other locks and condition variables
124
125  return true;
126}
127
128ThreadList* ThreadList::Create() {
129  return new ThreadList;
130}
131
132ThreadList::ThreadList() {
133  lock_ = Mutex::Create("ThreadList::Lock");
134}
135
136ThreadList::~ThreadList() {
137  // Make sure that all threads have exited and unregistered when we
138  // reach this point. This means that all daemon threads had been
139  // shutdown cleanly.
140  CHECK_EQ(list_.size(), 0);
141  delete lock_;
142  lock_ = NULL;
143}
144
145void ThreadList::Register(Thread* thread) {
146  MutexLock mu(lock_);
147  CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
148  list_.push_front(thread);
149}
150
151void ThreadList::Unregister(Thread* thread) {
152  MutexLock mu(lock_);
153  CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
154  list_.remove(thread);
155}
156
157}  // namespace
158