blob: ef6b6320b038b00be41d90ebb746af4b4a843ae5 [file] [log] [blame]
// 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.
#include "platform/globals.h"
#if defined(HOST_OS_WINDOWS)
#include "bin/thread.h"
#include "bin/thread_win.h"
#include <process.h> // NOLINT
#include "platform/assert.h"
namespace dart {
namespace bin {
class ThreadStartData {
public:
ThreadStartData(const char* name,
Thread::ThreadStartFunction function,
uword parameter)
: name_(name), function_(function), parameter_(parameter) {}
const char* name() const { return name_; }
Thread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
const char* name_;
Thread::ThreadStartFunction function_;
uword parameter_;
DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
};
// Dispatch to the thread start function provided by the caller. This trampoline
// is used to ensure that the thread is properly destroyed if the thread just
// exits.
static unsigned int __stdcall ThreadEntry(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
Thread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
// Call the supplied thread start function handing it its parameters.
function(parameter);
return 0;
}
int Thread::Start(const char* name,
ThreadStartFunction function,
uword parameter) {
ThreadStartData* start_data = new ThreadStartData(name, function, parameter);
uint32_t tid;
uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(),
ThreadEntry, start_data, 0, &tid);
if ((thread == -1L) || (thread == 0)) {
#ifdef DEBUG
fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno));
#endif
return errno;
}
// Close the handle, so we don't leak the thread object.
CloseHandle(reinterpret_cast<HANDLE>(thread));
return 0;
}
const ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
const ThreadId Thread::kInvalidThreadId = 0;
ThreadLocalKey Thread::CreateThreadLocal() {
ThreadLocalKey key = TlsAlloc();
if (key == kUnsetThreadLocalKey) {
FATAL1("TlsAlloc failed %d", GetLastError());
}
return key;
}
void Thread::DeleteThreadLocal(ThreadLocalKey key) {
ASSERT(key != kUnsetThreadLocalKey);
BOOL result = TlsFree(key);
if (!result) {
FATAL1("TlsFree failed %d", GetLastError());
}
}
intptr_t Thread::GetMaxStackSize() {
const int kStackSize = (128 * kWordSize * KB);
return kStackSize;
}
ThreadId Thread::GetCurrentThreadId() {
return ::GetCurrentThreadId();
}
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) <= sizeof(intptr_t));
return static_cast<intptr_t>(id);
}
bool Thread::Compare(ThreadId a, ThreadId b) {
return (a == b);
}
void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
ASSERT(key != kUnsetThreadLocalKey);
BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value));
if (!result) {
FATAL1("TlsSetValue failed %d", GetLastError());
}
}
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() {
InitializeCriticalSection(&data_.cs_);
InitializeConditionVariable(&data_.cond_);
}
Monitor::~Monitor() {
DeleteCriticalSection(&data_.cs_);
}
void Monitor::Enter() {
EnterCriticalSection(&data_.cs_);
}
void Monitor::Exit() {
LeaveCriticalSection(&data_.cs_);
}
Monitor::WaitResult Monitor::Wait(int64_t millis) {
Monitor::WaitResult retval = kNotified;
if (millis == kNoTimeout) {
SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE);
} else {
// Wait for the given period of time for a Notify or a NotifyAll
// event.
if (!SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis)) {
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
#endif // defined(HOST_OS_WINDOWS)