[vm] Move synchronization primitives to platform
This CL also removes ability to assign names to mutexes which was
added in c25ebfff96 but did not yield
any interesting data.
TEST=ci
CoreLibraryReviewExempt: Changes to dart:concurrent only.
Cq-Include-Trybots: luci.dart.try:vm-fuchsia-release-x64-try,vm-win-debug-x64-try,vm-win-release-x64-try,vm-aot-linux-product-x64-try
Change-Id: Id41e1d29832f6008e02f0a571ee67564e1a84224
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375300
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
b3c4471f82
commit
e105029f62
@@ -42,15 +42,10 @@ builtin_impl_sources = [
|
||||
"lockers.h",
|
||||
"thread.h",
|
||||
"thread_absl.cc",
|
||||
"thread_absl.h",
|
||||
"thread_fuchsia.cc",
|
||||
"thread_fuchsia.h",
|
||||
"thread_linux.cc",
|
||||
"thread_linux.h",
|
||||
"thread_macos.cc",
|
||||
"thread_macos.h",
|
||||
"thread_win.cc",
|
||||
"thread_win.h",
|
||||
"uri.cc",
|
||||
"uri.h",
|
||||
"utils.cc",
|
||||
|
||||
@@ -190,15 +190,7 @@ Handle::Handle(intptr_t handle,
|
||||
monitor_(),
|
||||
type_(type),
|
||||
handle_(reinterpret_cast<HANDLE>(handle)),
|
||||
data_ready_(),
|
||||
pending_read_(nullptr),
|
||||
pending_write_(nullptr),
|
||||
last_error_(NOERROR),
|
||||
read_thread_id_(Thread::kInvalidThreadId),
|
||||
read_thread_handle_(nullptr),
|
||||
read_thread_starting_(false),
|
||||
read_thread_finished_(false),
|
||||
flags_(0) {
|
||||
data_ready_() {
|
||||
if (supports_overlapped_io == SupportsOverlappedIO::kYes) {
|
||||
EventHandler::delegate()->AssociateWithCompletionPort(this);
|
||||
} else {
|
||||
@@ -256,14 +248,13 @@ void Handle::WaitForReadThreadFinished() {
|
||||
HANDLE to_join = nullptr;
|
||||
{
|
||||
MonitorLocker ml(&monitor_);
|
||||
if (read_thread_id_ != Thread::kInvalidThreadId) {
|
||||
if (read_thread_ != INVALID_HANDLE_VALUE) {
|
||||
while (!read_thread_finished_) {
|
||||
ml.Wait();
|
||||
}
|
||||
read_thread_finished_ = false;
|
||||
read_thread_id_ = Thread::kInvalidThreadId;
|
||||
to_join = read_thread_handle_;
|
||||
read_thread_handle_ = nullptr;
|
||||
to_join = read_thread_;
|
||||
read_thread_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
if (to_join != nullptr) {
|
||||
@@ -296,12 +287,22 @@ void Handle::WriteComplete(std::unique_ptr<OverlappedBuffer> buffer) {
|
||||
pending_write_ = nullptr;
|
||||
}
|
||||
|
||||
// Helper method which returns a real HANDLE for the current thread.
|
||||
static HANDLE GetCurrentThreadHandle() {
|
||||
HANDLE thread_handle = INVALID_HANDLE_VALUE;
|
||||
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
||||
GetCurrentProcess(), &thread_handle,
|
||||
/*dwDesiredAccess=*/0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
FATAL("Failed to obtain thread handle");
|
||||
}
|
||||
return thread_handle;
|
||||
}
|
||||
|
||||
void Handle::NotifyReadThreadStarted() {
|
||||
MonitorLocker ml(&monitor_);
|
||||
ASSERT(read_thread_starting_);
|
||||
ASSERT(read_thread_id_ == Thread::kInvalidThreadId);
|
||||
read_thread_id_ = Thread::GetCurrentThreadId();
|
||||
read_thread_handle_ = OpenThread(SYNCHRONIZE, false, read_thread_id_);
|
||||
ASSERT(read_thread_ == INVALID_HANDLE_VALUE);
|
||||
read_thread_ = GetCurrentThreadHandle();
|
||||
read_thread_starting_ = false;
|
||||
ml.Notify();
|
||||
}
|
||||
@@ -309,7 +310,7 @@ void Handle::NotifyReadThreadStarted() {
|
||||
void Handle::NotifyReadThreadFinished() {
|
||||
MonitorLocker ml(&monitor_);
|
||||
ASSERT(!read_thread_finished_);
|
||||
ASSERT(read_thread_id_ != Thread::kInvalidThreadId);
|
||||
ASSERT(read_thread_ != INVALID_HANDLE_VALUE);
|
||||
read_thread_finished_ = true;
|
||||
ml.Notify();
|
||||
}
|
||||
@@ -747,8 +748,7 @@ StdHandle* StdHandle::Stdin(HANDLE handle) {
|
||||
void StdHandle::RunWriteLoop() {
|
||||
MonitorLocker ml(&monitor_);
|
||||
write_thread_running_ = true;
|
||||
thread_id_ = Thread::GetCurrentThreadId();
|
||||
thread_handle_ = OpenThread(SYNCHRONIZE, false, thread_id_);
|
||||
thread_handle_ = GetCurrentThreadHandle();
|
||||
// Notify we have started.
|
||||
ml.Notify();
|
||||
|
||||
@@ -1339,14 +1339,11 @@ void EventHandlerImplementation::HandleCompletionOrInterrupt(
|
||||
}
|
||||
|
||||
EventHandlerImplementation::EventHandlerImplementation() {
|
||||
handler_thread_id_ = Thread::kInvalidThreadId;
|
||||
handler_thread_handle_ = nullptr;
|
||||
completion_port_ =
|
||||
CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, NULL, 1);
|
||||
if (completion_port_ == nullptr) {
|
||||
FATAL("Completion port creation failed");
|
||||
}
|
||||
shutdown_ = false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -1380,8 +1377,8 @@ void EventHandlerImplementation::InitializeSocketExtensions() {
|
||||
|
||||
EventHandlerImplementation::~EventHandlerImplementation() {
|
||||
// Join the handler thread.
|
||||
DWORD res = WaitForSingleObject(handler_thread_handle_, INFINITE);
|
||||
CloseHandle(handler_thread_handle_);
|
||||
DWORD res = WaitForSingleObject(handler_thread_, INFINITE);
|
||||
CloseHandle(handler_thread_);
|
||||
ASSERT(res == WAIT_OBJECT_0);
|
||||
CloseHandle(completion_port_);
|
||||
}
|
||||
@@ -1425,9 +1422,7 @@ void EventHandlerImplementation::EventHandlerEntry(uword args) {
|
||||
|
||||
{
|
||||
MonitorLocker ml(&handler_impl->monitor_);
|
||||
handler_impl->handler_thread_id_ = Thread::GetCurrentThreadId();
|
||||
handler_impl->handler_thread_handle_ =
|
||||
OpenThread(SYNCHRONIZE, false, handler_impl->handler_thread_id_);
|
||||
handler_impl->handler_thread_ = GetCurrentThreadHandle();
|
||||
ml.Notify();
|
||||
}
|
||||
|
||||
@@ -1499,7 +1494,7 @@ void EventHandlerImplementation::Start(EventHandler* handler) {
|
||||
|
||||
{
|
||||
MonitorLocker ml(&monitor_);
|
||||
while (handler_thread_id_ == Thread::kInvalidThreadId) {
|
||||
while (handler_thread_ == INVALID_HANDLE_VALUE) {
|
||||
ml.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,16 +254,15 @@ class Handle : public ReferenceCounted<Handle>, public DescriptorInfoBase {
|
||||
HANDLE handle_;
|
||||
|
||||
std::unique_ptr<OverlappedBuffer>
|
||||
data_ready_; // Buffer for data ready to be read.
|
||||
OverlappedBuffer* pending_read_; // Buffer for pending read.
|
||||
OverlappedBuffer* pending_write_; // Buffer for pending write
|
||||
data_ready_; // Buffer for data ready to be read.
|
||||
OverlappedBuffer* pending_read_ = nullptr; // Buffer for pending read.
|
||||
OverlappedBuffer* pending_write_ = nullptr; // Buffer for pending write
|
||||
|
||||
DWORD last_error_;
|
||||
DWORD last_error_ = NOERROR;
|
||||
|
||||
ThreadId read_thread_id_;
|
||||
HANDLE read_thread_handle_;
|
||||
bool read_thread_starting_;
|
||||
bool read_thread_finished_;
|
||||
HANDLE read_thread_ = INVALID_HANDLE_VALUE;
|
||||
bool read_thread_starting_ = false;
|
||||
bool read_thread_finished_ = false;
|
||||
|
||||
private:
|
||||
void WaitForReadThreadStarted();
|
||||
@@ -278,7 +277,7 @@ class Handle : public ReferenceCounted<Handle>, public DescriptorInfoBase {
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len);
|
||||
|
||||
int flags_;
|
||||
int flags_ = 0;
|
||||
|
||||
friend class ReferenceCounted<Handle>;
|
||||
DISALLOW_COPY_AND_ASSIGN(Handle);
|
||||
@@ -324,18 +323,12 @@ class StdHandle : public FileHandle {
|
||||
static StdHandle* stdin_;
|
||||
|
||||
explicit StdHandle(HANDLE handle)
|
||||
: FileHandle(handle, kStd, SupportsOverlappedIO::kNo),
|
||||
thread_id_(Thread::kInvalidThreadId),
|
||||
thread_handle_(nullptr),
|
||||
thread_wrote_(0),
|
||||
write_thread_exists_(false),
|
||||
write_thread_running_(false) {}
|
||||
: FileHandle(handle, kStd, SupportsOverlappedIO::kNo) {}
|
||||
|
||||
ThreadId thread_id_;
|
||||
HANDLE thread_handle_;
|
||||
intptr_t thread_wrote_;
|
||||
bool write_thread_exists_;
|
||||
bool write_thread_running_;
|
||||
HANDLE thread_handle_ = INVALID_HANDLE_VALUE;
|
||||
intptr_t thread_wrote_ = 0;
|
||||
bool write_thread_exists_ = false;
|
||||
bool write_thread_running_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StdHandle);
|
||||
};
|
||||
@@ -590,12 +583,11 @@ class EventHandlerImplementation {
|
||||
std::unique_ptr<OverlappedBuffer> buffer);
|
||||
|
||||
Monitor monitor_;
|
||||
ThreadId handler_thread_id_;
|
||||
HANDLE handler_thread_handle_;
|
||||
HANDLE handler_thread_ = INVALID_HANDLE_VALUE;
|
||||
|
||||
TimeoutQueue timeout_queue_; // Time for next timeout.
|
||||
bool shutdown_;
|
||||
HANDLE completion_port_;
|
||||
bool shutdown_ = false;
|
||||
HANDLE completion_port_ = INVALID_HANDLE_VALUE;
|
||||
|
||||
std::atomic<bool> socket_extensions_initialized_{false};
|
||||
LPFN_ACCEPTEX accept_ex_ = nullptr;
|
||||
|
||||
@@ -146,7 +146,7 @@ class FSEventsWatcher {
|
||||
static void Run(uword arg) {
|
||||
FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(arg);
|
||||
// Only checked in debug mode.
|
||||
watcher->threadId_ = Thread::GetCurrentThreadId();
|
||||
watcher->owner_.Acquire();
|
||||
watcher->run_loop_ = CFRunLoopGetCurrent();
|
||||
CFRetain(watcher->run_loop_);
|
||||
|
||||
@@ -165,6 +165,7 @@ class FSEventsWatcher {
|
||||
|
||||
CFRelease(watcher->run_loop_);
|
||||
watcher->monitor_.Enter();
|
||||
watcher->owner_.Release();
|
||||
watcher->run_loop_ = nullptr;
|
||||
watcher->monitor_.Notify();
|
||||
watcher->monitor_.Exit();
|
||||
@@ -188,7 +189,7 @@ class FSEventsWatcher {
|
||||
|
||||
static void StopCallback(CFRunLoopTimerRef timer, void* info) {
|
||||
FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(info);
|
||||
ASSERT(Thread::Compare(watcher->threadId_, Thread::GetCurrentThreadId()));
|
||||
DEBUG_ASSERT(watcher->owner_.IsOwnedByCurrentThread());
|
||||
CFRunLoopStop(watcher->run_loop_);
|
||||
}
|
||||
|
||||
@@ -228,8 +229,7 @@ class FSEventsWatcher {
|
||||
}
|
||||
Node* node = static_cast<Node*>(client);
|
||||
RELEASE_ASSERT(node->watcher() != nullptr);
|
||||
ASSERT(Thread::Compare(node->watcher()->threadId_,
|
||||
Thread::GetCurrentThreadId()));
|
||||
DEBUG_ASSERT(node->watcher()->owner_.IsOwnedByCurrentThread());
|
||||
for (size_t i = 0; i < num_events; i++) {
|
||||
char* path = reinterpret_cast<char**>(event_paths)[i];
|
||||
FSEvent event;
|
||||
@@ -251,7 +251,7 @@ class FSEventsWatcher {
|
||||
|
||||
Monitor monitor_;
|
||||
CFRunLoopRef run_loop_;
|
||||
ThreadId threadId_;
|
||||
platform::ThreadBoundResource owner_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FSEventsWatcher);
|
||||
};
|
||||
|
||||
+1
-68
@@ -6,37 +6,13 @@
|
||||
#define RUNTIME_BIN_THREAD_H_
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
class Thread;
|
||||
class Mutex;
|
||||
class Monitor;
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
// Declare the OS-specific types ahead of defining the generic classes.
|
||||
#if defined(DART_USE_ABSL)
|
||||
#include "bin/thread_absl.h"
|
||||
#elif defined(DART_HOST_OS_FUCHSIA)
|
||||
#include "bin/thread_fuchsia.h"
|
||||
#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
#include "bin/thread_linux.h"
|
||||
#elif defined(DART_HOST_OS_MACOS)
|
||||
#include "bin/thread_macos.h"
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
#include "bin/thread_win.h"
|
||||
#else
|
||||
#error Unknown target os.
|
||||
#endif
|
||||
#include "platform/synchronization.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
static const ThreadId kInvalidThreadId;
|
||||
|
||||
typedef void (*ThreadStartFunction)(uword parameter);
|
||||
|
||||
// Start a thread running the specified function. Returns 0 if the
|
||||
@@ -47,8 +23,6 @@ class Thread {
|
||||
uword parameters);
|
||||
|
||||
static intptr_t GetMaxStackSize();
|
||||
static ThreadId GetCurrentThreadId();
|
||||
static bool Compare(ThreadId a, ThreadId b);
|
||||
|
||||
static void InitOnce();
|
||||
|
||||
@@ -57,47 +31,6 @@ class Thread {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Thread);
|
||||
};
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
MutexData data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Mutex);
|
||||
};
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
enum WaitResult { kNotified, kTimedOut };
|
||||
|
||||
static constexpr int64_t kNoTimeout = 0;
|
||||
|
||||
Monitor();
|
||||
~Monitor();
|
||||
|
||||
void Enter();
|
||||
void Exit();
|
||||
|
||||
// Wait for notification or timeout.
|
||||
WaitResult Wait(int64_t millis);
|
||||
WaitResult WaitMicros(int64_t micros);
|
||||
|
||||
// Notify waiting threads.
|
||||
void Notify();
|
||||
void NotifyAll();
|
||||
|
||||
private:
|
||||
MonitorData data_; // OS-specific data.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Monitor);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -10,37 +10,12 @@
|
||||
#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]; \
|
||||
FATAL("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,
|
||||
@@ -113,86 +88,11 @@ int Thread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
|
||||
intptr_t Thread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId Thread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
// 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_t ThreadId;
|
||||
|
||||
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_
|
||||
@@ -6,7 +6,6 @@
|
||||
#if defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "bin/thread_fuchsia.h"
|
||||
|
||||
#include <errno.h> // NOLINT
|
||||
#include <sys/time.h> // NOLINT
|
||||
@@ -21,44 +20,6 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
#define VALIDATE_PTHREAD_RESULT(result) \
|
||||
if (result != 0) { \
|
||||
const int kBufferSize = 1024; \
|
||||
char error_buf[kBufferSize]; \
|
||||
FATAL("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
|
||||
|
||||
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
int64_t nanos =
|
||||
(micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
ASSERT(result == 0);
|
||||
ts->tv_sec += secs;
|
||||
ts->tv_nsec += nanos;
|
||||
if (ts->tv_nsec >= kNanosecondsPerSecond) {
|
||||
ts->tv_sec += 1;
|
||||
ts->tv_nsec -= kNanosecondsPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -127,157 +88,11 @@ int Thread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
|
||||
intptr_t Thread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId Thread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::Compare(ThreadId a, ThreadId b) {
|
||||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
int result = pthread_mutexattr_init(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
pthread_condattr_t cond_attr;
|
||||
result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
return WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (micros == kNoTimeout) {
|
||||
// Wait forever.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ComputeTimeSpecMicros(&ts, micros);
|
||||
int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2016, 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_FUCHSIA_H_
|
||||
#define RUNTIME_BIN_THREAD_FUCHSIA_H_
|
||||
|
||||
#if !defined(RUNTIME_BIN_THREAD_H_)
|
||||
#error Do not include thread_fuchsia.h directly; use thread.h instead.
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
typedef pthread_t ThreadId;
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_BIN_THREAD_FUCHSIA_H_
|
||||
@@ -7,7 +7,6 @@
|
||||
!defined(DART_USE_ABSL)
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "bin/thread_linux.h"
|
||||
|
||||
#include <errno.h> // NOLINT
|
||||
#include <sys/resource.h> // NOLINT
|
||||
@@ -19,44 +18,6 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
#define VALIDATE_PTHREAD_RESULT(result) \
|
||||
if (result != 0) { \
|
||||
const int kBufferSize = 1024; \
|
||||
char error_buf[kBufferSize]; \
|
||||
FATAL("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
|
||||
|
||||
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
int64_t nanos =
|
||||
(micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
ASSERT(result == 0);
|
||||
ts->tv_sec += secs;
|
||||
ts->tv_nsec += nanos;
|
||||
if (ts->tv_nsec >= kNanosecondsPerSecond) {
|
||||
ts->tv_sec += 1;
|
||||
ts->tv_nsec -= kNanosecondsPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -124,157 +85,11 @@ int Thread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
|
||||
intptr_t Thread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId Thread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::Compare(ThreadId a, ThreadId b) {
|
||||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
int result = pthread_mutexattr_init(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
pthread_condattr_t cond_attr;
|
||||
result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
return WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (micros == kNoTimeout) {
|
||||
// Wait forever.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ComputeTimeSpecMicros(&ts, micros);
|
||||
int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2012, 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_LINUX_H_
|
||||
#define RUNTIME_BIN_THREAD_LINUX_H_
|
||||
|
||||
#if !defined(RUNTIME_BIN_THREAD_H_)
|
||||
#error Do not include thread_linux.h directly; use thread.h instead.
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
typedef pthread_t ThreadId;
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_BIN_THREAD_LINUX_H_
|
||||
@@ -6,7 +6,6 @@
|
||||
#if defined(DART_HOST_OS_MACOS) && !defined(DART_USE_ABSL)
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "bin/thread_macos.h"
|
||||
|
||||
#include <mach/mach_host.h> // NOLINT
|
||||
#include <mach/mach_init.h> // NOLINT
|
||||
@@ -25,31 +24,6 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
#define VALIDATE_PTHREAD_RESULT(result) \
|
||||
if (result != 0) { \
|
||||
const int kBufferSize = 1024; \
|
||||
char error_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
FATAL("pthread error: %d (%s)", result, error_message); \
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define RETURN_ON_PTHREAD_FAILURE(result) \
|
||||
if (result != 0) { \
|
||||
const int kBufferSize = 1024; \
|
||||
char error_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
|
||||
result, error_message); \
|
||||
return result; \
|
||||
}
|
||||
#else
|
||||
#define RETURN_ON_PTHREAD_FAILURE(result) \
|
||||
if (result != 0) { \
|
||||
return result; \
|
||||
}
|
||||
#endif
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -118,156 +92,11 @@ int Thread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(nullptr);
|
||||
|
||||
intptr_t Thread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId Thread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
bool Thread::Compare(ThreadId a, ThreadId b) {
|
||||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if ((result == EBUSY) || (result == EDEADLK)) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), nullptr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
return WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (micros == kNoTimeout) {
|
||||
// Wait forever.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
if (secs > kMaxInt32) {
|
||||
// Avoid truncation of overly large timeout values.
|
||||
secs = kMaxInt32;
|
||||
}
|
||||
int64_t nanos =
|
||||
(micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
|
||||
ts.tv_sec = static_cast<int32_t>(secs);
|
||||
ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
|
||||
int result =
|
||||
pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// TODO(iposva): Do we need to track lock owners?
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2012, 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_MACOS_H_
|
||||
#define RUNTIME_BIN_THREAD_MACOS_H_
|
||||
|
||||
#if !defined(RUNTIME_BIN_THREAD_H_)
|
||||
#error Do not include thread_macos.h directly; use thread.h instead.
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
typedef pthread_t ThreadId;
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_BIN_THREAD_MACOS_H_
|
||||
@@ -6,7 +6,6 @@
|
||||
#if defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "bin/thread_win.h"
|
||||
|
||||
#include <process.h> // NOLINT
|
||||
|
||||
@@ -70,95 +69,11 @@ int Thread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId Thread::kInvalidThreadId = 0;
|
||||
|
||||
intptr_t Thread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId Thread::GetCurrentThreadId() {
|
||||
return ::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
bool Thread::Compare(ThreadId a, ThreadId b) {
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {}
|
||||
|
||||
void Mutex::Lock() {
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
InitializeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {}
|
||||
|
||||
void Monitor::Enter() {
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (millis == kNoTimeout) {
|
||||
SleepConditionVariableSRW(&data_.cond_, &data_.lock_, INFINITE,
|
||||
/*Flags=*/0);
|
||||
} else {
|
||||
// Wait for the given period of time for a Notify or a NotifyAll
|
||||
// event.
|
||||
if (!SleepConditionVariableSRW(&data_.cond_, &data_.lock_, millis,
|
||||
/*Flags=*/0)) {
|
||||
ASSERT(GetLastError() == ERROR_TIMEOUT);
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
||||
// TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows.
|
||||
int64_t millis = micros / kMicrosecondsPerMillisecond;
|
||||
if ((millis * kMicrosecondsPerMillisecond) < micros) {
|
||||
// We've been asked to sleep for a fraction of a millisecond,
|
||||
// this isn't supported on Windows. Bumps milliseconds up by one
|
||||
// so that we never return too early. We likely return late though.
|
||||
millis += 1;
|
||||
}
|
||||
return Wait(millis);
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
WakeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
WakeAllConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2012, 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_WIN_H_
|
||||
#define RUNTIME_BIN_THREAD_WIN_H_
|
||||
|
||||
#if !defined(RUNTIME_BIN_THREAD_H_)
|
||||
#error Do not include thread_win.h directly; use thread.h instead.
|
||||
#endif
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
typedef DWORD ThreadId;
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
SRWLOCK lock_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
SRWLOCK lock_;
|
||||
CONDITION_VARIABLE cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_BIN_THREAD_WIN_H_
|
||||
@@ -21,6 +21,10 @@ platform_sources = [
|
||||
"memory_sanitizer.h",
|
||||
"safe_stack.h",
|
||||
"signal_blocker.h",
|
||||
"synchronization.h",
|
||||
"synchronization_absl.cc",
|
||||
"synchronization_posix.cc",
|
||||
"synchronization_win.cc",
|
||||
"syslog.h",
|
||||
"syslog_android.cc",
|
||||
"syslog_fuchsia.cc",
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2024, 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_PLATFORM_SYNCHRONIZATION_H_
|
||||
#define RUNTIME_PLATFORM_SYNCHRONIZATION_H_
|
||||
|
||||
#include "platform/allocation.h"
|
||||
#include "platform/threads.h"
|
||||
|
||||
#if defined(DART_USE_ABSL)
|
||||
#include "third_party/absl/synchronization/mutex.h"
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if defined(DART_USE_ABSL)
|
||||
using MutexImpl = absl::Mutex;
|
||||
using ConditionVariableImpl = absl::CondVar;
|
||||
#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
using MutexImpl = pthread_mutex_t;
|
||||
using ConditionVariableImpl = pthread_cond_t;
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
using MutexImpl = SRWLOCK;
|
||||
using ConditionVariableImpl = CONDITION_VARIABLE;
|
||||
#else
|
||||
#error Unknown target os.
|
||||
#endif
|
||||
|
||||
// Mark when we are running in a signal handler (Linux, Android) or with a
|
||||
// suspended thread (Windows, Mac, Fuchia). During this time, we cannot take
|
||||
// locks.
|
||||
class DisallowMutexLockingScope : public ValueObject {
|
||||
#if defined(DEBUG)
|
||||
public:
|
||||
DisallowMutexLockingScope() {
|
||||
ASSERT(!is_active_);
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
~DisallowMutexLockingScope() { is_active_ = false; }
|
||||
|
||||
static bool is_active() { return is_active_; }
|
||||
|
||||
private:
|
||||
static inline thread_local bool is_active_ = false;
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
return owner_.IsOwnedByCurrentThread();
|
||||
}
|
||||
|
||||
void Lock();
|
||||
bool TryLock(); // Returns false if lock is busy and locking failed.
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
MutexImpl mutex_;
|
||||
platform::ThreadBoundResource owner_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
DISALLOW_COPY_AND_ASSIGN(Mutex);
|
||||
};
|
||||
|
||||
class ConditionVariable {
|
||||
public:
|
||||
enum WaitResult { kNotified, kTimedOut };
|
||||
static constexpr int64_t kNoTimeout = 0;
|
||||
|
||||
ConditionVariable();
|
||||
~ConditionVariable();
|
||||
|
||||
WaitResult Wait(Mutex* mutex, int64_t timeout_millis = kNoTimeout);
|
||||
|
||||
WaitResult WaitMicros(Mutex* mutex, int64_t timeout_micros = kNoTimeout);
|
||||
|
||||
void Notify();
|
||||
void NotifyAll();
|
||||
|
||||
private:
|
||||
ConditionVariableImpl cv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
|
||||
};
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
using WaitResult = ConditionVariable::WaitResult;
|
||||
static constexpr WaitResult kNotified = ConditionVariable::kNotified;
|
||||
static constexpr WaitResult kTimedOut = ConditionVariable::kTimedOut;
|
||||
|
||||
static constexpr int64_t kNoTimeout = ConditionVariable::kNoTimeout;
|
||||
|
||||
Monitor() {}
|
||||
~Monitor() {}
|
||||
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
return mutex_.IsOwnedByCurrentThread();
|
||||
}
|
||||
|
||||
bool TryEnter() { return mutex_.TryLock(); }
|
||||
void Enter() { return mutex_.Lock(); }
|
||||
void Exit() { return mutex_.Unlock(); }
|
||||
|
||||
// Wait for notification or timeout.
|
||||
WaitResult Wait(int64_t timeout_millis) {
|
||||
return cv_.Wait(&mutex_, timeout_millis);
|
||||
}
|
||||
|
||||
WaitResult WaitMicros(int64_t timeout_micros) {
|
||||
return cv_.WaitMicros(&mutex_, timeout_micros);
|
||||
}
|
||||
|
||||
// Notify waiting threads.
|
||||
void Notify() { cv_.Notify(); }
|
||||
|
||||
void NotifyAll() { cv_.NotifyAll(); }
|
||||
|
||||
private:
|
||||
Mutex mutex_; // OS-specific data.
|
||||
ConditionVariable cv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Monitor);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_PLATFORM_SYNCHRONIZATION_H_
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2024, 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 "platform/synchronization.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
Mutex::Mutex() {}
|
||||
|
||||
Mutex::~Mutex() {}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
void Mutex::Lock() {
|
||||
mutex_.Lock();
|
||||
owner_.Acquire();
|
||||
}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
bool Mutex::TryLock() {
|
||||
if (!mutex_.TryLock()) {
|
||||
return false;
|
||||
}
|
||||
owner_.Acquire();
|
||||
return true;
|
||||
}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
void Mutex::Unlock() {
|
||||
owner_.Release();
|
||||
mutex_.Unlock();
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
ConditionVariable::WaitResult ConditionVariable::Wait(Mutex* mutex,
|
||||
int64_t timeout_millis) {
|
||||
static_assert(kNoTimeout * kMicrosecondsPerMillisecond == kNoTimeout);
|
||||
return WaitMicros(mutex, timeout_millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
ConditionVariable::WaitResult ConditionVariable::WaitMicros(
|
||||
Mutex* mutex,
|
||||
int64_t timeout_micros) {
|
||||
mutex->owner_.Release();
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (timeout_micros == kNoTimeout) {
|
||||
// Wait forever.
|
||||
cv_.Wait(&mutex->mutex_);
|
||||
} else {
|
||||
if (cv_.WaitWithTimeout(&mutex->mutex_,
|
||||
absl::Microseconds(timeout_micros))) {
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
mutex->owner_.Acquire();
|
||||
return retval;
|
||||
}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
void ConditionVariable::Notify() {
|
||||
cv_.Signal();
|
||||
}
|
||||
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
void ConditionVariable::NotifyAll() {
|
||||
cv_.SignalAll();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_ABSL)
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2024, 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) && \
|
||||
(defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID))
|
||||
|
||||
#include "platform/synchronization.h"
|
||||
|
||||
#include <errno.h> // NOLINT
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h> // NOLINT
|
||||
|
||||
#include "platform/utils.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(&mutex_, &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(&mutex_);
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!DisallowMutexLockingScope::is_active());
|
||||
|
||||
int result = pthread_mutex_lock(&mutex_);
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
owner_.Acquire();
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!DisallowMutexLockingScope::is_active());
|
||||
|
||||
int result = pthread_mutex_trylock(&mutex_);
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
owner_.Acquire();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
owner_.Release();
|
||||
int result = pthread_mutex_unlock(&mutex_);
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
pthread_condattr_t cond_attr;
|
||||
int result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if !defined(DART_HOST_OS_MACOS)
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif
|
||||
|
||||
result = pthread_cond_init(&cv_, &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
int result = pthread_cond_destroy(&cv_);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::WaitResult ConditionVariable::Wait(Mutex* mutex,
|
||||
int64_t millis) {
|
||||
static_assert(kNoTimeout * kMicrosecondsPerMillisecond == kNoTimeout);
|
||||
return WaitMicros(mutex, millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
static int TimedWait(pthread_cond_t* cv,
|
||||
pthread_mutex_t* mutex,
|
||||
int64_t timeout_micros) {
|
||||
const int64_t secs = timeout_micros / kMicrosecondsPerSecond;
|
||||
const int64_t nanos = (timeout_micros - (secs * kMicrosecondsPerSecond)) *
|
||||
kNanosecondsPerMicrosecond;
|
||||
|
||||
struct timespec ts;
|
||||
#if defined(DART_HOST_OS_MACOS)
|
||||
// On Mac OS X we can use non-portable pthread_cond_timedwait_relative_np
|
||||
// instead of computing timespec for the wakeup moment.
|
||||
ts.tv_sec = static_cast<int32_t>(
|
||||
Utils::Minimum(static_cast<int64_t>(kMaxInt32), secs));
|
||||
ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
|
||||
return pthread_cond_timedwait_relative_np(cv, mutex, &ts);
|
||||
#else
|
||||
// Otherwise we need to compute absolute timespec.
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ts.tv_sec += secs;
|
||||
ts.tv_nsec += nanos;
|
||||
if (ts.tv_nsec >= kNanosecondsPerSecond) {
|
||||
ts.tv_sec += 1;
|
||||
ts.tv_nsec -= kNanosecondsPerSecond;
|
||||
}
|
||||
|
||||
return pthread_cond_timedwait(cv, mutex, &ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
ConditionVariable::WaitResult ConditionVariable::WaitMicros(
|
||||
Mutex* mutex,
|
||||
int64_t timeout_micros) {
|
||||
mutex->owner_.Release();
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (timeout_micros == kNoTimeout) {
|
||||
// Wait forever.
|
||||
int result = pthread_cond_wait(&cv_, &mutex->mutex_);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
int result = TimedWait(&cv_, &mutex->mutex_, timeout_micros);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
mutex->owner_.Acquire();
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
int result = pthread_cond_signal(&cv_);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void ConditionVariable::NotifyAll() {
|
||||
int result = pthread_cond_broadcast(&cv_);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_USE_ABSL) && (defined(DART_HOST_OS_LINUX) || \
|
||||
// defined(DART_HOST_OS_FUCHSIA) || \
|
||||
// defined(DART_HOST_OS_MACOS) || \
|
||||
// defined(DART_HOST_OS_ANDROID))
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2024, 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_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
|
||||
|
||||
#include "platform/synchronization.h"
|
||||
|
||||
#include <process.h> // NOLINT
|
||||
|
||||
#include "platform/address_sanitizer.h"
|
||||
#include "platform/assert.h"
|
||||
#include "platform/safe_stack.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
Mutex::Mutex() {
|
||||
InitializeSRWLock(&mutex_);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!DisallowMutexLockingScope::is_active());
|
||||
|
||||
AcquireSRWLockExclusive(&mutex_);
|
||||
owner_.Acquire();
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!DisallowMutexLockingScope::is_active());
|
||||
|
||||
if (TryAcquireSRWLockExclusive(&mutex_) != 0) {
|
||||
owner_.Acquire();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
owner_.Release();
|
||||
ReleaseSRWLockExclusive(&mutex_);
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
InitializeConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {}
|
||||
|
||||
ConditionVariable::WaitResult ConditionVariable::Wait(Mutex* mutex,
|
||||
int64_t timeout_millis) {
|
||||
mutex->owner_.Release();
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
if (timeout_millis == kNoTimeout) {
|
||||
SleepConditionVariableSRW(&cv_, &mutex->mutex_, INFINITE, 0);
|
||||
} else {
|
||||
// Wait for the given period of time for a Notify or a NotifyAll
|
||||
// event.
|
||||
if (!SleepConditionVariableSRW(&cv_, &mutex->mutex_, timeout_millis, 0)) {
|
||||
ASSERT(GetLastError() == ERROR_TIMEOUT);
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
mutex->owner_.Acquire();
|
||||
return retval;
|
||||
}
|
||||
|
||||
ConditionVariable::WaitResult ConditionVariable::WaitMicros(Mutex* mutex,
|
||||
int64_t micros) {
|
||||
// TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows.
|
||||
int64_t millis = micros / kMicrosecondsPerMillisecond;
|
||||
if ((millis * kMicrosecondsPerMillisecond) < micros) {
|
||||
// We've been asked to sleep for a fraction of a millisecond,
|
||||
// this isn't supported on Windows. Bumps milliseconds up by one
|
||||
// so that we never return too early. We likely return late though.
|
||||
millis += 1;
|
||||
}
|
||||
return Wait(mutex, millis);
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
WakeConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
void ConditionVariable::NotifyAll() {
|
||||
WakeAllConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2024, 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_PLATFORM_THREADS_H_
|
||||
#define RUNTIME_PLATFORM_THREADS_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
namespace platform {
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
typedef pthread_t ThreadId;
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
typedef DWORD ThreadId;
|
||||
#else
|
||||
#error Unknown target os.
|
||||
#endif
|
||||
|
||||
static constexpr ThreadId kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
|
||||
inline ThreadId GetCurrentThreadId() {
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
return pthread_self();
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
return ::GetCurrentThreadId();
|
||||
#else
|
||||
#error Unknown target os.
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool AreSameThreads(ThreadId a, ThreadId b) {
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
return pthread_equal(a, b) != 0;
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
return a == b;
|
||||
#else
|
||||
#error Unknown target os.
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
class ThreadBoundResource {
|
||||
public:
|
||||
~ThreadBoundResource() { ASSERT(owner_ == kUnowned); }
|
||||
|
||||
void Acquire() {
|
||||
ASSERT(owner_ == kUnowned);
|
||||
owner_ = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
void Release() {
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = kUnowned;
|
||||
}
|
||||
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
return AreSameThreads(owner_, GetCurrentThreadId());
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr ThreadId kUnowned = kInvalidThreadId;
|
||||
ThreadId owner_ = kUnowned;
|
||||
};
|
||||
#else
|
||||
class ThreadBoundResource {
|
||||
public:
|
||||
void Acquire() {}
|
||||
|
||||
void Release() {}
|
||||
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \
|
||||
defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID)
|
||||
|
||||
#define VALIDATE_PTHREAD_RESULT(result) \
|
||||
if (result != 0) { \
|
||||
const int kBufferSize = 1024; \
|
||||
char error_buf[kBufferSize]; \
|
||||
FATAL("pthread error: %d (%s)", result, \
|
||||
Utils::StrError(result, error_buf, kBufferSize)); \
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_PLATFORM_THREADS_H_
|
||||
@@ -30,7 +30,7 @@ static intptr_t page_cache_size = 0;
|
||||
|
||||
void Page::Init() {
|
||||
ASSERT(page_cache_mutex == nullptr);
|
||||
page_cache_mutex = new Mutex(NOT_IN_PRODUCT("page_cache_mutex"));
|
||||
page_cache_mutex = new Mutex();
|
||||
}
|
||||
|
||||
void Page::ClearCache() {
|
||||
|
||||
+13
-23
@@ -357,28 +357,18 @@ IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
background_compiler_(new BackgroundCompiler(this)),
|
||||
#endif
|
||||
symbols_mutex_(NOT_IN_PRODUCT("IsolateGroup::symbols_mutex_")),
|
||||
type_canonicalization_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::type_canonicalization_mutex_")),
|
||||
type_arguments_canonicalization_mutex_(NOT_IN_PRODUCT(
|
||||
"IsolateGroup::type_arguments_canonicalization_mutex_")),
|
||||
subtype_test_cache_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::subtype_test_cache_mutex_")),
|
||||
megamorphic_table_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::megamorphic_table_mutex_")),
|
||||
type_feedback_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::type_feedback_mutex_")),
|
||||
patchable_call_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::patchable_call_mutex_")),
|
||||
constant_canonicalization_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::constant_canonicalization_mutex_")),
|
||||
kernel_data_lib_cache_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::kernel_data_lib_cache_mutex_")),
|
||||
kernel_data_class_cache_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::kernel_data_class_cache_mutex_")),
|
||||
kernel_constants_mutex_(
|
||||
NOT_IN_PRODUCT("IsolateGroup::kernel_constants_mutex_")),
|
||||
field_list_mutex_(NOT_IN_PRODUCT("Isolate::field_list_mutex_")),
|
||||
symbols_mutex_(),
|
||||
type_canonicalization_mutex_(),
|
||||
type_arguments_canonicalization_mutex_(),
|
||||
subtype_test_cache_mutex_(),
|
||||
megamorphic_table_mutex_(),
|
||||
type_feedback_mutex_(),
|
||||
patchable_call_mutex_(),
|
||||
constant_canonicalization_mutex_(),
|
||||
kernel_data_lib_cache_mutex_(),
|
||||
kernel_data_class_cache_mutex_(),
|
||||
kernel_constants_mutex_(),
|
||||
field_list_mutex_(),
|
||||
boxed_field_list_(GrowableObjectArray::null()),
|
||||
program_lock_(new SafepointRwLock()),
|
||||
active_mutators_monitor_(new Monitor()),
|
||||
@@ -1758,7 +1748,7 @@ Isolate::Isolate(IsolateGroup* isolate_group,
|
||||
on_shutdown_callback_(Isolate::ShutdownCallback()),
|
||||
on_cleanup_callback_(Isolate::CleanupCallback()),
|
||||
random_(),
|
||||
mutex_(NOT_IN_PRODUCT("Isolate::mutex_")),
|
||||
mutex_(),
|
||||
tag_table_(GrowableObjectArray::null()),
|
||||
sticky_error_(Error::null()),
|
||||
spawn_count_monitor_(),
|
||||
|
||||
+14
-130
@@ -8,6 +8,8 @@
|
||||
#include "platform/atomic.h"
|
||||
#include "platform/globals.h"
|
||||
#include "platform/safe_stack.h"
|
||||
#include "platform/synchronization.h"
|
||||
#include "platform/threads.h"
|
||||
#include "platform/utils.h"
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/globals.h"
|
||||
@@ -37,53 +39,6 @@ class Mutex;
|
||||
class ThreadState;
|
||||
class TimelineEventBlock;
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
explicit Mutex(NOT_IN_PRODUCT(const char* name = "anonymous mutex"));
|
||||
~Mutex();
|
||||
|
||||
ThreadId InvalidateOwner();
|
||||
void SetCurrentThreadAsOwner();
|
||||
bool IsOwnedByCurrentThread() const;
|
||||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
bool TryLock(); // Returns false if lock is busy and locking failed.
|
||||
|
||||
MutexData data_;
|
||||
NOT_IN_PRODUCT(const char* name_);
|
||||
#if defined(DEBUG)
|
||||
ThreadId owner_;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
friend class ConditionVariable;
|
||||
friend class MallocLocker;
|
||||
friend class MutexLocker;
|
||||
friend class SafepointMutexLocker;
|
||||
friend class OSThreadIterator;
|
||||
friend class TimelineEventRecorder;
|
||||
friend class TimelineEventRingRecorder;
|
||||
friend class PageSpace;
|
||||
friend void Dart_TestMutex();
|
||||
DISALLOW_COPY_AND_ASSIGN(Mutex);
|
||||
};
|
||||
|
||||
class ConditionVariable {
|
||||
public:
|
||||
ConditionVariable();
|
||||
~ConditionVariable();
|
||||
|
||||
void Wait(Mutex* mutex);
|
||||
void Notify();
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
ConditionVariableData data_;
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
|
||||
};
|
||||
|
||||
class BaseThread {
|
||||
public:
|
||||
bool is_os_thread() const { return is_os_thread_; }
|
||||
@@ -100,6 +55,8 @@ class BaseThread {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseThread);
|
||||
};
|
||||
|
||||
using ThreadId = platform::ThreadId;
|
||||
|
||||
// Low-level operations on OS platform threads.
|
||||
class OSThread : public BaseThread {
|
||||
public:
|
||||
@@ -240,13 +197,11 @@ class OSThread : public BaseThread {
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
return ThreadInlineImpl::GetThreadLocal(key);
|
||||
}
|
||||
static ThreadId GetCurrentThreadId();
|
||||
static void SetThreadLocal(ThreadLocalKey key, uword value);
|
||||
static intptr_t GetMaxStackSize();
|
||||
static void Join(ThreadJoinId id);
|
||||
static intptr_t ThreadIdToIntPtr(ThreadId id);
|
||||
static ThreadId ThreadIdFromIntPtr(intptr_t id);
|
||||
static bool Compare(ThreadId a, ThreadId b);
|
||||
|
||||
// This function can be called only once per OSThread, and should only be
|
||||
// called when the returned id will eventually be passed to OSThread::Join().
|
||||
@@ -262,10 +217,17 @@ class OSThread : public BaseThread {
|
||||
|
||||
static constexpr intptr_t kStackSizeBufferMax = (16 * KB * kWordSize);
|
||||
static constexpr float kStackSizeBufferFraction = 0.5;
|
||||
|
||||
static const ThreadId kInvalidThreadId;
|
||||
static const ThreadJoinId kInvalidThreadJoinId;
|
||||
|
||||
static constexpr ThreadId kInvalidThreadId = platform::kInvalidThreadId;
|
||||
static ThreadId GetCurrentThreadId() {
|
||||
return platform::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
static bool Compare(ThreadId a, ThreadId b) {
|
||||
return platform::AreSameThreads(a, b);
|
||||
}
|
||||
|
||||
private:
|
||||
// The constructor is private as CreateOSThread should be used
|
||||
// to create a new OSThread structure.
|
||||
@@ -372,78 +334,6 @@ class OSThreadIterator : public ValueObject {
|
||||
OSThread* next_;
|
||||
};
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
enum WaitResult { kNotified, kTimedOut };
|
||||
|
||||
static constexpr int64_t kNoTimeout = 0;
|
||||
|
||||
Monitor();
|
||||
~Monitor();
|
||||
|
||||
#if defined(DEBUG)
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
return owner_ == OSThread::GetCurrentThreadId();
|
||||
}
|
||||
#else
|
||||
bool IsOwnedByCurrentThread() const {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool TryEnter(); // Returns false if lock is busy and locking failed.
|
||||
void Enter();
|
||||
void Exit();
|
||||
|
||||
// Wait for notification or timeout.
|
||||
WaitResult Wait(int64_t millis);
|
||||
WaitResult WaitMicros(int64_t micros);
|
||||
|
||||
// Notify waiting threads.
|
||||
void Notify();
|
||||
void NotifyAll();
|
||||
|
||||
MonitorData data_; // OS-specific data.
|
||||
#if defined(DEBUG)
|
||||
ThreadId owner_;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
friend class MonitorLocker;
|
||||
friend class SafepointMonitorLocker;
|
||||
friend class SafepointRwLock;
|
||||
friend void Dart_TestMonitor();
|
||||
DISALLOW_COPY_AND_ASSIGN(Monitor);
|
||||
};
|
||||
|
||||
inline bool Mutex::IsOwnedByCurrentThread() const {
|
||||
#if defined(DEBUG)
|
||||
return owner_ == OSThread::GetCurrentThreadId();
|
||||
#else
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline ThreadId Mutex::InvalidateOwner() {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = owner_;
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
return saved_owner;
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void Mutex::SetCurrentThreadAsOwner() {
|
||||
#if defined(DEBUG)
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Mark when we are running in a signal handler (Linux, Android) or with a
|
||||
// suspended thread (Windows, Mac, Fuchia). During this time, we cannot take
|
||||
// locks, access Thread/Isolate::Current(), or use malloc.
|
||||
@@ -451,9 +341,6 @@ class ThreadInterruptScope : public ValueObject {
|
||||
#if defined(DEBUG)
|
||||
public:
|
||||
ThreadInterruptScope() {
|
||||
ASSERT(!in_thread_interrupt_scope_); // We don't use nested signals.
|
||||
in_thread_interrupt_scope_ = true;
|
||||
|
||||
// Poison attempts to use Thread::Current. This is much cheaper than adding
|
||||
// an assert in Thread::Current itself.
|
||||
saved_current_vm_thread_ = OSThread::CurrentVMThread();
|
||||
@@ -462,14 +349,11 @@ class ThreadInterruptScope : public ValueObject {
|
||||
|
||||
~ThreadInterruptScope() {
|
||||
OSThread::SetCurrentVMThread(saved_current_vm_thread_);
|
||||
in_thread_interrupt_scope_ = false;
|
||||
}
|
||||
|
||||
static bool in_thread_interrupt_scope() { return in_thread_interrupt_scope_; }
|
||||
|
||||
private:
|
||||
DisallowMutexLockingScope disallow_locks_;
|
||||
ThreadState* saved_current_vm_thread_;
|
||||
static inline thread_local bool in_thread_interrupt_scope_ = false;
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
|
||||
@@ -30,48 +30,6 @@ DEFINE_FLAG(int,
|
||||
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]; \
|
||||
FATAL("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]; \
|
||||
FATAL("[%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,
|
||||
@@ -187,7 +145,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
@@ -216,10 +173,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
#if defined(DART_HOST_OS_ANDROID)
|
||||
@@ -280,10 +233,6 @@ ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OSThread::Compare(ThreadId a, ThreadId b) {
|
||||
return pthread_equal(a, b) != 0;
|
||||
}
|
||||
|
||||
bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
|
||||
#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
|
||||
pthread_attr_t attr;
|
||||
@@ -325,171 +274,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
}
|
||||
#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();
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
data_.cond()->Wait(mutex->data_.mutex());
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
data_.cond()->Signal();
|
||||
}
|
||||
|
||||
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());
|
||||
data_.cond()->SignalAll();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_ABSL)
|
||||
|
||||
@@ -13,12 +13,10 @@
|
||||
|
||||
#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 =
|
||||
@@ -40,54 +38,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() : mutex_() {}
|
||||
~MutexData() {}
|
||||
|
||||
absl::Mutex* mutex() { return &mutex_; }
|
||||
|
||||
absl::Mutex mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() : cond_() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
absl::CondVar* cond() { return &cond_; }
|
||||
|
||||
absl::CondVar cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
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_
|
||||
|
||||
@@ -29,62 +29,6 @@ DEFINE_FLAG(int,
|
||||
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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
FATAL("pthread error: %d (%s)", result, error_message); \
|
||||
}
|
||||
|
||||
#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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
FATAL("[%s] pthread error: %d (%s)", name_, result, error_message); \
|
||||
}
|
||||
#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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
|
||||
result, error_message); \
|
||||
return result; \
|
||||
}
|
||||
#else
|
||||
#define RETURN_ON_PTHREAD_FAILURE(result) \
|
||||
if (result != 0) return result;
|
||||
#endif
|
||||
|
||||
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
|
||||
struct timeval tv;
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
int64_t remaining_micros = (micros - (secs * kMicrosecondsPerSecond));
|
||||
int result = gettimeofday(&tv, nullptr);
|
||||
ASSERT(result == 0);
|
||||
ts->tv_sec = tv.tv_sec + secs;
|
||||
ts->tv_nsec = (tv.tv_usec + remaining_micros) * kNanosecondsPerMicrosecond;
|
||||
if (ts->tv_nsec >= kNanosecondsPerSecond) {
|
||||
ts->tv_sec += 1;
|
||||
ts->tv_nsec -= kNanosecondsPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -179,7 +123,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
@@ -208,10 +151,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return gettid();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
return GetCurrentThreadId();
|
||||
@@ -252,10 +191,6 @@ ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
|
||||
return static_cast<ThreadId>(id);
|
||||
}
|
||||
|
||||
bool OSThread::Compare(ThreadId a, ThreadId b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
|
||||
pthread_attr_t attr;
|
||||
if (pthread_getattr_np(pthread_self(), &attr) != 0) {
|
||||
@@ -290,260 +225,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
}
|
||||
#endif
|
||||
|
||||
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
||||
#if !defined(PRODUCT)
|
||||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
pthread_condattr_t cond_attr;
|
||||
int result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
int result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
int result = pthread_mutexattr_init(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
pthread_condattr_t cond_attr;
|
||||
result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#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)
|
||||
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
return WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
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.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ComputeTimeSpecMicros(&ts, micros);
|
||||
int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pid_t ThreadId;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
@@ -39,54 +38,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_ANDROID_H_
|
||||
|
||||
@@ -22,49 +22,6 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
#define VALIDATE_PTHREAD_RESULT(result) \
|
||||
if (result != 0) { \
|
||||
FATAL("pthread error: %d", result); \
|
||||
}
|
||||
|
||||
#if defined(PRODUCT)
|
||||
#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
|
||||
#else
|
||||
#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
|
||||
if (result != 0) { \
|
||||
FATAL("[%s] pthread error: %d", name_, result); \
|
||||
}
|
||||
#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) { \
|
||||
fprintf(stderr, "%s:%d: pthread error: %d\n", __FILE__, __LINE__, result); \
|
||||
return result; \
|
||||
}
|
||||
#else
|
||||
#define RETURN_ON_PTHREAD_FAILURE(result) \
|
||||
if (result != 0) return result;
|
||||
#endif
|
||||
|
||||
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
|
||||
// time in nanoseconds.
|
||||
zx_time_t now = zx_clock_get_monotonic();
|
||||
zx_time_t target = now + (micros * kNanosecondsPerMicrosecond);
|
||||
int64_t secs = target / kNanosecondsPerSecond;
|
||||
int64_t nanos = target - (secs * kNanosecondsPerSecond);
|
||||
|
||||
ts->tv_sec = secs;
|
||||
ts->tv_nsec = nanos;
|
||||
}
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -136,7 +93,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = ZX_HANDLE_INVALID;
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
@@ -165,10 +121,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return thrd_get_zx_handle(thrd_current());
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
return pthread_self();
|
||||
@@ -209,10 +161,6 @@ 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;
|
||||
if (pthread_getattr_np(pthread_self(), &attr) != 0) {
|
||||
@@ -283,264 +231,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
#undef STRINGIFY
|
||||
#endif
|
||||
|
||||
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
||||
#if !defined(PRODUCT)
|
||||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
pthread_condattr_t cond_attr;
|
||||
int result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
int result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
int result = pthread_mutexattr_init(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
pthread_condattr_t cond_attr;
|
||||
result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#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)
|
||||
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
return retval;
|
||||
}
|
||||
|
||||
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.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ComputeTimeSpecMicros(&ts, micros);
|
||||
int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef zx_handle_t ThreadId;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
@@ -40,54 +39,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_FUCHSIA_H_
|
||||
|
||||
@@ -28,63 +28,6 @@ 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]; \
|
||||
FATAL("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]; \
|
||||
FATAL("[%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
|
||||
|
||||
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
int64_t nanos =
|
||||
(micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
ASSERT(result == 0);
|
||||
ts->tv_sec += secs;
|
||||
ts->tv_nsec += nanos;
|
||||
if (ts->tv_nsec >= kNanosecondsPerSecond) {
|
||||
ts->tv_sec += 1;
|
||||
ts->tv_nsec -= kNanosecondsPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -179,7 +122,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
@@ -208,10 +150,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
return syscall(__NR_gettid);
|
||||
@@ -252,10 +190,6 @@ 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.
|
||||
@@ -291,264 +225,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
}
|
||||
#endif
|
||||
|
||||
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
||||
#if !defined(PRODUCT)
|
||||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
pthread_condattr_t cond_attr;
|
||||
int result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
int result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
int result = pthread_mutexattr_init(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&mutex_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
pthread_condattr_t cond_attr;
|
||||
result = pthread_condattr_init(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), &cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_condattr_destroy(&cond_attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#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)
|
||||
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
return retval;
|
||||
}
|
||||
|
||||
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.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
ComputeTimeSpecMicros(&ts, micros);
|
||||
int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadId;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
@@ -39,54 +38,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_LINUX_H_
|
||||
|
||||
@@ -34,48 +34,6 @@ DEFINE_FLAG(int,
|
||||
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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
FATAL("pthread error: %d (%s)", result, error_message); \
|
||||
}
|
||||
|
||||
#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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
FATAL("[%s] pthread error: %d (%s)", name_, result, error_message); \
|
||||
}
|
||||
#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_message[kBufferSize]; \
|
||||
Utils::StrError(result, error_message, kBufferSize); \
|
||||
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
|
||||
result, error_message); \
|
||||
return result; \
|
||||
}
|
||||
#else
|
||||
#define RETURN_ON_PTHREAD_FAILURE(result) \
|
||||
if (result != 0) return result;
|
||||
#endif
|
||||
|
||||
class ThreadStartData {
|
||||
public:
|
||||
ThreadStartData(const char* name,
|
||||
@@ -161,7 +119,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(nullptr);
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(nullptr);
|
||||
|
||||
@@ -190,10 +147,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
return ThreadIdFromIntPtr(pthread_mach_thread_np(pthread_self()));
|
||||
@@ -234,10 +187,6 @@ ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
|
||||
return reinterpret_cast<ThreadId>(id);
|
||||
}
|
||||
|
||||
bool OSThread::Compare(ThreadId a, ThreadId b) {
|
||||
return pthread_equal(a, b) != 0;
|
||||
}
|
||||
|
||||
bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
|
||||
*upper = reinterpret_cast<uword>(pthread_get_stackaddr_np(pthread_self()));
|
||||
*lower = *upper - pthread_get_stacksize_np(pthread_self());
|
||||
@@ -259,252 +208,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
}
|
||||
#endif
|
||||
|
||||
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
||||
#if !defined(PRODUCT)
|
||||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
// Verify that creating a pthread_mutex succeeded.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
// Verify that the pthread_mutex was destroyed.
|
||||
VALIDATE_PTHREAD_RESULT_NAMED(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
// Specifically check for dead lock to help debugging.
|
||||
ASSERT(result != EDEADLK);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if ((result == EBUSY) || (result == EDEADLK)) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
// Specifically check for wrong thread unlocking to aid debugging.
|
||||
ASSERT(result != EPERM);
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
int result = pthread_cond_init(data_.cond(), nullptr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
int result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
result = pthread_mutex_init(data_.mutex(), &attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_mutexattr_destroy(&attr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_init(data_.cond(), nullptr);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#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)
|
||||
|
||||
int result = pthread_mutex_destroy(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
result = pthread_cond_destroy(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_trylock(data_.mutex());
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if ((result == EBUSY) || (result == EDEADLK)) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
int result = pthread_mutex_lock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
int result = pthread_mutex_unlock(data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
return WaitMicros(millis * kMicrosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
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.
|
||||
int result = pthread_cond_wait(data_.cond(), data_.mutex());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
int64_t secs = micros / kMicrosecondsPerSecond;
|
||||
if (secs > kMaxInt32) {
|
||||
// Avoid truncation of overly large timeout values.
|
||||
secs = kMaxInt32;
|
||||
}
|
||||
int64_t nanos =
|
||||
(micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
|
||||
ts.tv_sec = static_cast<int32_t>(secs);
|
||||
ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
|
||||
int result =
|
||||
pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts);
|
||||
ASSERT((result == 0) || (result == ETIMEDOUT));
|
||||
if (result == ETIMEDOUT) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_signal(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
int result = pthread_cond_broadcast(data_.cond());
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_MACOS)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadId;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
@@ -40,54 +39,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
pthread_mutex_t* mutex() { return &mutex_; }
|
||||
pthread_cond_t* cond() { return &cond_; }
|
||||
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_MACOS_H_
|
||||
|
||||
@@ -99,7 +99,6 @@ int OSThread::Start(const char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ThreadId OSThread::kInvalidThreadId = 0;
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId = nullptr;
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
@@ -125,10 +124,6 @@ intptr_t OSThread::GetMaxStackSize() {
|
||||
return kStackSize;
|
||||
}
|
||||
|
||||
ThreadId OSThread::GetCurrentThreadId() {
|
||||
return ::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
ThreadId OSThread::GetCurrentThreadTraceId() {
|
||||
return ::GetCurrentThreadId();
|
||||
@@ -173,10 +168,6 @@ ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
|
||||
return static_cast<ThreadId>(id);
|
||||
}
|
||||
|
||||
bool OSThread::Compare(ThreadId a, ThreadId b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
|
||||
// On Windows stack limits for the current thread are available in
|
||||
// the thread information block (TIB).
|
||||
@@ -227,186 +218,6 @@ void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
}
|
||||
}
|
||||
|
||||
Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
||||
#if !defined(PRODUCT)
|
||||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
ConditionVariable::ConditionVariable() {
|
||||
InitializeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {}
|
||||
|
||||
void ConditionVariable::Wait(Mutex* mutex) {
|
||||
#if defined(DEBUG)
|
||||
ThreadId saved_owner = mutex->InvalidateOwner();
|
||||
#endif
|
||||
|
||||
SleepConditionVariableSRW(&data_.cond_, &mutex->data_.lock_, INFINITE, 0);
|
||||
|
||||
#if defined(DEBUG)
|
||||
mutex->SetCurrentThreadAsOwner();
|
||||
ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() {
|
||||
WakeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
Monitor::Monitor() {
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
InitializeConditionVariable(&data_.cond_);
|
||||
#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)
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
// Attempt to pass the semaphore but return immediately.
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
|
||||
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
}
|
||||
|
||||
void Monitor::Exit() {
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
#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 (millis == kNoTimeout) {
|
||||
SleepConditionVariableSRW(&data_.cond_, &data_.lock_, INFINITE, 0);
|
||||
} else {
|
||||
// Wait for the given period of time for a Notify or a NotifyAll
|
||||
// event.
|
||||
if (!SleepConditionVariableSRW(&data_.cond_, &data_.lock_, millis, 0)) {
|
||||
ASSERT(GetLastError() == ERROR_TIMEOUT);
|
||||
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;
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
||||
// TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows.
|
||||
int64_t millis = micros / kMicrosecondsPerMillisecond;
|
||||
if ((millis * kMicrosecondsPerMillisecond) < micros) {
|
||||
// We've been asked to sleep for a fraction of a millisecond,
|
||||
// this isn't supported on Windows. Bumps milliseconds up by one
|
||||
// so that we never return too early. We likely return late though.
|
||||
millis += 1;
|
||||
}
|
||||
return Wait(millis);
|
||||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
WakeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
WakeAllConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void ThreadLocalData::AddThreadLocal(ThreadLocalKey key,
|
||||
ThreadDestructor destructor) {
|
||||
ASSERT(thread_locals_ != nullptr);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
namespace dart {
|
||||
|
||||
typedef DWORD ThreadLocalKey;
|
||||
typedef DWORD ThreadId;
|
||||
typedef HANDLE ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
|
||||
@@ -39,47 +38,6 @@ class ThreadInlineImpl {
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
class MutexData {
|
||||
private:
|
||||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
SRWLOCK lock_;
|
||||
|
||||
friend class Mutex;
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class ConditionVariableData {
|
||||
private:
|
||||
ConditionVariableData() {}
|
||||
~ConditionVariableData() {}
|
||||
|
||||
CONDITION_VARIABLE cond_;
|
||||
|
||||
friend class ConditionVariable;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
SRWLOCK lock_;
|
||||
CONDITION_VARIABLE cond_;
|
||||
|
||||
friend class Monitor;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
};
|
||||
|
||||
typedef void (*ThreadDestructor)(void* parameter);
|
||||
|
||||
class ThreadLocalEntry {
|
||||
|
||||
@@ -80,7 +80,7 @@ static Mutex* global_random_mutex = nullptr;
|
||||
|
||||
void Random::Init() {
|
||||
ASSERT(global_random_mutex == nullptr);
|
||||
global_random_mutex = new Mutex(NOT_IN_PRODUCT("global_random_mutex"));
|
||||
global_random_mutex = new Mutex();
|
||||
ASSERT(global_random == nullptr);
|
||||
global_random = new Random();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ void VirtualMemoryCompressedHeap::Init(void* compressed_heap_region,
|
||||
// same upper 32 bits, which is what we really need for compressed pointers.
|
||||
intptr_t mask = ~(kCompressedHeapAlignment - 1);
|
||||
ASSERT((base_ & mask) == ((base_ + size_ - 1) & mask));
|
||||
mutex_ = new Mutex(NOT_IN_PRODUCT("compressed_heap_mutex"));
|
||||
mutex_ = new Mutex();
|
||||
}
|
||||
|
||||
void VirtualMemoryCompressedHeap::Cleanup() {
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ static intptr_t segment_cache_size = 0;
|
||||
|
||||
void Zone::Init() {
|
||||
ASSERT(segment_cache_mutex == nullptr);
|
||||
segment_cache_mutex = new Mutex(NOT_IN_PRODUCT("segment_cache_mutex"));
|
||||
segment_cache_mutex = new Mutex();
|
||||
}
|
||||
|
||||
void Zone::Cleanup() {
|
||||
|
||||
@@ -10,12 +10,12 @@ import "dart:nativewrappers" show NativeFieldWrapperClass1;
|
||||
@pragma("vm:entry-point")
|
||||
abstract interface class Mutex {
|
||||
@patch
|
||||
factory Mutex._(String debug_name) => _MutexImpl(debug_name);
|
||||
factory Mutex._() => _MutexImpl();
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
base class _MutexImpl extends NativeFieldWrapperClass1 implements Mutex {
|
||||
_MutexImpl(this.debug_name) {
|
||||
_MutexImpl() {
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ base class _MutexImpl extends NativeFieldWrapperClass1 implements Mutex {
|
||||
_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
String debug_name;
|
||||
}
|
||||
|
||||
@patch
|
||||
|
||||
@@ -15,9 +15,9 @@ library dart.concurrent;
|
||||
///
|
||||
/// Mutex objects are owned by an isolate which created them.
|
||||
abstract interface class Mutex {
|
||||
factory Mutex({String debug_name = "mutex"}) => Mutex._(debug_name);
|
||||
factory Mutex() => Mutex._();
|
||||
|
||||
external factory Mutex._(String debug_name);
|
||||
external factory Mutex._();
|
||||
|
||||
/// Acquire exclusive ownership of this mutex.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user