1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_WINDOWS)
7
8#include "bin/thread.h"
9#include "bin/thread_win.h"
10
11#include <process.h> // NOLINT
12
13#include "platform/assert.h"
14
15namespace dart {
16namespace bin {
17
18class ThreadStartData {
19 public:
20 ThreadStartData(const char* name,
21 Thread::ThreadStartFunction function,
22 uword parameter)
23 : name_(name), function_(function), parameter_(parameter) {}
24
25 const char* name() const { return name_; }
26 Thread::ThreadStartFunction function() const { return function_; }
27 uword parameter() const { return parameter_; }
28
29 private:
30 const char* name_;
31 Thread::ThreadStartFunction function_;
32 uword parameter_;
33
34 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
35};
36
37// Dispatch to the thread start function provided by the caller. This trampoline
38// is used to ensure that the thread is properly destroyed if the thread just
39// exits.
40static unsigned int __stdcall ThreadEntry(void* data_ptr) {
41 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
42
43 Thread::ThreadStartFunction function = data->function();
44 uword parameter = data->parameter();
45 delete data;
46
47 // Call the supplied thread start function handing it its parameters.
48 function(parameter);
49
50 return 0;
51}
52
53int Thread::Start(const char* name,
54 ThreadStartFunction function,
55 uword parameter) {
56 ThreadStartData* start_data = new ThreadStartData(name, function, parameter);
57 uint32_t tid;
58 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(),
59 ThreadEntry, start_data, 0, &tid);
60 if ((thread == -1L) || (thread == 0)) {
61#ifdef DEBUG
62 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno));
63#endif
64 return errno;
65 }
66
67 // Close the handle, so we don't leak the thread object.
68 CloseHandle(reinterpret_cast<HANDLE>(thread));
69
70 return 0;
71}
72
73const ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
74const ThreadId Thread::kInvalidThreadId = 0;
75
76ThreadLocalKey Thread::CreateThreadLocal() {
77 ThreadLocalKey key = TlsAlloc();
78 if (key == kUnsetThreadLocalKey) {
79 FATAL1("TlsAlloc failed %d", GetLastError());
80 }
81 return key;
82}
83
84void Thread::DeleteThreadLocal(ThreadLocalKey key) {
85 ASSERT(key != kUnsetThreadLocalKey);
86 BOOL result = TlsFree(key);
87 if (!result) {
88 FATAL1("TlsFree failed %d", GetLastError());
89 }
90}
91
92intptr_t Thread::GetMaxStackSize() {
93 const int kStackSize = (128 * kWordSize * KB);
94 return kStackSize;
95}
96
97ThreadId Thread::GetCurrentThreadId() {
98 return ::GetCurrentThreadId();
99}
100
101intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
102 ASSERT(sizeof(id) <= sizeof(intptr_t));
103 return static_cast<intptr_t>(id);
104}
105
106bool Thread::Compare(ThreadId a, ThreadId b) {
107 return (a == b);
108}
109
110void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
111 ASSERT(key != kUnsetThreadLocalKey);
112 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value));
113 if (!result) {
114 FATAL1("TlsSetValue failed %d", GetLastError());
115 }
116}
117
118Mutex::Mutex() {
119 InitializeSRWLock(&data_.lock_);
120}
121
122Mutex::~Mutex() {}
123
124void Mutex::Lock() {
125 AcquireSRWLockExclusive(&data_.lock_);
126}
127
128bool Mutex::TryLock() {
129 if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) {
130 return true;
131 }
132 return false;
133}
134
135void Mutex::Unlock() {
136 ReleaseSRWLockExclusive(&data_.lock_);
137}
138
139Monitor::Monitor() {
140 InitializeCriticalSection(&data_.cs_);
141 InitializeConditionVariable(&data_.cond_);
142}
143
144Monitor::~Monitor() {
145 DeleteCriticalSection(&data_.cs_);
146}
147
148void Monitor::Enter() {
149 EnterCriticalSection(&data_.cs_);
150}
151
152void Monitor::Exit() {
153 LeaveCriticalSection(&data_.cs_);
154}
155
156Monitor::WaitResult Monitor::Wait(int64_t millis) {
157 Monitor::WaitResult retval = kNotified;
158 if (millis == kNoTimeout) {
159 SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE);
160 } else {
161 // Wait for the given period of time for a Notify or a NotifyAll
162 // event.
163 if (!SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis)) {
164 ASSERT(GetLastError() == ERROR_TIMEOUT);
165 retval = kTimedOut;
166 }
167 }
168
169 return retval;
170}
171
172Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
173 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows.
174 int64_t millis = micros / kMicrosecondsPerMillisecond;
175 if ((millis * kMicrosecondsPerMillisecond) < micros) {
176 // We've been asked to sleep for a fraction of a millisecond,
177 // this isn't supported on Windows. Bumps milliseconds up by one
178 // so that we never return too early. We likely return late though.
179 millis += 1;
180 }
181 return Wait(millis);
182}
183
184void Monitor::Notify() {
185 WakeConditionVariable(&data_.cond_);
186}
187
188void Monitor::NotifyAll() {
189 WakeAllConditionVariable(&data_.cond_);
190}
191
192} // namespace bin
193} // namespace dart
194
195#endif // defined(HOST_OS_WINDOWS)
196