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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h" // NOLINT
6#if defined(HOST_OS_MACOS)
7
8#include "vm/os_thread.h"
9
10#include <mach/mach_host.h> // NOLINT
11#include <mach/mach_init.h> // NOLINT
12#include <mach/mach_port.h> // NOLINT
13#include <mach/mach_traps.h> // NOLINT
14#include <mach/task_info.h> // NOLINT
15#include <mach/thread_act.h> // NOLINT
16#include <mach/thread_info.h> // NOLINT
17#include <signal.h> // NOLINT
18#include <sys/errno.h> // NOLINT
19#include <sys/sysctl.h> // NOLINT
20#include <sys/types.h> // NOLINT
21
22#include "platform/address_sanitizer.h"
23#include "platform/assert.h"
24#include "platform/safe_stack.h"
25#include "platform/signal_blocker.h"
26#include "platform/utils.h"
27
28#include "vm/flags.h"
29
30namespace dart {
31
32DEFINE_FLAG(int,
33 worker_thread_priority,
34 kMinInt,
35 "The thread priority the VM should use for new worker threads.");
36
37#define VALIDATE_PTHREAD_RESULT(result) \
38 if (result != 0) { \
39 const int kBufferSize = 1024; \
40 char error_message[kBufferSize]; \
41 Utils::StrError(result, error_message, kBufferSize); \
42 FATAL2("pthread error: %d (%s)", result, error_message); \
43 }
44
45#if defined(PRODUCT)
46#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
47#else
48#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
49 if (result != 0) { \
50 const int kBufferSize = 1024; \
51 char error_message[kBufferSize]; \
52 Utils::StrError(result, error_message, kBufferSize); \
53 FATAL3("[%s] pthread error: %d (%s)", name_, result, error_message); \
54 }
55#endif
56
57#if defined(DEBUG)
58#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
59#else
60// NOTE: This (currently) expands to a no-op.
61#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
62#endif
63
64#ifdef DEBUG
65#define RETURN_ON_PTHREAD_FAILURE(result) \
66 if (result != 0) { \
67 const int kBufferSize = 1024; \
68 char error_message[kBufferSize]; \
69 Utils::StrError(result, error_message, kBufferSize); \
70 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
71 result, error_message); \
72 return result; \
73 }
74#else
75#define RETURN_ON_PTHREAD_FAILURE(result) \
76 if (result != 0) return result;
77#endif
78
79class ThreadStartData {
80 public:
81 ThreadStartData(const char* name,
82 OSThread::ThreadStartFunction function,
83 uword parameter)
84 : name_(name), function_(function), parameter_(parameter) {}
85
86 const char* name() const { return name_; }
87 OSThread::ThreadStartFunction function() const { return function_; }
88 uword parameter() const { return parameter_; }
89
90 private:
91 const char* name_;
92 OSThread::ThreadStartFunction function_;
93 uword parameter_;
94
95 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
96};
97
98// Dispatch to the thread start function provided by the caller. This trampoline
99// is used to ensure that the thread is properly destroyed if the thread just
100// exits.
101static void* ThreadStart(void* data_ptr) {
102 if (FLAG_worker_thread_priority != kMinInt) {
103 const pthread_t thread = pthread_self();
104 int policy = SCHED_FIFO;
105 struct sched_param schedule;
106 if (pthread_getschedparam(thread, &policy, &schedule) != 0) {
107 FATAL1("Obtainign sched param failed: errno = %d\n", errno);
108 }
109 schedule.sched_priority = FLAG_worker_thread_priority;
110 if (pthread_setschedparam(thread, policy, &schedule) != 0) {
111 FATAL2("Setting thread priority to %d failed: errno = %d\n",
112 FLAG_worker_thread_priority, errno);
113 }
114 }
115
116 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
117
118 const char* name = data->name();
119 OSThread::ThreadStartFunction function = data->function();
120 uword parameter = data->parameter();
121 delete data;
122
123 // Set the thread name.
124 pthread_setname_np(name);
125
126 // Create new OSThread object and set as TLS for new thread.
127 OSThread* thread = OSThread::CreateOSThread();
128 if (thread != NULL) {
129 OSThread::SetCurrent(thread);
130 thread->set_name(name);
131 // Call the supplied thread start function handing it its parameters.
132 function(parameter);
133 }
134
135 return NULL;
136}
137
138int OSThread::Start(const char* name,
139 ThreadStartFunction function,
140 uword parameter) {
141 pthread_attr_t attr;
142 int result = pthread_attr_init(&attr);
143 RETURN_ON_PTHREAD_FAILURE(result);
144
145 result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
146 RETURN_ON_PTHREAD_FAILURE(result);
147
148 ThreadStartData* data = new ThreadStartData(name, function, parameter);
149
150 pthread_t tid;
151 result = pthread_create(&tid, &attr, ThreadStart, data);
152 RETURN_ON_PTHREAD_FAILURE(result);
153
154 result = pthread_attr_destroy(&attr);
155 RETURN_ON_PTHREAD_FAILURE(result);
156
157 return 0;
158}
159
160const ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
161const ThreadJoinId OSThread::kInvalidThreadJoinId =
162 reinterpret_cast<ThreadJoinId>(NULL);
163
164ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
165 pthread_key_t key = kUnsetThreadLocalKey;
166 int result = pthread_key_create(&key, destructor);
167 VALIDATE_PTHREAD_RESULT(result);
168 ASSERT(key != kUnsetThreadLocalKey);
169 return key;
170}
171
172void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
173 ASSERT(key != kUnsetThreadLocalKey);
174 int result = pthread_key_delete(key);
175 VALIDATE_PTHREAD_RESULT(result);
176}
177
178void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
179 ASSERT(key != kUnsetThreadLocalKey);
180 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
181 VALIDATE_PTHREAD_RESULT(result);
182}
183
184intptr_t OSThread::GetMaxStackSize() {
185 const int kStackSize = (128 * kWordSize * KB);
186 return kStackSize;
187}
188
189ThreadId OSThread::GetCurrentThreadId() {
190 return pthread_self();
191}
192
193#ifdef SUPPORT_TIMELINE
194ThreadId OSThread::GetCurrentThreadTraceId() {
195 return ThreadIdFromIntPtr(pthread_mach_thread_np(pthread_self()));
196}
197#endif // PRODUCT
198
199ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
200 ASSERT(thread != NULL);
201 // Make sure we're filling in the join id for the current thread.
202 ASSERT(thread->id() == GetCurrentThreadId());
203 // Make sure the join_id_ hasn't been set, yet.
204 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
205 pthread_t id = pthread_self();
206#if defined(DEBUG)
207 thread->join_id_ = id;
208#endif
209 return id;
210}
211
212void OSThread::Join(ThreadJoinId id) {
213 int result = pthread_join(id, NULL);
214 ASSERT(result == 0);
215}
216
217intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) {
218 ASSERT(sizeof(id) == sizeof(intptr_t));
219 return reinterpret_cast<intptr_t>(id);
220}
221
222ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
223 return reinterpret_cast<ThreadId>(id);
224}
225
226bool OSThread::Compare(ThreadId a, ThreadId b) {
227 return pthread_equal(a, b) != 0;
228}
229
230bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
231 *upper = reinterpret_cast<uword>(pthread_get_stackaddr_np(pthread_self()));
232 *lower = *upper - pthread_get_stacksize_np(pthread_self());
233 return true;
234}
235
236#if defined(USING_SAFE_STACK)
237NO_SANITIZE_ADDRESS
238NO_SANITIZE_SAFE_STACK
239uword OSThread::GetCurrentSafestackPointer() {
240#error "SAFE_STACK is unsupported on this platform"
241 return 0;
242}
243
244NO_SANITIZE_ADDRESS
245NO_SANITIZE_SAFE_STACK
246void OSThread::SetCurrentSafestackPointer(uword ssp) {
247#error "SAFE_STACK is unsupported on this platform"
248}
249#endif
250
251Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
252#if !defined(PRODUCT)
253 : name_(name)
254#endif
255{
256 pthread_mutexattr_t attr;
257 int result = pthread_mutexattr_init(&attr);
258 VALIDATE_PTHREAD_RESULT_NAMED(result);
259
260#if defined(DEBUG)
261 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
262 VALIDATE_PTHREAD_RESULT_NAMED(result);
263#endif // defined(DEBUG)
264
265 result = pthread_mutex_init(data_.mutex(), &attr);
266 // Verify that creating a pthread_mutex succeeded.
267 VALIDATE_PTHREAD_RESULT_NAMED(result);
268
269 result = pthread_mutexattr_destroy(&attr);
270 VALIDATE_PTHREAD_RESULT_NAMED(result);
271
272#if defined(DEBUG)
273 // When running with assertions enabled we do track the owner.
274 owner_ = OSThread::kInvalidThreadId;
275#endif // defined(DEBUG)
276}
277
278Mutex::~Mutex() {
279 int result = pthread_mutex_destroy(data_.mutex());
280 // Verify that the pthread_mutex was destroyed.
281 VALIDATE_PTHREAD_RESULT_NAMED(result);
282
283#if defined(DEBUG)
284 // When running with assertions enabled we do track the owner.
285 ASSERT(owner_ == OSThread::kInvalidThreadId);
286#endif // defined(DEBUG)
287}
288
289void Mutex::Lock() {
290 int result = pthread_mutex_lock(data_.mutex());
291 // Specifically check for dead lock to help debugging.
292 ASSERT(result != EDEADLK);
293 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
294#if defined(DEBUG)
295 // When running with assertions enabled we do track the owner.
296 owner_ = OSThread::GetCurrentThreadId();
297#endif // defined(DEBUG)
298}
299
300bool Mutex::TryLock() {
301 int result = pthread_mutex_trylock(data_.mutex());
302 // Return false if the lock is busy and locking failed.
303 if ((result == EBUSY) || (result == EDEADLK)) {
304 return false;
305 }
306 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
307#if defined(DEBUG)
308 // When running with assertions enabled we do track the owner.
309 owner_ = OSThread::GetCurrentThreadId();
310#endif // defined(DEBUG)
311 return true;
312}
313
314void Mutex::Unlock() {
315#if defined(DEBUG)
316 // When running with assertions enabled we do track the owner.
317 ASSERT(IsOwnedByCurrentThread());
318 owner_ = OSThread::kInvalidThreadId;
319#endif // defined(DEBUG)
320 int result = pthread_mutex_unlock(data_.mutex());
321 // Specifically check for wrong thread unlocking to aid debugging.
322 ASSERT(result != EPERM);
323 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
324}
325
326Monitor::Monitor() {
327 pthread_mutexattr_t attr;
328 int result = pthread_mutexattr_init(&attr);
329 VALIDATE_PTHREAD_RESULT(result);
330
331#if defined(DEBUG)
332 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
333 VALIDATE_PTHREAD_RESULT(result);
334#endif // defined(DEBUG)
335
336 result = pthread_mutex_init(data_.mutex(), &attr);
337 VALIDATE_PTHREAD_RESULT(result);
338
339 result = pthread_mutexattr_destroy(&attr);
340 VALIDATE_PTHREAD_RESULT(result);
341
342 result = pthread_cond_init(data_.cond(), NULL);
343 VALIDATE_PTHREAD_RESULT(result);
344
345#if defined(DEBUG)
346 // When running with assertions enabled we track the owner.
347 owner_ = OSThread::kInvalidThreadId;
348#endif // defined(DEBUG)
349}
350
351Monitor::~Monitor() {
352#if defined(DEBUG)
353 // When running with assertions enabled we track the owner.
354 ASSERT(owner_ == OSThread::kInvalidThreadId);
355#endif // defined(DEBUG)
356
357 int result = pthread_mutex_destroy(data_.mutex());
358 VALIDATE_PTHREAD_RESULT(result);
359
360 result = pthread_cond_destroy(data_.cond());
361 VALIDATE_PTHREAD_RESULT(result);
362}
363
364bool Monitor::TryEnter() {
365 int result = pthread_mutex_trylock(data_.mutex());
366 // Return false if the lock is busy and locking failed.
367 if ((result == EBUSY) || (result == EDEADLK)) {
368 return false;
369 }
370 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
371#if defined(DEBUG)
372 // When running with assertions enabled we track the owner.
373 ASSERT(owner_ == OSThread::kInvalidThreadId);
374 owner_ = OSThread::GetCurrentThreadId();
375#endif // defined(DEBUG)
376 return true;
377}
378
379void Monitor::Enter() {
380 int result = pthread_mutex_lock(data_.mutex());
381 VALIDATE_PTHREAD_RESULT(result);
382
383#if defined(DEBUG)
384 // When running with assertions enabled we track the owner.
385 ASSERT(owner_ == OSThread::kInvalidThreadId);
386 owner_ = OSThread::GetCurrentThreadId();
387#endif // defined(DEBUG)
388}
389
390void Monitor::Exit() {
391#if defined(DEBUG)
392 // When running with assertions enabled we track the owner.
393 ASSERT(IsOwnedByCurrentThread());
394 owner_ = OSThread::kInvalidThreadId;
395#endif // defined(DEBUG)
396
397 int result = pthread_mutex_unlock(data_.mutex());
398 VALIDATE_PTHREAD_RESULT(result);
399}
400
401Monitor::WaitResult Monitor::Wait(int64_t millis) {
402 return WaitMicros(millis * kMicrosecondsPerMillisecond);
403}
404
405Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
406#if defined(DEBUG)
407 // When running with assertions enabled we track the owner.
408 ASSERT(IsOwnedByCurrentThread());
409 ThreadId saved_owner = owner_;
410 owner_ = OSThread::kInvalidThreadId;
411#endif // defined(DEBUG)
412
413 Monitor::WaitResult retval = kNotified;
414 if (micros == kNoTimeout) {
415 // Wait forever.
416 int result = pthread_cond_wait(data_.cond(), data_.mutex());
417 VALIDATE_PTHREAD_RESULT(result);
418 } else {
419 struct timespec ts;
420 int64_t secs = micros / kMicrosecondsPerSecond;
421 if (secs > kMaxInt32) {
422 // Avoid truncation of overly large timeout values.
423 secs = kMaxInt32;
424 }
425 int64_t nanos =
426 (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
427 ts.tv_sec = static_cast<int32_t>(secs);
428 ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
429 int result =
430 pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts);
431 ASSERT((result == 0) || (result == ETIMEDOUT));
432 if (result == ETIMEDOUT) {
433 retval = kTimedOut;
434 }
435 }
436
437#if defined(DEBUG)
438 // When running with assertions enabled we track the owner.
439 ASSERT(owner_ == OSThread::kInvalidThreadId);
440 owner_ = OSThread::GetCurrentThreadId();
441 ASSERT(owner_ == saved_owner);
442#endif // defined(DEBUG)
443 return retval;
444}
445
446void Monitor::Notify() {
447 // When running with assertions enabled we track the owner.
448 ASSERT(IsOwnedByCurrentThread());
449 int result = pthread_cond_signal(data_.cond());
450 VALIDATE_PTHREAD_RESULT(result);
451}
452
453void Monitor::NotifyAll() {
454 // When running with assertions enabled we track the owner.
455 ASSERT(IsOwnedByCurrentThread());
456 int result = pthread_cond_broadcast(data_.cond());
457 VALIDATE_PTHREAD_RESULT(result);
458}
459
460} // namespace dart
461
462#endif // defined(HOST_OS_MACOS)
463