[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:
Ryan Macnak 2018-11-09 18:44:49 +00:00 committed by commit-bot@chromium.org
parent 4b900fdcc5
commit cb522bfcd2
13 changed files with 38 additions and 573 deletions

View file

@ -36,7 +36,6 @@ bool InitOnce(char** error) {
err.message());
return false;
}
bin::Thread::InitOnce();
bin::TimerUtils::InitOnce();
bin::EventHandler::Start();
return true;

View file

@ -18,7 +18,6 @@ namespace bin {
void BootstrapDartIo() {
// Bootstrap 'dart:io' event handler.
Thread::InitOnce();
TimerUtils::InitOnce();
EventHandler::Start();
}

View file

@ -980,7 +980,6 @@ int main(int argc, char** argv) {
return kErrorExitCode;
}
Console::SaveConfig();
Thread::InitOnce();
Loader::InitOnce();
DartUtils::SetOriginalWorkingDirectory();
// Start event handler.

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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;