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