OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(HOST_OS_MACOS) | 6 #if defined(HOST_OS_MACOS) |
7 | 7 |
8 #include "bin/thread.h" | 8 #include "bin/thread.h" |
9 #include "bin/thread_macos.h" | 9 #include "bin/thread_macos.h" |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 namespace bin { | 26 namespace bin { |
27 | 27 |
28 #define VALIDATE_PTHREAD_RESULT(result) \ | 28 #define VALIDATE_PTHREAD_RESULT(result) \ |
29 if (result != 0) { \ | 29 if (result != 0) { \ |
30 const int kBufferSize = 1024; \ | 30 const int kBufferSize = 1024; \ |
31 char error_message[kBufferSize]; \ | 31 char error_message[kBufferSize]; \ |
32 Utils::StrError(result, error_message, kBufferSize); \ | 32 Utils::StrError(result, error_message, kBufferSize); \ |
33 FATAL2("pthread error: %d (%s)", result, error_message); \ | 33 FATAL2("pthread error: %d (%s)", result, error_message); \ |
34 } | 34 } |
35 | 35 |
36 | |
37 #ifdef DEBUG | 36 #ifdef DEBUG |
38 #define RETURN_ON_PTHREAD_FAILURE(result) \ | 37 #define RETURN_ON_PTHREAD_FAILURE(result) \ |
39 if (result != 0) { \ | 38 if (result != 0) { \ |
40 const int kBufferSize = 1024; \ | 39 const int kBufferSize = 1024; \ |
41 char error_message[kBufferSize]; \ | 40 char error_message[kBufferSize]; \ |
42 Utils::StrError(result, error_message, kBufferSize); \ | 41 Utils::StrError(result, error_message, kBufferSize); \ |
43 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \ | 42 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \ |
44 result, error_message); \ | 43 result, error_message); \ |
45 return result; \ | 44 return result; \ |
46 } | 45 } |
47 #else | 46 #else |
48 #define RETURN_ON_PTHREAD_FAILURE(result) \ | 47 #define RETURN_ON_PTHREAD_FAILURE(result) \ |
49 if (result != 0) { \ | 48 if (result != 0) { \ |
50 return result; \ | 49 return result; \ |
51 } | 50 } |
52 #endif | 51 #endif |
53 | 52 |
54 | |
55 class ThreadStartData { | 53 class ThreadStartData { |
56 public: | 54 public: |
57 ThreadStartData(Thread::ThreadStartFunction function, uword parameter) | 55 ThreadStartData(Thread::ThreadStartFunction function, uword parameter) |
58 : function_(function), parameter_(parameter) {} | 56 : function_(function), parameter_(parameter) {} |
59 | 57 |
60 Thread::ThreadStartFunction function() const { return function_; } | 58 Thread::ThreadStartFunction function() const { return function_; } |
61 uword parameter() const { return parameter_; } | 59 uword parameter() const { return parameter_; } |
62 | 60 |
63 private: | 61 private: |
64 Thread::ThreadStartFunction function_; | 62 Thread::ThreadStartFunction function_; |
65 uword parameter_; | 63 uword parameter_; |
66 | 64 |
67 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); | 65 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); |
68 }; | 66 }; |
69 | 67 |
70 | |
71 // Dispatch to the thread start function provided by the caller. This trampoline | 68 // Dispatch to the thread start function provided by the caller. This trampoline |
72 // is used to ensure that the thread is properly destroyed if the thread just | 69 // is used to ensure that the thread is properly destroyed if the thread just |
73 // exits. | 70 // exits. |
74 static void* ThreadStart(void* data_ptr) { | 71 static void* ThreadStart(void* data_ptr) { |
75 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); | 72 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); |
76 | 73 |
77 Thread::ThreadStartFunction function = data->function(); | 74 Thread::ThreadStartFunction function = data->function(); |
78 uword parameter = data->parameter(); | 75 uword parameter = data->parameter(); |
79 delete data; | 76 delete data; |
80 | 77 |
81 // Call the supplied thread start function handing it its parameters. | 78 // Call the supplied thread start function handing it its parameters. |
82 function(parameter); | 79 function(parameter); |
83 | 80 |
84 return NULL; | 81 return NULL; |
85 } | 82 } |
86 | 83 |
87 | |
88 int Thread::Start(ThreadStartFunction function, uword parameter) { | 84 int Thread::Start(ThreadStartFunction function, uword parameter) { |
89 pthread_attr_t attr; | 85 pthread_attr_t attr; |
90 int result = pthread_attr_init(&attr); | 86 int result = pthread_attr_init(&attr); |
91 RETURN_ON_PTHREAD_FAILURE(result); | 87 RETURN_ON_PTHREAD_FAILURE(result); |
92 | 88 |
93 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | 89 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
94 RETURN_ON_PTHREAD_FAILURE(result); | 90 RETURN_ON_PTHREAD_FAILURE(result); |
95 | 91 |
96 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize()); | 92 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize()); |
97 RETURN_ON_PTHREAD_FAILURE(result); | 93 RETURN_ON_PTHREAD_FAILURE(result); |
98 | 94 |
99 ThreadStartData* data = new ThreadStartData(function, parameter); | 95 ThreadStartData* data = new ThreadStartData(function, parameter); |
100 | 96 |
101 pthread_t tid; | 97 pthread_t tid; |
102 result = pthread_create(&tid, &attr, ThreadStart, data); | 98 result = pthread_create(&tid, &attr, ThreadStart, data); |
103 RETURN_ON_PTHREAD_FAILURE(result); | 99 RETURN_ON_PTHREAD_FAILURE(result); |
104 | 100 |
105 result = pthread_attr_destroy(&attr); | 101 result = pthread_attr_destroy(&attr); |
106 RETURN_ON_PTHREAD_FAILURE(result); | 102 RETURN_ON_PTHREAD_FAILURE(result); |
107 | 103 |
108 return 0; | 104 return 0; |
109 } | 105 } |
110 | 106 |
111 | |
112 const ThreadLocalKey Thread::kUnsetThreadLocalKey = | 107 const ThreadLocalKey Thread::kUnsetThreadLocalKey = |
113 static_cast<pthread_key_t>(-1); | 108 static_cast<pthread_key_t>(-1); |
114 const ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL); | 109 const ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL); |
115 | 110 |
116 ThreadLocalKey Thread::CreateThreadLocal() { | 111 ThreadLocalKey Thread::CreateThreadLocal() { |
117 pthread_key_t key = kUnsetThreadLocalKey; | 112 pthread_key_t key = kUnsetThreadLocalKey; |
118 int result = pthread_key_create(&key, NULL); | 113 int result = pthread_key_create(&key, NULL); |
119 VALIDATE_PTHREAD_RESULT(result); | 114 VALIDATE_PTHREAD_RESULT(result); |
120 ASSERT(key != kUnsetThreadLocalKey); | 115 ASSERT(key != kUnsetThreadLocalKey); |
121 return key; | 116 return key; |
122 } | 117 } |
123 | 118 |
124 | |
125 void Thread::DeleteThreadLocal(ThreadLocalKey key) { | 119 void Thread::DeleteThreadLocal(ThreadLocalKey key) { |
126 ASSERT(key != kUnsetThreadLocalKey); | 120 ASSERT(key != kUnsetThreadLocalKey); |
127 int result = pthread_key_delete(key); | 121 int result = pthread_key_delete(key); |
128 VALIDATE_PTHREAD_RESULT(result); | 122 VALIDATE_PTHREAD_RESULT(result); |
129 } | 123 } |
130 | 124 |
131 | |
132 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { | 125 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { |
133 ASSERT(key != kUnsetThreadLocalKey); | 126 ASSERT(key != kUnsetThreadLocalKey); |
134 int result = pthread_setspecific(key, reinterpret_cast<void*>(value)); | 127 int result = pthread_setspecific(key, reinterpret_cast<void*>(value)); |
135 VALIDATE_PTHREAD_RESULT(result); | 128 VALIDATE_PTHREAD_RESULT(result); |
136 } | 129 } |
137 | 130 |
138 | |
139 intptr_t Thread::GetMaxStackSize() { | 131 intptr_t Thread::GetMaxStackSize() { |
140 const int kStackSize = (128 * kWordSize * KB); | 132 const int kStackSize = (128 * kWordSize * KB); |
141 return kStackSize; | 133 return kStackSize; |
142 } | 134 } |
143 | 135 |
144 | |
145 ThreadId Thread::GetCurrentThreadId() { | 136 ThreadId Thread::GetCurrentThreadId() { |
146 return pthread_self(); | 137 return pthread_self(); |
147 } | 138 } |
148 | 139 |
149 | |
150 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { | 140 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { |
151 ASSERT(sizeof(id) == sizeof(intptr_t)); | 141 ASSERT(sizeof(id) == sizeof(intptr_t)); |
152 return reinterpret_cast<intptr_t>(id); | 142 return reinterpret_cast<intptr_t>(id); |
153 } | 143 } |
154 | 144 |
155 | |
156 bool Thread::Compare(ThreadId a, ThreadId b) { | 145 bool Thread::Compare(ThreadId a, ThreadId b) { |
157 return (pthread_equal(a, b) != 0); | 146 return (pthread_equal(a, b) != 0); |
158 } | 147 } |
159 | 148 |
160 | |
161 void Thread::InitOnce() { | 149 void Thread::InitOnce() { |
162 // Nothing to be done. | 150 // Nothing to be done. |
163 } | 151 } |
164 | 152 |
165 | |
166 Mutex::Mutex() { | 153 Mutex::Mutex() { |
167 pthread_mutexattr_t attr; | 154 pthread_mutexattr_t attr; |
168 int result = pthread_mutexattr_init(&attr); | 155 int result = pthread_mutexattr_init(&attr); |
169 VALIDATE_PTHREAD_RESULT(result); | 156 VALIDATE_PTHREAD_RESULT(result); |
170 | 157 |
171 #if defined(DEBUG) | 158 #if defined(DEBUG) |
172 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); | 159 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); |
173 VALIDATE_PTHREAD_RESULT(result); | 160 VALIDATE_PTHREAD_RESULT(result); |
174 #endif // defined(DEBUG) | 161 #endif // defined(DEBUG) |
175 | 162 |
176 result = pthread_mutex_init(data_.mutex(), &attr); | 163 result = pthread_mutex_init(data_.mutex(), &attr); |
177 // Verify that creating a pthread_mutex succeeded. | 164 // Verify that creating a pthread_mutex succeeded. |
178 VALIDATE_PTHREAD_RESULT(result); | 165 VALIDATE_PTHREAD_RESULT(result); |
179 | 166 |
180 result = pthread_mutexattr_destroy(&attr); | 167 result = pthread_mutexattr_destroy(&attr); |
181 VALIDATE_PTHREAD_RESULT(result); | 168 VALIDATE_PTHREAD_RESULT(result); |
182 } | 169 } |
183 | 170 |
184 | |
185 Mutex::~Mutex() { | 171 Mutex::~Mutex() { |
186 int result = pthread_mutex_destroy(data_.mutex()); | 172 int result = pthread_mutex_destroy(data_.mutex()); |
187 // Verify that the pthread_mutex was destroyed. | 173 // Verify that the pthread_mutex was destroyed. |
188 VALIDATE_PTHREAD_RESULT(result); | 174 VALIDATE_PTHREAD_RESULT(result); |
189 } | 175 } |
190 | 176 |
191 | |
192 void Mutex::Lock() { | 177 void Mutex::Lock() { |
193 int result = pthread_mutex_lock(data_.mutex()); | 178 int result = pthread_mutex_lock(data_.mutex()); |
194 // Specifically check for dead lock to help debugging. | 179 // Specifically check for dead lock to help debugging. |
195 ASSERT(result != EDEADLK); | 180 ASSERT(result != EDEADLK); |
196 ASSERT(result == 0); // Verify no other errors. | 181 ASSERT(result == 0); // Verify no other errors. |
197 // TODO(iposva): Do we need to track lock owners? | 182 // TODO(iposva): Do we need to track lock owners? |
198 } | 183 } |
199 | 184 |
200 | |
201 bool Mutex::TryLock() { | 185 bool Mutex::TryLock() { |
202 int result = pthread_mutex_trylock(data_.mutex()); | 186 int result = pthread_mutex_trylock(data_.mutex()); |
203 // Return false if the lock is busy and locking failed. | 187 // Return false if the lock is busy and locking failed. |
204 if ((result == EBUSY) || (result == EDEADLK)) { | 188 if ((result == EBUSY) || (result == EDEADLK)) { |
205 return false; | 189 return false; |
206 } | 190 } |
207 ASSERT(result == 0); // Verify no other errors. | 191 ASSERT(result == 0); // Verify no other errors. |
208 // TODO(iposva): Do we need to track lock owners? | 192 // TODO(iposva): Do we need to track lock owners? |
209 return true; | 193 return true; |
210 } | 194 } |
211 | 195 |
212 | |
213 void Mutex::Unlock() { | 196 void Mutex::Unlock() { |
214 // TODO(iposva): Do we need to track lock owners? | 197 // TODO(iposva): Do we need to track lock owners? |
215 int result = pthread_mutex_unlock(data_.mutex()); | 198 int result = pthread_mutex_unlock(data_.mutex()); |
216 // Specifically check for wrong thread unlocking to aid debugging. | 199 // Specifically check for wrong thread unlocking to aid debugging. |
217 ASSERT(result != EPERM); | 200 ASSERT(result != EPERM); |
218 ASSERT(result == 0); // Verify no other errors. | 201 ASSERT(result == 0); // Verify no other errors. |
219 } | 202 } |
220 | 203 |
221 | |
222 Monitor::Monitor() { | 204 Monitor::Monitor() { |
223 pthread_mutexattr_t attr; | 205 pthread_mutexattr_t attr; |
224 int result = pthread_mutexattr_init(&attr); | 206 int result = pthread_mutexattr_init(&attr); |
225 VALIDATE_PTHREAD_RESULT(result); | 207 VALIDATE_PTHREAD_RESULT(result); |
226 | 208 |
227 #if defined(DEBUG) | 209 #if defined(DEBUG) |
228 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); | 210 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); |
229 VALIDATE_PTHREAD_RESULT(result); | 211 VALIDATE_PTHREAD_RESULT(result); |
230 #endif // defined(DEBUG) | 212 #endif // defined(DEBUG) |
231 | 213 |
232 result = pthread_mutex_init(data_.mutex(), &attr); | 214 result = pthread_mutex_init(data_.mutex(), &attr); |
233 VALIDATE_PTHREAD_RESULT(result); | 215 VALIDATE_PTHREAD_RESULT(result); |
234 | 216 |
235 result = pthread_mutexattr_destroy(&attr); | 217 result = pthread_mutexattr_destroy(&attr); |
236 VALIDATE_PTHREAD_RESULT(result); | 218 VALIDATE_PTHREAD_RESULT(result); |
237 | 219 |
238 result = pthread_cond_init(data_.cond(), NULL); | 220 result = pthread_cond_init(data_.cond(), NULL); |
239 VALIDATE_PTHREAD_RESULT(result); | 221 VALIDATE_PTHREAD_RESULT(result); |
240 } | 222 } |
241 | 223 |
242 | |
243 Monitor::~Monitor() { | 224 Monitor::~Monitor() { |
244 int result = pthread_mutex_destroy(data_.mutex()); | 225 int result = pthread_mutex_destroy(data_.mutex()); |
245 VALIDATE_PTHREAD_RESULT(result); | 226 VALIDATE_PTHREAD_RESULT(result); |
246 | 227 |
247 result = pthread_cond_destroy(data_.cond()); | 228 result = pthread_cond_destroy(data_.cond()); |
248 VALIDATE_PTHREAD_RESULT(result); | 229 VALIDATE_PTHREAD_RESULT(result); |
249 } | 230 } |
250 | 231 |
251 | |
252 void Monitor::Enter() { | 232 void Monitor::Enter() { |
253 int result = pthread_mutex_lock(data_.mutex()); | 233 int result = pthread_mutex_lock(data_.mutex()); |
254 VALIDATE_PTHREAD_RESULT(result); | 234 VALIDATE_PTHREAD_RESULT(result); |
255 // TODO(iposva): Do we need to track lock owners? | 235 // TODO(iposva): Do we need to track lock owners? |
256 } | 236 } |
257 | 237 |
258 | |
259 void Monitor::Exit() { | 238 void Monitor::Exit() { |
260 // TODO(iposva): Do we need to track lock owners? | 239 // TODO(iposva): Do we need to track lock owners? |
261 int result = pthread_mutex_unlock(data_.mutex()); | 240 int result = pthread_mutex_unlock(data_.mutex()); |
262 VALIDATE_PTHREAD_RESULT(result); | 241 VALIDATE_PTHREAD_RESULT(result); |
263 } | 242 } |
264 | 243 |
265 | |
266 Monitor::WaitResult Monitor::Wait(int64_t millis) { | 244 Monitor::WaitResult Monitor::Wait(int64_t millis) { |
267 return WaitMicros(millis * kMicrosecondsPerMillisecond); | 245 return WaitMicros(millis * kMicrosecondsPerMillisecond); |
268 } | 246 } |
269 | 247 |
270 | |
271 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { | 248 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { |
272 // TODO(iposva): Do we need to track lock owners? | 249 // TODO(iposva): Do we need to track lock owners? |
273 Monitor::WaitResult retval = kNotified; | 250 Monitor::WaitResult retval = kNotified; |
274 if (micros == kNoTimeout) { | 251 if (micros == kNoTimeout) { |
275 // Wait forever. | 252 // Wait forever. |
276 int result = pthread_cond_wait(data_.cond(), data_.mutex()); | 253 int result = pthread_cond_wait(data_.cond(), data_.mutex()); |
277 VALIDATE_PTHREAD_RESULT(result); | 254 VALIDATE_PTHREAD_RESULT(result); |
278 } else { | 255 } else { |
279 struct timespec ts; | 256 struct timespec ts; |
280 int64_t secs = micros / kMicrosecondsPerSecond; | 257 int64_t secs = micros / kMicrosecondsPerSecond; |
281 if (secs > kMaxInt32) { | 258 if (secs > kMaxInt32) { |
282 // Avoid truncation of overly large timeout values. | 259 // Avoid truncation of overly large timeout values. |
283 secs = kMaxInt32; | 260 secs = kMaxInt32; |
284 } | 261 } |
285 int64_t nanos = | 262 int64_t nanos = |
286 (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond; | 263 (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond; |
287 ts.tv_sec = static_cast<int32_t>(secs); | 264 ts.tv_sec = static_cast<int32_t>(secs); |
288 ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec). | 265 ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec). |
289 int result = | 266 int result = |
290 pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts); | 267 pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts); |
291 ASSERT((result == 0) || (result == ETIMEDOUT)); | 268 ASSERT((result == 0) || (result == ETIMEDOUT)); |
292 if (result == ETIMEDOUT) { | 269 if (result == ETIMEDOUT) { |
293 retval = kTimedOut; | 270 retval = kTimedOut; |
294 } | 271 } |
295 } | 272 } |
296 return retval; | 273 return retval; |
297 } | 274 } |
298 | 275 |
299 | |
300 void Monitor::Notify() { | 276 void Monitor::Notify() { |
301 // TODO(iposva): Do we need to track lock owners? | 277 // TODO(iposva): Do we need to track lock owners? |
302 int result = pthread_cond_signal(data_.cond()); | 278 int result = pthread_cond_signal(data_.cond()); |
303 VALIDATE_PTHREAD_RESULT(result); | 279 VALIDATE_PTHREAD_RESULT(result); |
304 } | 280 } |
305 | 281 |
306 | |
307 void Monitor::NotifyAll() { | 282 void Monitor::NotifyAll() { |
308 // TODO(iposva): Do we need to track lock owners? | 283 // TODO(iposva): Do we need to track lock owners? |
309 int result = pthread_cond_broadcast(data_.cond()); | 284 int result = pthread_cond_broadcast(data_.cond()); |
310 VALIDATE_PTHREAD_RESULT(result); | 285 VALIDATE_PTHREAD_RESULT(result); |
311 } | 286 } |
312 | 287 |
313 } // namespace bin | 288 } // namespace bin |
314 } // namespace dart | 289 } // namespace dart |
315 | 290 |
316 #endif // defined(HOST_OS_MACOS) | 291 #endif // defined(HOST_OS_MACOS) |
OLD | NEW |