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