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 | |
15 | namespace dart { |
16 | namespace bin { |
17 | |
18 | class 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. |
40 | static 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 | |
53 | int 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 | |
73 | const ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; |
74 | const ThreadId Thread::kInvalidThreadId = 0; |
75 | |
76 | ThreadLocalKey Thread::CreateThreadLocal() { |
77 | ThreadLocalKey key = TlsAlloc(); |
78 | if (key == kUnsetThreadLocalKey) { |
79 | FATAL1("TlsAlloc failed %d" , GetLastError()); |
80 | } |
81 | return key; |
82 | } |
83 | |
84 | void 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 | |
92 | intptr_t Thread::GetMaxStackSize() { |
93 | const int kStackSize = (128 * kWordSize * KB); |
94 | return kStackSize; |
95 | } |
96 | |
97 | ThreadId Thread::GetCurrentThreadId() { |
98 | return ::GetCurrentThreadId(); |
99 | } |
100 | |
101 | intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { |
102 | ASSERT(sizeof(id) <= sizeof(intptr_t)); |
103 | return static_cast<intptr_t>(id); |
104 | } |
105 | |
106 | bool Thread::Compare(ThreadId a, ThreadId b) { |
107 | return (a == b); |
108 | } |
109 | |
110 | void 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 | |
118 | Mutex::Mutex() { |
119 | InitializeSRWLock(&data_.lock_); |
120 | } |
121 | |
122 | Mutex::~Mutex() {} |
123 | |
124 | void Mutex::Lock() { |
125 | AcquireSRWLockExclusive(&data_.lock_); |
126 | } |
127 | |
128 | bool Mutex::TryLock() { |
129 | if (TryAcquireSRWLockExclusive(&data_.lock_) != 0) { |
130 | return true; |
131 | } |
132 | return false; |
133 | } |
134 | |
135 | void Mutex::Unlock() { |
136 | ReleaseSRWLockExclusive(&data_.lock_); |
137 | } |
138 | |
139 | Monitor::Monitor() { |
140 | InitializeCriticalSection(&data_.cs_); |
141 | InitializeConditionVariable(&data_.cond_); |
142 | } |
143 | |
144 | Monitor::~Monitor() { |
145 | DeleteCriticalSection(&data_.cs_); |
146 | } |
147 | |
148 | void Monitor::Enter() { |
149 | EnterCriticalSection(&data_.cs_); |
150 | } |
151 | |
152 | void Monitor::Exit() { |
153 | LeaveCriticalSection(&data_.cs_); |
154 | } |
155 | |
156 | Monitor::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 | |
172 | Monitor::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 | |
184 | void Monitor::Notify() { |
185 | WakeConditionVariable(&data_.cond_); |
186 | } |
187 | |
188 | void Monitor::NotifyAll() { |
189 | WakeAllConditionVariable(&data_.cond_); |
190 | } |
191 | |
192 | } // namespace bin |
193 | } // namespace dart |
194 | |
195 | #endif // defined(HOST_OS_WINDOWS) |
196 | |