mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm] Update Windows synchronization code to CONDITION_VARIABLEs and SRWLOCKs.
Use CRITICAL_SECTIONs for dart::bin::Monitor as the event handler requires a recursive monitor. Requires Vista or later. Bug: https://github.com/dart-lang/sdk/issues/35029 Bug: https://github.com/dart-lang/sdk/issues/35118 Change-Id: I1e96c5b428257649a45d26a979fba53a10f02151 Reviewed-on: https://dart-review.googlesource.com/c/20901 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
parent
4b900fdcc5
commit
cb522bfcd2
|
@ -36,7 +36,6 @@ bool InitOnce(char** error) {
|
|||
err.message());
|
||||
return false;
|
||||
}
|
||||
bin::Thread::InitOnce();
|
||||
bin::TimerUtils::InitOnce();
|
||||
bin::EventHandler::Start();
|
||||
return true;
|
||||
|
|
|
@ -18,7 +18,6 @@ namespace bin {
|
|||
|
||||
void BootstrapDartIo() {
|
||||
// Bootstrap 'dart:io' event handler.
|
||||
Thread::InitOnce();
|
||||
TimerUtils::InitOnce();
|
||||
EventHandler::Start();
|
||||
}
|
||||
|
|
|
@ -980,7 +980,6 @@ int main(int argc, char** argv) {
|
|||
return kErrorExitCode;
|
||||
}
|
||||
Console::SaveConfig();
|
||||
Thread::InitOnce();
|
||||
Loader::InitOnce();
|
||||
DartUtils::SetOriginalWorkingDirectory();
|
||||
// Start event handler.
|
||||
|
|
|
@ -276,7 +276,6 @@ static int Main(int argc, const char** argv) {
|
|||
dart_argv = &argv[1];
|
||||
}
|
||||
|
||||
bin::Thread::InitOnce();
|
||||
bin::TimerUtils::InitOnce();
|
||||
bin::EventHandler::Start();
|
||||
|
||||
|
|
|
@ -152,10 +152,6 @@ bool Thread::Compare(ThreadId a, ThreadId b) {
|
|||
return (a == b);
|
||||
}
|
||||
|
||||
void Thread::InitOnce() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
|
|
|
@ -151,10 +151,6 @@ bool Thread::Compare(ThreadId a, ThreadId b) {
|
|||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
void Thread::InitOnce() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
|
|
|
@ -152,10 +152,6 @@ bool Thread::Compare(ThreadId a, ThreadId b) {
|
|||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
void Thread::InitOnce() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
|
|
|
@ -146,10 +146,6 @@ bool Thread::Compare(ThreadId a, ThreadId b) {
|
|||
return (pthread_equal(a, b) != 0);
|
||||
}
|
||||
|
||||
void Thread::InitOnce() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
int result = pthread_mutexattr_init(&attr);
|
||||
|
|
|
@ -40,14 +40,9 @@ static unsigned int __stdcall ThreadEntry(void* data_ptr) {
|
|||
uword parameter = data->parameter();
|
||||
delete data;
|
||||
|
||||
MonitorData::GetMonitorWaitDataForThread();
|
||||
|
||||
// Call the supplied thread start function handing it its parameters.
|
||||
function(parameter);
|
||||
|
||||
// Clean up the monitor wait data for this thread.
|
||||
MonitorWaitData::ThreadExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -114,63 +109,34 @@ void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
|||
}
|
||||
}
|
||||
|
||||
void Thread::InitOnce() {
|
||||
MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal();
|
||||
MonitorData::GetMonitorWaitDataForThread();
|
||||
}
|
||||
|
||||
Mutex::Mutex() {
|
||||
// Allocate unnamed semaphore with initial count 1 and max count 1.
|
||||
data_.semaphore_ = CreateSemaphore(NULL, 1, 1, NULL);
|
||||
if (data_.semaphore_ == NULL) {
|
||||
FATAL1("Mutex allocation failed %d", GetLastError());
|
||||
}
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
CloseHandle(data_.semaphore_);
|
||||
}
|
||||
Mutex::~Mutex() {}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DWORD result = WaitForSingleObject(data_.semaphore_, INFINITE);
|
||||
if (result != WAIT_OBJECT_0) {
|
||||
FATAL1("Mutex lock failed %d", GetLastError());
|
||||
}
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
// Attempt to pass the semaphore but return immediately.
|
||||
DWORD result = WaitForSingleObject(data_.semaphore_, 0);
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
|
||||
return true;
|
||||
}
|
||||
if ((result == WAIT_ABANDONED) || (result == WAIT_FAILED)) {
|
||||
FATAL1("Mutex try lock failed %d", GetLastError());
|
||||
}
|
||||
ASSERT(result == WAIT_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL);
|
||||
if (result == 0) {
|
||||
FATAL1("Mutex unlock failed %d", GetLastError());
|
||||
}
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ =
|
||||
Thread::kUnsetThreadLocalKey;
|
||||
|
||||
Monitor::Monitor() {
|
||||
InitializeCriticalSection(&data_.cs_);
|
||||
InitializeCriticalSection(&data_.waiters_cs_);
|
||||
data_.waiters_head_ = NULL;
|
||||
data_.waiters_tail_ = NULL;
|
||||
InitializeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
DeleteCriticalSection(&data_.cs_);
|
||||
DeleteCriticalSection(&data_.waiters_cs_);
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
|
@ -181,188 +147,19 @@ void Monitor::Exit() {
|
|||
LeaveCriticalSection(&data_.cs_);
|
||||
}
|
||||
|
||||
void MonitorWaitData::ThreadExit() {
|
||||
if (MonitorWaitData::monitor_wait_data_key_ != Thread::kUnsetThreadLocalKey) {
|
||||
uword raw_wait_data =
|
||||
Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
|
||||
if (raw_wait_data != 0) {
|
||||
MonitorWaitData* wait_data =
|
||||
reinterpret_cast<MonitorWaitData*>(raw_wait_data);
|
||||
delete wait_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorData::AddWaiter(MonitorWaitData* wait_data) {
|
||||
// Add the MonitorWaitData object to the list of objects waiting for
|
||||
// this monitor.
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
if (waiters_tail_ == NULL) {
|
||||
ASSERT(waiters_head_ == NULL);
|
||||
waiters_head_ = wait_data;
|
||||
waiters_tail_ = wait_data;
|
||||
} else {
|
||||
waiters_tail_->next_ = wait_data;
|
||||
waiters_tail_ = wait_data;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) {
|
||||
// Remove the MonitorWaitData object from the list of objects
|
||||
// waiting for this monitor.
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
MonitorWaitData* previous = NULL;
|
||||
MonitorWaitData* current = waiters_head_;
|
||||
while (current != NULL) {
|
||||
if (current == wait_data) {
|
||||
if (waiters_head_ == waiters_tail_) {
|
||||
waiters_head_ = NULL;
|
||||
waiters_tail_ = NULL;
|
||||
} else if (current == waiters_head_) {
|
||||
waiters_head_ = waiters_head_->next_;
|
||||
} else if (current == waiters_tail_) {
|
||||
ASSERT(previous != NULL);
|
||||
waiters_tail_ = previous;
|
||||
previous->next_ = NULL;
|
||||
} else {
|
||||
ASSERT(previous != NULL);
|
||||
previous->next_ = current->next_;
|
||||
}
|
||||
// Clear next.
|
||||
wait_data->next_ = NULL;
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
current = current->next_;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::SignalAndRemoveFirstWaiter() {
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
MonitorWaitData* first = waiters_head_;
|
||||
if (first != NULL) {
|
||||
// Remove from list.
|
||||
if (waiters_head_ == waiters_tail_) {
|
||||
waiters_tail_ = NULL;
|
||||
waiters_head_ = NULL;
|
||||
} else {
|
||||
waiters_head_ = waiters_head_->next_;
|
||||
}
|
||||
// Clear next.
|
||||
first->next_ = NULL;
|
||||
// Signal event.
|
||||
BOOL result = SetEvent(first->event_);
|
||||
if (result == 0) {
|
||||
FATAL1("Monitor::Notify failed to signal event %d", GetLastError());
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::SignalAndRemoveAllWaiters() {
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
// Extract list to signal.
|
||||
MonitorWaitData* current = waiters_head_;
|
||||
// Clear list.
|
||||
waiters_head_ = NULL;
|
||||
waiters_tail_ = NULL;
|
||||
// Iterate and signal all events.
|
||||
while (current != NULL) {
|
||||
// Copy next.
|
||||
MonitorWaitData* next = current->next_;
|
||||
// Clear next.
|
||||
current->next_ = NULL;
|
||||
// Signal event.
|
||||
BOOL result = SetEvent(current->event_);
|
||||
if (result == 0) {
|
||||
FATAL1("Failed to set event for NotifyAll %d", GetLastError());
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() {
|
||||
// Ensure that the thread local key for monitor wait data objects is
|
||||
// initialized.
|
||||
ASSERT(MonitorWaitData::monitor_wait_data_key_ !=
|
||||
Thread::kUnsetThreadLocalKey);
|
||||
|
||||
// Get the MonitorWaitData object containing the event for this
|
||||
// thread from thread local storage. Create it if it does not exist.
|
||||
uword raw_wait_data =
|
||||
Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
|
||||
MonitorWaitData* wait_data = NULL;
|
||||
if (raw_wait_data == 0) {
|
||||
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
wait_data = new MonitorWaitData(event);
|
||||
Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_,
|
||||
reinterpret_cast<uword>(wait_data));
|
||||
} else {
|
||||
wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data);
|
||||
ASSERT(wait_data->next_ == NULL);
|
||||
}
|
||||
return wait_data;
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
|
||||
// Get the wait data object containing the event to wait for.
|
||||
MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread();
|
||||
|
||||
// Start waiting by adding the MonitorWaitData to the list of
|
||||
// waiters.
|
||||
data_.AddWaiter(wait_data);
|
||||
|
||||
// Leave the monitor critical section while waiting.
|
||||
LeaveCriticalSection(&data_.cs_);
|
||||
|
||||
// Perform the actual wait on the event.
|
||||
DWORD result = WAIT_FAILED;
|
||||
if (millis == 0) {
|
||||
// Wait forever for a Notify or a NotifyAll event.
|
||||
result = WaitForSingleObject(wait_data->event_, INFINITE);
|
||||
if (result == WAIT_FAILED) {
|
||||
FATAL1("Monitor::Wait failed %d", GetLastError());
|
||||
}
|
||||
if (millis == kNoTimeout) {
|
||||
SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE);
|
||||
} else {
|
||||
// Wait for the given period of time for a Notify or a NotifyAll
|
||||
// event.
|
||||
result = WaitForSingleObject(wait_data->event_, millis);
|
||||
if (result == WAIT_FAILED) {
|
||||
FATAL1("Monitor::Wait with timeout failed %d", GetLastError());
|
||||
}
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
// No longer waiting. Remove from the list of waiters.
|
||||
data_.RemoveWaiter(wait_data);
|
||||
// Caveat: wait_data->event_ might have been signaled between
|
||||
// WaitForSingleObject and RemoveWaiter because we are not in any critical
|
||||
// section here. Leaving it in a signaled state would break invariants
|
||||
// that Monitor::Wait code relies on. We assume that when
|
||||
// WaitForSingleObject(wait_data->event_, ...) returns successfully then
|
||||
// corresponding wait_data is not on the waiters list anymore.
|
||||
// This is guaranteed because we only signal these events from
|
||||
// SignalAndRemoveAllWaiters/SignalAndRemoveFirstWaiter which
|
||||
// simultaneously remove MonitorWaitData from the list.
|
||||
// Now imagine that wait_data->event_ is left signaled here. In this case
|
||||
// the next WaitForSingleObject(wait_data->event_, ...) will immediately
|
||||
// return while wait_data is still on the waiters list. This would
|
||||
// leave waiters list in the inconsistent state.
|
||||
// To prevent this from happening simply reset the event.
|
||||
// Note: wait_data is no longer on the waiters list so it can't be
|
||||
// signaled anymore at this point so there is no race possible from
|
||||
// this point onward.
|
||||
ResetEvent(wait_data->event_);
|
||||
if (!SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis)) {
|
||||
ASSERT(GetLastError() == ERROR_TIMEOUT);
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
// Reacquire the monitor critical section before continuing.
|
||||
EnterCriticalSection(&data_.cs_);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -379,16 +176,11 @@ Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
|||
}
|
||||
|
||||
void Monitor::Notify() {
|
||||
data_.SignalAndRemoveFirstWaiter();
|
||||
WakeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// If one of the objects in the list of waiters wakes because of a
|
||||
// timeout before we signal it, that object will get an extra
|
||||
// signal. This will be treated as a spurious wake-up and is OK
|
||||
// since all uses of monitors should recheck the condition after a
|
||||
// Wait.
|
||||
data_.SignalAndRemoveAllWaiters();
|
||||
WakeAllConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
|
|
|
@ -41,7 +41,7 @@ class MutexData {
|
|||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
HANDLE semaphore_;
|
||||
SRWLOCK lock_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
|
@ -49,64 +49,15 @@ class MutexData {
|
|||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorWaitData {
|
||||
public:
|
||||
static void ThreadExit();
|
||||
|
||||
private:
|
||||
explicit MonitorWaitData(HANDLE event) : event_(event), next_(NULL) {}
|
||||
~MonitorWaitData() {
|
||||
CloseHandle(event_);
|
||||
ASSERT(next_ == NULL);
|
||||
}
|
||||
|
||||
// ThreadLocalKey used to fetch and store the MonitorWaitData object
|
||||
// for a given thread.
|
||||
static ThreadLocalKey monitor_wait_data_key_;
|
||||
|
||||
// Auto-reset event used for waiting.
|
||||
HANDLE event_;
|
||||
// Link to next element in the singly-linked list of waiters.
|
||||
MonitorWaitData* next_;
|
||||
|
||||
friend class Monitor;
|
||||
friend class MonitorData;
|
||||
friend class Thread;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorWaitData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
// Helper methods to manipulate the list of waiters for this
|
||||
// monitor.
|
||||
void AddWaiter(MonitorWaitData* wait_data);
|
||||
void RemoveWaiter(MonitorWaitData* wait_data);
|
||||
void SignalAndRemoveFirstWaiter();
|
||||
void SignalAndRemoveAllWaiters();
|
||||
static MonitorWaitData* GetMonitorWaitDataForThread();
|
||||
|
||||
// The external critical section for the monitor.
|
||||
CRITICAL_SECTION cs_;
|
||||
|
||||
// Condition variables are only available since Windows Vista. To
|
||||
// support at least Windows XP, we implement our own condition
|
||||
// variables using SetEvent on Event objects.
|
||||
|
||||
// Singly-linked list of event objects, one for each thread waiting
|
||||
// on this monitor. New waiters are added at the end of the list.
|
||||
// Notify signals the first element of the list (FIFO
|
||||
// order). NotifyAll, signals all the elements of the list.
|
||||
CRITICAL_SECTION waiters_cs_;
|
||||
MonitorWaitData* waiters_head_;
|
||||
MonitorWaitData* waiters_tail_;
|
||||
CONDITION_VARIABLE cond_;
|
||||
|
||||
friend class Monitor;
|
||||
friend class Thread;
|
||||
friend unsigned int __stdcall ThreadEntry(void* data_ptr);
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
|
|
|
@ -51,8 +51,6 @@ static unsigned int __stdcall ThreadEntry(void* data_ptr) {
|
|||
uword parameter = data->parameter();
|
||||
delete data;
|
||||
|
||||
MonitorData::GetMonitorWaitDataForThread();
|
||||
|
||||
// Create new OSThread object and set as TLS for new thread.
|
||||
OSThread* thread = OSThread::CreateOSThread();
|
||||
if (thread != NULL) {
|
||||
|
@ -63,9 +61,6 @@ static unsigned int __stdcall ThreadEntry(void* data_ptr) {
|
|||
function(parameter);
|
||||
}
|
||||
|
||||
// Clean up the monitor wait data for this thread.
|
||||
MonitorWaitData::ThreadExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -220,15 +215,7 @@ Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
|||
: name_(name)
|
||||
#endif
|
||||
{
|
||||
// Allocate unnamed semaphore with initial count 1 and max count 1.
|
||||
data_.semaphore_ = CreateSemaphore(NULL, 1, 1, NULL);
|
||||
if (data_.semaphore_ == NULL) {
|
||||
#if defined(PRODUCT)
|
||||
FATAL1("Mutex allocation failed %d", GetLastError());
|
||||
#else
|
||||
FATAL2("[%s] Mutex allocation failed %d", name_, GetLastError());
|
||||
#endif
|
||||
}
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
|
@ -236,7 +223,6 @@ Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
|
|||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
CloseHandle(data_.semaphore_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
|
@ -244,10 +230,7 @@ Mutex::~Mutex() {
|
|||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
DWORD result = WaitForSingleObject(data_.semaphore_, INFINITE);
|
||||
if (result != WAIT_OBJECT_0) {
|
||||
FATAL1("Mutex lock failed %d", GetLastError());
|
||||
}
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we do track the owner.
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
|
@ -255,19 +238,13 @@ void Mutex::Lock() {
|
|||
}
|
||||
|
||||
bool Mutex::TryLock() {
|
||||
// Attempt to pass the semaphore but return immediately.
|
||||
DWORD result = WaitForSingleObject(data_.semaphore_, 0);
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
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;
|
||||
}
|
||||
if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
|
||||
FATAL1("Mutex try lock failed %d", GetLastError());
|
||||
}
|
||||
ASSERT(result == WAIT_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -277,20 +254,12 @@ void Mutex::Unlock() {
|
|||
ASSERT(IsOwnedByCurrentThread());
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL);
|
||||
if (result == 0) {
|
||||
FATAL1("Mutex unlock failed %d", GetLastError());
|
||||
}
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = kUnsetThreadLocalKey;
|
||||
|
||||
Monitor::Monitor() {
|
||||
InitializeCriticalSection(&data_.cs_);
|
||||
InitializeCriticalSection(&data_.waiters_cs_);
|
||||
data_.waiters_head_ = NULL;
|
||||
data_.waiters_tail_ = NULL;
|
||||
|
||||
InitializeSRWLock(&data_.lock_);
|
||||
InitializeConditionVariable(&data_.cond_);
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
owner_ = OSThread::kInvalidThreadId;
|
||||
|
@ -302,27 +271,23 @@ Monitor::~Monitor() {
|
|||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
DeleteCriticalSection(&data_.cs_);
|
||||
DeleteCriticalSection(&data_.waiters_cs_);
|
||||
}
|
||||
|
||||
bool Monitor::TryEnter() {
|
||||
// Attempt to pass the semaphore but return immediately.
|
||||
BOOL result = TryEnterCriticalSection(&data_.cs_);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
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();
|
||||
// When running with assertions enabled we do track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
owner_ = OSThread::GetCurrentThreadId();
|
||||
#endif // defined(DEBUG)
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Monitor::Enter() {
|
||||
EnterCriticalSection(&data_.cs_);
|
||||
AcquireSRWLockExclusive(&data_.lock_);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
|
@ -338,130 +303,7 @@ void Monitor::Exit() {
|
|||
owner_ = OSThread::kInvalidThreadId;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
LeaveCriticalSection(&data_.cs_);
|
||||
}
|
||||
|
||||
void MonitorWaitData::ThreadExit() {
|
||||
if (MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey) {
|
||||
uword raw_wait_data =
|
||||
OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
|
||||
// Clear in case this is called a second time.
|
||||
OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, 0);
|
||||
if (raw_wait_data != 0) {
|
||||
MonitorWaitData* wait_data =
|
||||
reinterpret_cast<MonitorWaitData*>(raw_wait_data);
|
||||
delete wait_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorData::AddWaiter(MonitorWaitData* wait_data) {
|
||||
// Add the MonitorWaitData object to the list of objects waiting for
|
||||
// this monitor.
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
if (waiters_tail_ == NULL) {
|
||||
ASSERT(waiters_head_ == NULL);
|
||||
waiters_head_ = waiters_tail_ = wait_data;
|
||||
} else {
|
||||
waiters_tail_->next_ = wait_data;
|
||||
waiters_tail_ = wait_data;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) {
|
||||
// Remove the MonitorWaitData object from the list of objects
|
||||
// waiting for this monitor.
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
MonitorWaitData* previous = NULL;
|
||||
MonitorWaitData* current = waiters_head_;
|
||||
while (current != NULL) {
|
||||
if (current == wait_data) {
|
||||
if (waiters_head_ == waiters_tail_) {
|
||||
waiters_head_ = waiters_tail_ = NULL;
|
||||
} else if (current == waiters_head_) {
|
||||
waiters_head_ = waiters_head_->next_;
|
||||
} else if (current == waiters_tail_) {
|
||||
ASSERT(previous != NULL);
|
||||
waiters_tail_ = previous;
|
||||
previous->next_ = NULL;
|
||||
} else {
|
||||
ASSERT(previous != NULL);
|
||||
previous->next_ = current->next_;
|
||||
}
|
||||
// Clear next.
|
||||
wait_data->next_ = NULL;
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
current = current->next_;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::SignalAndRemoveFirstWaiter() {
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
MonitorWaitData* first = waiters_head_;
|
||||
if (first != NULL) {
|
||||
// Remove from list.
|
||||
if (waiters_head_ == waiters_tail_) {
|
||||
waiters_tail_ = waiters_head_ = NULL;
|
||||
} else {
|
||||
waiters_head_ = waiters_head_->next_;
|
||||
}
|
||||
// Clear next.
|
||||
first->next_ = NULL;
|
||||
// Signal event.
|
||||
BOOL result = SetEvent(first->event_);
|
||||
if (result == 0) {
|
||||
FATAL1("Monitor::Notify failed to signal event %d", GetLastError());
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
void MonitorData::SignalAndRemoveAllWaiters() {
|
||||
EnterCriticalSection(&waiters_cs_);
|
||||
// Extract list to signal.
|
||||
MonitorWaitData* current = waiters_head_;
|
||||
// Clear list.
|
||||
waiters_head_ = waiters_tail_ = NULL;
|
||||
// Iterate and signal all events.
|
||||
while (current != NULL) {
|
||||
// Copy next.
|
||||
MonitorWaitData* next = current->next_;
|
||||
// Clear next.
|
||||
current->next_ = NULL;
|
||||
// Signal event.
|
||||
BOOL result = SetEvent(current->event_);
|
||||
if (result == 0) {
|
||||
FATAL1("Failed to set event for NotifyAll %d", GetLastError());
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
LeaveCriticalSection(&waiters_cs_);
|
||||
}
|
||||
|
||||
MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() {
|
||||
// Ensure that the thread local key for monitor wait data objects is
|
||||
// initialized.
|
||||
ASSERT(MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey);
|
||||
|
||||
// Get the MonitorWaitData object containing the event for this
|
||||
// thread from thread local storage. Create it if it does not exist.
|
||||
uword raw_wait_data =
|
||||
OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
|
||||
MonitorWaitData* wait_data = NULL;
|
||||
if (raw_wait_data == 0) {
|
||||
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
wait_data = new MonitorWaitData(event);
|
||||
OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_,
|
||||
reinterpret_cast<uword>(wait_data));
|
||||
} else {
|
||||
wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data);
|
||||
ASSERT(wait_data->next_ == NULL);
|
||||
}
|
||||
return wait_data;
|
||||
ReleaseSRWLockExclusive(&data_.lock_);
|
||||
}
|
||||
|
||||
Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
||||
|
@ -473,60 +315,17 @@ Monitor::WaitResult Monitor::Wait(int64_t millis) {
|
|||
#endif // defined(DEBUG)
|
||||
|
||||
Monitor::WaitResult retval = kNotified;
|
||||
|
||||
// Get the wait data object containing the event to wait for.
|
||||
MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread();
|
||||
|
||||
// Start waiting by adding the MonitorWaitData to the list of
|
||||
// waiters.
|
||||
data_.AddWaiter(wait_data);
|
||||
|
||||
// Leave the monitor critical section while waiting.
|
||||
LeaveCriticalSection(&data_.cs_);
|
||||
|
||||
// Perform the actual wait on the event.
|
||||
DWORD result = WAIT_FAILED;
|
||||
if (millis == 0) {
|
||||
// Wait forever for a Notify or a NotifyAll event.
|
||||
result = WaitForSingleObject(wait_data->event_, INFINITE);
|
||||
if (result == WAIT_FAILED) {
|
||||
FATAL1("Monitor::Wait failed %d", GetLastError());
|
||||
}
|
||||
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.
|
||||
result = WaitForSingleObject(wait_data->event_, millis);
|
||||
if (result == WAIT_FAILED) {
|
||||
FATAL1("Monitor::Wait with timeout failed %d", GetLastError());
|
||||
}
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
// No longer waiting. Remove from the list of waiters.
|
||||
data_.RemoveWaiter(wait_data);
|
||||
// Caveat: wait_data->event_ might have been signaled between
|
||||
// WaitForSingleObject and RemoveWaiter because we are not in any critical
|
||||
// section here. Leaving it in a signaled state would break invariants
|
||||
// that Monitor::Wait code relies on. We assume that when
|
||||
// WaitForSingleObject(wait_data->event_, ...) returns successfully then
|
||||
// corresponding wait_data is not on the waiters list anymore.
|
||||
// This is guaranteed because we only signal these events from
|
||||
// SignalAndRemoveAllWaiters/SignalAndRemoveFirstWaiter which
|
||||
// simultaneously remove MonitorWaitData from the list.
|
||||
// Now imagine that wait_data->event_ is left signaled here. In this case
|
||||
// the next WaitForSingleObject(wait_data->event_, ...) will immediately
|
||||
// return while wait_data is still on the waiters list. This would
|
||||
// leave waiters list in the inconsistent state.
|
||||
// To prevent this from happening simply reset the event.
|
||||
// Note: wait_data is no longer on the waiters list so it can't be
|
||||
// signaled anymore at this point so there is no race possible from
|
||||
// this point onward.
|
||||
ResetEvent(wait_data->event_);
|
||||
if (!SleepConditionVariableSRW(&data_.cond_, &data_.lock_, millis, 0)) {
|
||||
ASSERT(GetLastError() == ERROR_TIMEOUT);
|
||||
retval = kTimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
// Reacquire the monitor critical section before continuing.
|
||||
EnterCriticalSection(&data_.cs_);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(owner_ == OSThread::kInvalidThreadId);
|
||||
|
@ -551,18 +350,13 @@ Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
|
|||
void Monitor::Notify() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
data_.SignalAndRemoveFirstWaiter();
|
||||
WakeConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void Monitor::NotifyAll() {
|
||||
// When running with assertions enabled we track the owner.
|
||||
ASSERT(IsOwnedByCurrentThread());
|
||||
// If one of the objects in the list of waiters wakes because of a
|
||||
// timeout before we signal it, that object will get an extra
|
||||
// signal. This will be treated as a spurious wake-up and is OK
|
||||
// since all uses of monitors should recheck the condition after a
|
||||
// Wait.
|
||||
data_.SignalAndRemoveAllWaiters();
|
||||
WakeAllConditionVariable(&data_.cond_);
|
||||
}
|
||||
|
||||
void ThreadLocalData::AddThreadLocal(ThreadLocalKey key,
|
||||
|
@ -677,7 +471,6 @@ void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) {
|
|||
// and on W2K and W2K3. So don't assume it is sent.
|
||||
if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) {
|
||||
dart::ThreadLocalData::RunDestructors();
|
||||
dart::MonitorWaitData::ThreadExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class MutexData {
|
|||
MutexData() {}
|
||||
~MutexData() {}
|
||||
|
||||
HANDLE semaphore_;
|
||||
SRWLOCK lock_;
|
||||
|
||||
friend class Mutex;
|
||||
|
||||
|
@ -52,64 +52,15 @@ class MutexData {
|
|||
DISALLOW_COPY_AND_ASSIGN(MutexData);
|
||||
};
|
||||
|
||||
class MonitorWaitData {
|
||||
public:
|
||||
static void ThreadExit();
|
||||
|
||||
private:
|
||||
explicit MonitorWaitData(HANDLE event) : event_(event), next_(NULL) {}
|
||||
~MonitorWaitData() {
|
||||
CloseHandle(event_);
|
||||
ASSERT(next_ == NULL);
|
||||
}
|
||||
|
||||
// ThreadLocalKey used to fetch and store the MonitorWaitData object
|
||||
// for a given thread.
|
||||
static ThreadLocalKey monitor_wait_data_key_;
|
||||
|
||||
// Auto-reset event used for waiting.
|
||||
HANDLE event_;
|
||||
// Link to next element in the singly-linked list of waiters.
|
||||
MonitorWaitData* next_;
|
||||
|
||||
friend class Monitor;
|
||||
friend class MonitorData;
|
||||
friend class OS;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorWaitData);
|
||||
};
|
||||
|
||||
class MonitorData {
|
||||
private:
|
||||
MonitorData() {}
|
||||
~MonitorData() {}
|
||||
|
||||
// Helper methods to manipulate the list of waiters for this
|
||||
// monitor.
|
||||
void AddWaiter(MonitorWaitData* wait_data);
|
||||
void RemoveWaiter(MonitorWaitData* wait_data);
|
||||
void SignalAndRemoveFirstWaiter();
|
||||
void SignalAndRemoveAllWaiters();
|
||||
static MonitorWaitData* GetMonitorWaitDataForThread();
|
||||
|
||||
// The external critical section for the monitor.
|
||||
CRITICAL_SECTION cs_;
|
||||
|
||||
// Condition variables are only available since Windows Vista. To
|
||||
// support at least Windows XP, we implement our own condition
|
||||
// variables using SetEvent on Event objects.
|
||||
|
||||
// Singly-linked list of event objects, one for each thread waiting
|
||||
// on this monitor. New waiters are added at the end of the list.
|
||||
// Notify signals the first element of the list (FIFO
|
||||
// order). NotifyAll, signals all the elements of the list.
|
||||
CRITICAL_SECTION waiters_cs_;
|
||||
MonitorWaitData* waiters_head_;
|
||||
MonitorWaitData* waiters_tail_;
|
||||
SRWLOCK lock_;
|
||||
CONDITION_VARIABLE cond_;
|
||||
|
||||
friend class Monitor;
|
||||
friend class OS;
|
||||
friend unsigned int __stdcall ThreadEntry(void* data_ptr);
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(MonitorData);
|
||||
|
|
|
@ -323,8 +323,6 @@ void OS::Init() {
|
|||
// Do not pop up a message box when abort is called.
|
||||
_set_abort_behavior(0, _WRITE_ABORT_MSG);
|
||||
ThreadLocalData::Init();
|
||||
MonitorWaitData::monitor_wait_data_key_ = OSThread::CreateThreadLocal();
|
||||
MonitorData::GetMonitorWaitDataForThread();
|
||||
LARGE_INTEGER ticks_per_sec;
|
||||
if (!QueryPerformanceFrequency(&ticks_per_sec)) {
|
||||
qpc_ticks_per_second = 0;
|
||||
|
|
Loading…
Reference in a new issue