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 | |
30 | namespace dart { |
31 | |
32 | DEFINE_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 | |
79 | class 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. |
101 | static 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 | |
138 | int 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 | |
160 | const ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL); |
161 | const ThreadJoinId OSThread::kInvalidThreadJoinId = |
162 | reinterpret_cast<ThreadJoinId>(NULL); |
163 | |
164 | ThreadLocalKey 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 | |
172 | void OSThread::DeleteThreadLocal(ThreadLocalKey key) { |
173 | ASSERT(key != kUnsetThreadLocalKey); |
174 | int result = pthread_key_delete(key); |
175 | VALIDATE_PTHREAD_RESULT(result); |
176 | } |
177 | |
178 | void 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 | |
184 | intptr_t OSThread::GetMaxStackSize() { |
185 | const int kStackSize = (128 * kWordSize * KB); |
186 | return kStackSize; |
187 | } |
188 | |
189 | ThreadId OSThread::GetCurrentThreadId() { |
190 | return pthread_self(); |
191 | } |
192 | |
193 | #ifdef SUPPORT_TIMELINE |
194 | ThreadId OSThread::GetCurrentThreadTraceId() { |
195 | return ThreadIdFromIntPtr(pthread_mach_thread_np(pthread_self())); |
196 | } |
197 | #endif // PRODUCT |
198 | |
199 | ThreadJoinId 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 | |
212 | void OSThread::Join(ThreadJoinId id) { |
213 | int result = pthread_join(id, NULL); |
214 | ASSERT(result == 0); |
215 | } |
216 | |
217 | intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { |
218 | ASSERT(sizeof(id) == sizeof(intptr_t)); |
219 | return reinterpret_cast<intptr_t>(id); |
220 | } |
221 | |
222 | ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { |
223 | return reinterpret_cast<ThreadId>(id); |
224 | } |
225 | |
226 | bool OSThread::Compare(ThreadId a, ThreadId b) { |
227 | return pthread_equal(a, b) != 0; |
228 | } |
229 | |
230 | bool 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) |
237 | NO_SANITIZE_ADDRESS |
238 | NO_SANITIZE_SAFE_STACK |
239 | uword OSThread::GetCurrentSafestackPointer() { |
240 | #error "SAFE_STACK is unsupported on this platform" |
241 | return 0; |
242 | } |
243 | |
244 | NO_SANITIZE_ADDRESS |
245 | NO_SANITIZE_SAFE_STACK |
246 | void OSThread::SetCurrentSafestackPointer(uword ssp) { |
247 | #error "SAFE_STACK is unsupported on this platform" |
248 | } |
249 | #endif |
250 | |
251 | Mutex::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 | |
278 | Mutex::~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 | |
289 | void 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 | |
300 | bool 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 | |
314 | void 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 | |
326 | Monitor::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 | |
351 | Monitor::~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 | |
364 | bool 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 | |
379 | void 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 | |
390 | void 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 | |
401 | Monitor::WaitResult Monitor::Wait(int64_t millis) { |
402 | return WaitMicros(millis * kMicrosecondsPerMillisecond); |
403 | } |
404 | |
405 | Monitor::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 | |
446 | void 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 | |
453 | void 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 | |