[vm] Add build-time option to use absl mutexes in place of pthread mutexes.

TEST=ci, cbuild
Bug: b/220994782
Change-Id: Id1a15d0d9fcef192847b25a2549730eb1014a99e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/236760
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2022-03-10 23:48:05 +00:00 committed by Commit Bot
parent d4bc590c27
commit a48d05c8f9
19 changed files with 822 additions and 21 deletions

View file

@ -45,6 +45,8 @@ builtin_impl_sources = [
"isolate_data.h",
"lockers.h",
"thread.h",
"thread_absl.cc",
"thread_absl.h",
"thread_android.cc",
"thread_android.h",
"thread_fuchsia.cc",

View file

@ -16,7 +16,9 @@ class Monitor;
} // namespace dart
// Declare the OS-specific types ahead of defining the generic classes.
#if defined(DART_HOST_OS_ANDROID)
#if defined(DART_USE_ABSL)
#include "bin/thread_absl.h"
#elif defined(DART_HOST_OS_ANDROID)
#include "bin/thread_android.h"
#elif defined(DART_HOST_OS_FUCHSIA)
#include "bin/thread_fuchsia.h"

221
runtime/bin/thread_absl.cc Normal file
View file

@ -0,0 +1,221 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_USE_ABSL)
#include <errno.h> // NOLINT
#include <sys/resource.h> // NOLINT
#include <sys/time.h> // NOLINT
#include "bin/thread.h"
#include "bin/thread_absl.h"
#include "platform/assert.h"
#include "platform/utils.h"
namespace dart {
namespace bin {
#define VALIDATE_PTHREAD_RESULT(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
FATAL2("pthread error: %d (%s)", result, \
Utils::StrError(result, error_buf, kBufferSize)); \
}
#ifdef DEBUG
#define RETURN_ON_PTHREAD_FAILURE(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
result, Utils::StrError(result, error_buf, kBufferSize)); \
return result; \
}
#else
#define RETURN_ON_PTHREAD_FAILURE(result) \
if (result != 0) { \
return result; \
}
#endif
class ThreadStartData {
public:
ThreadStartData(const char* name,
Thread::ThreadStartFunction function,
uword parameter)
: name_(name), function_(function), parameter_(parameter) {}
const char* name() const { return name_; }
Thread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
const char* name_;
Thread::ThreadStartFunction function_;
uword parameter_;
DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
};
// Dispatch to the thread start function provided by the caller. This trampoline
// is used to ensure that the thread is properly destroyed if the thread just
// exits.
static void* ThreadStart(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
const char* name = data->name();
Thread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
// Set the thread name. There is 16 bytes limit on the name (including \0).
// pthread_setname_np ignores names that are too long rather than truncating.
char truncated_name[16];
snprintf(truncated_name, sizeof(truncated_name), "%s", name);
pthread_setname_np(pthread_self(), truncated_name);
// Call the supplied thread start function handing it its parameters.
function(parameter);
return NULL;
}
int Thread::Start(const char* name,
ThreadStartFunction function,
uword parameter) {
pthread_attr_t attr;
int result = pthread_attr_init(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
RETURN_ON_PTHREAD_FAILURE(result);
result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
RETURN_ON_PTHREAD_FAILURE(result);
ThreadStartData* data = new ThreadStartData(name, function, parameter);
pthread_t tid;
result = pthread_create(&tid, &attr, ThreadStart, data);
RETURN_ON_PTHREAD_FAILURE(result);
result = pthread_attr_destroy(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
return 0;
}
const ThreadLocalKey Thread::kUnsetThreadLocalKey =
static_cast<pthread_key_t>(-1);
const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
int result = pthread_key_create(&key, NULL);
VALIDATE_PTHREAD_RESULT(result);
ASSERT(key != kUnsetThreadLocalKey);
return key;
}
void Thread::DeleteThreadLocal(ThreadLocalKey key) {
ASSERT(key != kUnsetThreadLocalKey);
int result = pthread_key_delete(key);
VALIDATE_PTHREAD_RESULT(result);
}
void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
ASSERT(key != kUnsetThreadLocalKey);
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
VALIDATE_PTHREAD_RESULT(result);
}
intptr_t Thread::GetMaxStackSize() {
const int kStackSize = (128 * kWordSize * KB);
return kStackSize;
}
ThreadId Thread::GetCurrentThreadId() {
return pthread_self();
}
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) == sizeof(intptr_t));
return static_cast<intptr_t>(id);
}
bool Thread::Compare(ThreadId a, ThreadId b) {
return (pthread_equal(a, b) != 0);
}
Mutex::Mutex() : data_() {}
Mutex::~Mutex() {}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Mutex::Lock() {
data_.mutex()->Lock();
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
bool Mutex::TryLock() {
if (!data_.mutex()->TryLock()) {
return false;
}
return true;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Mutex::Unlock() {
data_.mutex()->Unlock();
}
Monitor::Monitor() : data_() {}
Monitor::~Monitor() {}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Enter() {
data_.mutex()->Lock();
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Exit() {
data_.mutex()->Unlock();
}
Monitor::WaitResult Monitor::Wait(int64_t millis) {
return WaitMicros(millis * kMicrosecondsPerMillisecond);
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
Monitor::WaitResult retval = kNotified;
if (micros == kNoTimeout) {
// Wait forever.
data_.cond()->Wait(data_.mutex());
} else {
if (data_.cond()->WaitWithTimeout(data_.mutex(),
absl::Microseconds(micros))) {
retval = kTimedOut;
}
}
return retval;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Notify() {
data_.cond()->Signal();
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::NotifyAll() {
data_.cond()->SignalAll();
}
} // namespace bin
} // namespace dart
#endif // defined(DART_USE_ABSL)

76
runtime/bin/thread_absl.h Normal file
View file

@ -0,0 +1,76 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_BIN_THREAD_ABSL_H_
#define RUNTIME_BIN_THREAD_ABSL_H_
#if !defined(RUNTIME_BIN_THREAD_H_)
#error Do not include thread_absl.h directly; use thread.h instead.
#endif
#include <pthread.h>
#include "platform/assert.h"
#include "platform/globals.h"
#include "third_party/absl/synchronization/mutex.h"
namespace dart {
namespace bin {
typedef pthread_key_t ThreadLocalKey;
typedef pthread_t ThreadId;
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
~ThreadInlineImpl() {}
static uword GetThreadLocal(ThreadLocalKey key) {
static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
ASSERT(key != kUnsetThreadLocalKey);
return reinterpret_cast<uword>(pthread_getspecific(key));
}
friend class Thread;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
};
class MutexData {
private:
MutexData() : mutex_() {}
~MutexData() {}
absl::Mutex* mutex() { return &mutex_; }
absl::Mutex mutex_;
friend class Mutex;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(MutexData);
};
class MonitorData {
private:
MonitorData() : mutex_(), cond_() {}
~MonitorData() {}
absl::Mutex* mutex() { return &mutex_; }
absl::CondVar* cond() { return &cond_; }
absl::Mutex mutex_;
absl::CondVar cond_;
friend class Monitor;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(MonitorData);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_THREAD_ABSL_H_

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_ANDROID)
#if defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL)
#include "bin/thread.h"
#include "bin/thread_android.h"
@ -301,4 +301,4 @@ void Monitor::NotifyAll() {
} // namespace bin
} // namespace dart
#endif // defined(DART_HOST_OS_ANDROID)
#endif // defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_FUCHSIA)
#if defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)
#include "bin/thread.h"
#include "bin/thread_fuchsia.h"
@ -305,4 +305,4 @@ void Monitor::NotifyAll() {
} // namespace bin
} // namespace dart
#endif // defined(DART_HOST_OS_FUCHSIA)
#endif // defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_LINUX)
#if defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)
#include "bin/thread.h"
#include "bin/thread_linux.h"
@ -304,4 +304,4 @@ void Monitor::NotifyAll() {
} // namespace bin
} // namespace dart
#endif // defined(DART_HOST_OS_LINUX)
#endif // defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_MACOS)
#if defined(DART_HOST_OS_MACOS) && !defined(DART_USE_ABSL)
#include "bin/thread.h"
#include "bin/thread_macos.h"
@ -294,4 +294,4 @@ void Monitor::NotifyAll() {
} // namespace bin
} // namespace dart
#endif // defined(DART_HOST_OS_MACOS)
#endif // defined(DART_HOST_OS_MACOS) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_WINDOWS)
#if defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
#include "bin/thread.h"
#include "bin/thread_win.h"
@ -192,4 +192,4 @@ void Monitor::NotifyAll() {
} // namespace bin
} // namespace dart
#endif // defined(DART_HOST_OS_WINDOWS)
#endif // defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)

View file

@ -64,6 +64,7 @@ final Set<String> excludedFiles = Set<String>.from([
'runtime/bin/socket_base_linux.h',
'runtime/bin/socket_base_macos.h',
'runtime/bin/socket_base_win.h',
'runtime/bin/thread_absl.h',
'runtime/bin/thread_android.h',
'runtime/bin/thread_fuchsia.h',
'runtime/bin/thread_linux.h',
@ -100,6 +101,7 @@ final Set<String> excludedFiles = Set<String>.from([
'runtime/vm/instructions_ia32.h',
'runtime/vm/instructions_riscv.h',
'runtime/vm/instructions_x64.h',
'runtime/vm/os_thread_absl.h',
'runtime/vm/os_thread_android.h',
'runtime/vm/os_thread_fuchsia.h',
'runtime/vm/os_thread_linux.h',

View file

@ -13,7 +13,9 @@
#include "vm/globals.h"
// Declare the OS-specific types ahead of defining the generic classes.
#if defined(DART_HOST_OS_ANDROID)
#if defined(DART_USE_ABSL)
#include "vm/os_thread_absl.h"
#elif defined(DART_HOST_OS_ANDROID)
#include "vm/os_thread_android.h"
#elif defined(DART_HOST_OS_FUCHSIA)
#include "vm/os_thread_fuchsia.h"

View file

@ -0,0 +1,417 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h" // NOLINT
#if defined(DART_USE_ABSL)
#include <errno.h> // NOLINT
#include <stdio.h>
#include <sys/resource.h> // NOLINT
#include <sys/syscall.h> // NOLINT
#include <sys/time.h> // NOLINT
#include "platform/address_sanitizer.h"
#include "platform/assert.h"
#include "platform/safe_stack.h"
#include "platform/signal_blocker.h"
#include "platform/utils.h"
#include "vm/flags.h"
#include "vm/os_thread.h"
namespace dart {
DEFINE_FLAG(int,
worker_thread_priority,
kMinInt,
"The thread priority the VM should use for new worker threads.");
#define VALIDATE_PTHREAD_RESULT(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
FATAL2("pthread error: %d (%s)", result, \
Utils::StrError(result, error_buf, kBufferSize)); \
}
// Variation of VALIDATE_PTHREAD_RESULT for named objects.
#if defined(PRODUCT)
#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
#else
#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
FATAL3("[%s] pthread error: %d (%s)", name_, result, \
Utils::StrError(result, error_buf, kBufferSize)); \
}
#endif
#if defined(DEBUG)
#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
#else
// NOTE: This (currently) expands to a no-op.
#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
#endif
#ifdef DEBUG
#define RETURN_ON_PTHREAD_FAILURE(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
result, Utils::StrError(result, error_buf, kBufferSize)); \
return result; \
}
#else
#define RETURN_ON_PTHREAD_FAILURE(result) \
if (result != 0) return result;
#endif
class ThreadStartData {
public:
ThreadStartData(const char* name,
OSThread::ThreadStartFunction function,
uword parameter)
: name_(name), function_(function), parameter_(parameter) {}
const char* name() const { return name_; }
OSThread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
const char* name_;
OSThread::ThreadStartFunction function_;
uword parameter_;
DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
};
// TODO(bkonyi): remove this call once the prebuilt SDK is updated.
// Spawned threads inherit their spawner's signal mask. We sometimes spawn
// threads for running Dart code from a thread that is blocking SIGPROF.
// This function explicitly unblocks SIGPROF so the profiler continues to
// sample this thread.
static void UnblockSIGPROF() {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPROF);
int r = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
USE(r);
ASSERT(r == 0);
ASSERT(!CHECK_IS_BLOCKING(SIGPROF));
}
// Dispatch to the thread start function provided by the caller. This trampoline
// is used to ensure that the thread is properly destroyed if the thread just
// exits.
static void* ThreadStart(void* data_ptr) {
if (FLAG_worker_thread_priority != kMinInt) {
if (setpriority(PRIO_PROCESS, syscall(__NR_gettid),
FLAG_worker_thread_priority) == -1) {
FATAL2("Setting thread priority to %d failed: errno = %d\n",
FLAG_worker_thread_priority, errno);
}
}
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
const char* name = data->name();
OSThread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
// Set the thread name. There is 16 bytes limit on the name (including \0).
// pthread_setname_np ignores names that are too long rather than truncating.
char truncated_name[16];
snprintf(truncated_name, ARRAY_SIZE(truncated_name), "%s", name);
pthread_setname_np(pthread_self(), truncated_name);
// Create new OSThread object and set as TLS for new thread.
OSThread* thread = OSThread::CreateOSThread();
if (thread != NULL) {
OSThread::SetCurrent(thread);
thread->set_name(name);
UnblockSIGPROF();
// Call the supplied thread start function handing it its parameters.
function(parameter);
}
return NULL;
}
int OSThread::Start(const char* name,
ThreadStartFunction function,
uword parameter) {
pthread_attr_t attr;
int result = pthread_attr_init(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
RETURN_ON_PTHREAD_FAILURE(result);
ThreadStartData* data = new ThreadStartData(name, function, parameter);
pthread_t tid;
result = pthread_create(&tid, &attr, ThreadStart, data);
RETURN_ON_PTHREAD_FAILURE(result);
result = pthread_attr_destroy(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
return 0;
}
const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
const ThreadJoinId OSThread::kInvalidThreadJoinId =
static_cast<ThreadJoinId>(0);
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
pthread_key_t key = kUnsetThreadLocalKey;
int result = pthread_key_create(&key, destructor);
VALIDATE_PTHREAD_RESULT(result);
ASSERT(key != kUnsetThreadLocalKey);
return key;
}
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
ASSERT(key != kUnsetThreadLocalKey);
int result = pthread_key_delete(key);
VALIDATE_PTHREAD_RESULT(result);
}
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
ASSERT(key != kUnsetThreadLocalKey);
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
VALIDATE_PTHREAD_RESULT(result);
}
intptr_t OSThread::GetMaxStackSize() {
const int kStackSize = (128 * kWordSize * KB);
return kStackSize;
}
ThreadId OSThread::GetCurrentThreadId() {
return pthread_self();
}
#ifdef SUPPORT_TIMELINE
ThreadId OSThread::GetCurrentThreadTraceId() {
return syscall(__NR_gettid);
}
#endif // PRODUCT
ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
ASSERT(thread != NULL);
// Make sure we're filling in the join id for the current thread.
ASSERT(thread->id() == GetCurrentThreadId());
// Make sure the join_id_ hasn't been set, yet.
DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
pthread_t id = pthread_self();
#if defined(DEBUG)
thread->join_id_ = id;
#endif
return id;
}
void OSThread::Join(ThreadJoinId id) {
int result = pthread_join(id, NULL);
ASSERT(result == 0);
}
intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) == sizeof(intptr_t));
return static_cast<intptr_t>(id);
}
ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
return static_cast<ThreadId>(id);
}
bool OSThread::Compare(ThreadId a, ThreadId b) {
return pthread_equal(a, b) != 0;
}
bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
pthread_attr_t attr;
// May fail on the main thread.
if (pthread_getattr_np(pthread_self(), &attr) != 0) {
return false;
}
void* base;
size_t size;
int error = pthread_attr_getstack(&attr, &base, &size);
pthread_attr_destroy(&attr);
if (error != 0) {
return false;
}
*lower = reinterpret_cast<uword>(base);
*upper = *lower + size;
return true;
}
#if defined(USING_SAFE_STACK)
NO_SANITIZE_ADDRESS
NO_SANITIZE_SAFE_STACK
uword OSThread::GetCurrentSafestackPointer() {
#error "SAFE_STACK is unsupported on this platform"
return 0;
}
NO_SANITIZE_ADDRESS
NO_SANITIZE_SAFE_STACK
void OSThread::SetCurrentSafestackPointer(uword ssp) {
#error "SAFE_STACK is unsupported on this platform"
}
#endif
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
#if !defined(PRODUCT)
: name_(name)
#endif
{
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
Mutex::~Mutex() {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Mutex::Lock() {
data_.mutex()->Lock();
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
bool Mutex::TryLock() {
if (!data_.mutex()->TryLock()) {
return false;
}
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Mutex::Unlock() {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(IsOwnedByCurrentThread());
owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
data_.mutex()->Unlock();
}
Monitor::Monitor() {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
Monitor::~Monitor() {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
bool Monitor::TryEnter() {
if (!data_.mutex()->TryLock()) {
return false;
}
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(owner_ == OSThread::kInvalidThreadId);
owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Enter() {
data_.mutex()->Lock();
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(owner_ == OSThread::kInvalidThreadId);
owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Exit() {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(IsOwnedByCurrentThread());
owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
data_.mutex()->Unlock();
}
Monitor::WaitResult Monitor::Wait(int64_t millis) {
Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
return retval;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(IsOwnedByCurrentThread());
ThreadId saved_owner = owner_;
owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
Monitor::WaitResult retval = kNotified;
if (micros == kNoTimeout) {
// Wait forever.
data_.cond()->Wait(data_.mutex());
} else {
if (data_.cond()->WaitWithTimeout(data_.mutex(),
absl::Microseconds(micros))) {
retval = kTimedOut;
}
}
#if defined(DEBUG)
// When running with assertions enabled we track the owner.
ASSERT(owner_ == OSThread::kInvalidThreadId);
owner_ = OSThread::GetCurrentThreadId();
ASSERT(owner_ == saved_owner);
#endif // defined(DEBUG)
return retval;
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::Notify() {
// When running with assertions enabled we track the owner.
ASSERT(IsOwnedByCurrentThread());
data_.cond()->Signal();
}
ABSL_NO_THREAD_SAFETY_ANALYSIS
void Monitor::NotifyAll() {
// When running with assertions enabled we track the owner.
ASSERT(IsOwnedByCurrentThread());
xdata_.cond()->SignalAll();
}
} // namespace dart
#endif // defined(DART_USE_ABSL)

View file

@ -0,0 +1,77 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_OS_THREAD_ABSL_H_
#define RUNTIME_VM_OS_THREAD_ABSL_H_
#if !defined(RUNTIME_VM_OS_THREAD_H_)
#error Do not include os_thread_absl.h directly; use os_thread.h instead.
#endif
#include <pthread.h>
#include "platform/assert.h"
#include "platform/globals.h"
#include "third_party/absl/synchronization/mutex.h"
namespace dart {
typedef pthread_key_t ThreadLocalKey;
typedef pthread_t ThreadId;
typedef pthread_t ThreadJoinId;
static const ThreadLocalKey kUnsetThreadLocalKey =
static_cast<pthread_key_t>(-1);
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
~ThreadInlineImpl() {}
static uword GetThreadLocal(ThreadLocalKey key) {
ASSERT(key != kUnsetThreadLocalKey);
return reinterpret_cast<uword>(pthread_getspecific(key));
}
friend class OSThread;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
};
class MutexData {
private:
MutexData() : mutex_() {}
~MutexData() {}
absl::Mutex* mutex() { return &mutex_; }
absl::Mutex mutex_;
friend class Mutex;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(MutexData);
};
class MonitorData {
private:
MonitorData() : mutex_(), cond_() {}
~MonitorData() {}
absl::Mutex* mutex() { return &mutex_; }
absl::CondVar* cond() { return &cond_; }
absl::Mutex mutex_;
absl::CondVar cond_;
friend class Monitor;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(MonitorData);
};
} // namespace dart
#endif // RUNTIME_VM_OS_THREAD_ABSL_H_

View file

@ -4,7 +4,7 @@
#include "platform/globals.h" // NOLINT
#if defined(DART_HOST_OS_ANDROID)
#if defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL)
#include "vm/os_thread.h"
@ -491,4 +491,4 @@ void Monitor::NotifyAll() {
} // namespace dart
#endif // defined(DART_HOST_OS_ANDROID)
#endif // defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h" // NOLINT
#if defined(DART_HOST_OS_FUCHSIA)
#if defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)
#include "vm/os.h"
#include "vm/os_thread.h"
@ -492,4 +492,4 @@ void Monitor::NotifyAll() {
} // namespace dart
#endif // defined(DART_HOST_OS_FUCHSIA)
#endif // defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)

View file

@ -4,7 +4,7 @@
#include "platform/globals.h" // NOLINT
#if defined(DART_HOST_OS_LINUX)
#if defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)
#include "vm/os_thread.h"
@ -497,4 +497,4 @@ void Monitor::NotifyAll() {
} // namespace dart
#endif // defined(DART_HOST_OS_LINUX)
#endif // defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h" // NOLINT
#if defined(DART_HOST_OS_MACOS)
#if defined(DART_HOST_OS_MACOS) && !defined(DART_USE_ABSL)
#include "vm/os_thread.h"

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h" // NOLINT
#if defined(DART_HOST_OS_WINDOWS)
#if defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
#include "vm/growable_array.h"
#include "vm/lockers.h"
@ -530,4 +530,4 @@ PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit;
#endif // _WIN64
} // extern "C"
#endif // defined(DART_HOST_OS_WINDOWS)
#endif // defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)

View file

@ -210,6 +210,8 @@ vm_sources = [
"os_macos.cc",
"os_thread.cc",
"os_thread.h",
"os_thread_absl.cc",
"os_thread_absl.h",
"os_thread_android.cc",
"os_thread_android.h",
"os_thread_fuchsia.cc",