OLD | NEW |
| (Empty) |
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(TARGET_OS_WINDOWS) | |
7 | |
8 #include "vm/thread.h" | |
9 | |
10 #include <process.h> // NOLINT | |
11 | |
12 #include "platform/assert.h" | |
13 #include "vm/isolate.h" | |
14 | |
15 namespace dart { | |
16 | |
17 class ThreadStartData { | |
18 public: | |
19 ThreadStartData(Thread::ThreadStartFunction function, uword parameter) | |
20 : function_(function), parameter_(parameter) {} | |
21 | |
22 Thread::ThreadStartFunction function() const { return function_; } | |
23 uword parameter() const { return parameter_; } | |
24 | |
25 private: | |
26 Thread::ThreadStartFunction function_; | |
27 uword parameter_; | |
28 | |
29 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); | |
30 }; | |
31 | |
32 | |
33 // Dispatch to the thread start function provided by the caller. This trampoline | |
34 // is used to ensure that the thread is properly destroyed if the thread just | |
35 // exits. | |
36 static unsigned int __stdcall ThreadEntry(void* data_ptr) { | |
37 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); | |
38 | |
39 Thread::ThreadStartFunction function = data->function(); | |
40 uword parameter = data->parameter(); | |
41 delete data; | |
42 | |
43 MonitorData::GetMonitorWaitDataForThread(); | |
44 | |
45 // Call the supplied thread start function handing it its parameters. | |
46 function(parameter); | |
47 | |
48 // Clean up the monitor wait data for this thread. | |
49 MonitorWaitData::ThreadExit(); | |
50 | |
51 return 0; | |
52 } | |
53 | |
54 | |
55 int Thread::Start(ThreadStartFunction function, uword parameter) { | |
56 ThreadStartData* start_data = new ThreadStartData(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 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; | |
74 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 | |
85 void Thread::DeleteThreadLocal(ThreadLocalKey key) { | |
86 ASSERT(key != kUnsetThreadLocalKey); | |
87 BOOL result = TlsFree(key); | |
88 if (!result) { | |
89 FATAL1("TlsFree failed %d", GetLastError()); | |
90 } | |
91 } | |
92 | |
93 | |
94 intptr_t Thread::GetMaxStackSize() { | |
95 const int kStackSize = (128 * kWordSize * KB); | |
96 return kStackSize; | |
97 } | |
98 | |
99 | |
100 ThreadId Thread::GetCurrentThreadId() { | |
101 return ::GetCurrentThreadId(); | |
102 } | |
103 | |
104 | |
105 bool Thread::Join(ThreadId id) { | |
106 HANDLE handle = OpenThread(SYNCHRONIZE, false, id); | |
107 if (handle == INVALID_HANDLE_VALUE) { | |
108 return false; | |
109 } | |
110 DWORD res = WaitForSingleObject(handle, INFINITE); | |
111 CloseHandle(handle); | |
112 return res == WAIT_OBJECT_0; | |
113 } | |
114 | |
115 | |
116 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { | |
117 ASSERT(sizeof(id) <= sizeof(intptr_t)); | |
118 return static_cast<intptr_t>(id); | |
119 } | |
120 | |
121 | |
122 bool Thread::Compare(ThreadId a, ThreadId b) { | |
123 return a == b; | |
124 } | |
125 | |
126 | |
127 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) { | |
128 static const int64_t kTimeEpoc = 116444736000000000LL; | |
129 static const int64_t kTimeScaler = 10; // 100 ns to us. | |
130 // Although win32 uses 64-bit integers for representing timestamps, | |
131 // these are packed into a FILETIME structure. The FILETIME | |
132 // structure is just a struct representing a 64-bit integer. The | |
133 // TimeStamp union allows access to both a FILETIME and an integer | |
134 // representation of the timestamp. The Windows timestamp is in | |
135 // 100-nanosecond intervals since January 1, 1601. | |
136 union TimeStamp { | |
137 FILETIME ft_; | |
138 int64_t t_; | |
139 }; | |
140 ASSERT(cpu_usage != NULL); | |
141 TimeStamp created; | |
142 TimeStamp exited; | |
143 TimeStamp kernel; | |
144 TimeStamp user; | |
145 HANDLE handle = OpenThread(THREAD_QUERY_INFORMATION, false, thread_id); | |
146 BOOL result = GetThreadTimes(handle, | |
147 &created.ft_, | |
148 &exited.ft_, | |
149 &kernel.ft_, | |
150 &user.ft_); | |
151 CloseHandle(handle); | |
152 if (!result) { | |
153 FATAL1("GetThreadCpuUsage failed %d\n", GetLastError()); | |
154 } | |
155 *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler; | |
156 } | |
157 | |
158 | |
159 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { | |
160 ASSERT(key != kUnsetThreadLocalKey); | |
161 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); | |
162 if (!result) { | |
163 FATAL1("TlsSetValue failed %d", GetLastError()); | |
164 } | |
165 } | |
166 | |
167 | |
168 Mutex::Mutex() { | |
169 // Allocate unnamed semaphore with initial count 1 and max count 1. | |
170 data_.semaphore_ = CreateSemaphore(NULL, 1, 1, NULL); | |
171 if (data_.semaphore_ == NULL) { | |
172 FATAL1("Mutex allocation failed %d", GetLastError()); | |
173 } | |
174 // When running with assertions enabled we do track the owner. | |
175 #if defined(DEBUG) | |
176 owner_ = NULL; | |
177 #endif // defined(DEBUG) | |
178 } | |
179 | |
180 | |
181 Mutex::~Mutex() { | |
182 CloseHandle(data_.semaphore_); | |
183 // When running with assertions enabled we do track the owner. | |
184 #if defined(DEBUG) | |
185 ASSERT(owner_ == NULL); | |
186 #endif // defined(DEBUG) | |
187 } | |
188 | |
189 | |
190 void Mutex::Lock() { | |
191 DWORD result = WaitForSingleObject(data_.semaphore_, INFINITE); | |
192 if (result != WAIT_OBJECT_0) { | |
193 FATAL1("Mutex lock failed %d", GetLastError()); | |
194 } | |
195 // When running with assertions enabled we do track the owner. | |
196 #if defined(DEBUG) | |
197 owner_ = Isolate::Current(); | |
198 #endif // defined(DEBUG) | |
199 } | |
200 | |
201 | |
202 bool Mutex::TryLock() { | |
203 // Attempt to pass the semaphore but return immediately. | |
204 DWORD result = WaitForSingleObject(data_.semaphore_, 0); | |
205 if (result == WAIT_OBJECT_0) { | |
206 // When running with assertions enabled we do track the owner. | |
207 #if defined(DEBUG) | |
208 owner_ = Isolate::Current(); | |
209 #endif // defined(DEBUG) | |
210 return true; | |
211 } | |
212 if (result == WAIT_ABANDONED || result == WAIT_FAILED) { | |
213 FATAL1("Mutex try lock failed %d", GetLastError()); | |
214 } | |
215 ASSERT(result == WAIT_TIMEOUT); | |
216 return false; | |
217 } | |
218 | |
219 | |
220 void Mutex::Unlock() { | |
221 // When running with assertions enabled we do track the owner. | |
222 #if defined(DEBUG) | |
223 ASSERT(owner_ == Isolate::Current()); | |
224 owner_ = NULL; | |
225 #endif // defined(DEBUG) | |
226 BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL); | |
227 if (result == 0) { | |
228 FATAL1("Mutex unlock failed %d", GetLastError()); | |
229 } | |
230 } | |
231 | |
232 | |
233 ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = | |
234 Thread::kUnsetThreadLocalKey; | |
235 | |
236 | |
237 Monitor::Monitor() { | |
238 InitializeCriticalSection(&data_.cs_); | |
239 InitializeCriticalSection(&data_.waiters_cs_); | |
240 data_.waiters_head_ = NULL; | |
241 data_.waiters_tail_ = NULL; | |
242 } | |
243 | |
244 | |
245 Monitor::~Monitor() { | |
246 DeleteCriticalSection(&data_.cs_); | |
247 DeleteCriticalSection(&data_.waiters_cs_); | |
248 } | |
249 | |
250 | |
251 void Monitor::Enter() { | |
252 EnterCriticalSection(&data_.cs_); | |
253 } | |
254 | |
255 | |
256 void Monitor::Exit() { | |
257 LeaveCriticalSection(&data_.cs_); | |
258 } | |
259 | |
260 | |
261 void MonitorWaitData::ThreadExit() { | |
262 if (MonitorWaitData::monitor_wait_data_key_ != | |
263 Thread::kUnsetThreadLocalKey) { | |
264 uword raw_wait_data = | |
265 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | |
266 if (raw_wait_data != 0) { | |
267 MonitorWaitData* wait_data = | |
268 reinterpret_cast<MonitorWaitData*>(raw_wait_data); | |
269 delete wait_data; | |
270 } | |
271 } | |
272 } | |
273 | |
274 | |
275 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { | |
276 // Add the MonitorWaitData object to the list of objects waiting for | |
277 // this monitor. | |
278 EnterCriticalSection(&waiters_cs_); | |
279 if (waiters_tail_ == NULL) { | |
280 ASSERT(waiters_head_ == NULL); | |
281 waiters_head_ = waiters_tail_ = wait_data; | |
282 } else { | |
283 waiters_tail_->next_ = wait_data; | |
284 waiters_tail_ = wait_data; | |
285 } | |
286 LeaveCriticalSection(&waiters_cs_); | |
287 } | |
288 | |
289 | |
290 void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) { | |
291 // Remove the MonitorWaitData object from the list of objects | |
292 // waiting for this monitor. | |
293 EnterCriticalSection(&waiters_cs_); | |
294 MonitorWaitData* previous = NULL; | |
295 MonitorWaitData* current = waiters_head_; | |
296 while (current != NULL) { | |
297 if (current == wait_data) { | |
298 if (waiters_head_ == waiters_tail_) { | |
299 waiters_head_ = waiters_tail_ = NULL; | |
300 } else if (current == waiters_head_) { | |
301 waiters_head_ = waiters_head_->next_; | |
302 } else if (current == waiters_tail_) { | |
303 ASSERT(previous != NULL); | |
304 waiters_tail_ = previous; | |
305 previous->next_ = NULL; | |
306 } else { | |
307 ASSERT(previous != NULL); | |
308 previous->next_ = current->next_; | |
309 } | |
310 // Clear next. | |
311 wait_data->next_ = NULL; | |
312 break; | |
313 } | |
314 previous = current; | |
315 current = current->next_; | |
316 } | |
317 LeaveCriticalSection(&waiters_cs_); | |
318 } | |
319 | |
320 | |
321 void MonitorData::SignalAndRemoveFirstWaiter() { | |
322 EnterCriticalSection(&waiters_cs_); | |
323 MonitorWaitData* first = waiters_head_; | |
324 if (first != NULL) { | |
325 // Remove from list. | |
326 if (waiters_head_ == waiters_tail_) { | |
327 waiters_tail_ = waiters_head_ = NULL; | |
328 } else { | |
329 waiters_head_ = waiters_head_->next_; | |
330 } | |
331 // Clear next. | |
332 first->next_ = NULL; | |
333 // Signal event. | |
334 BOOL result = SetEvent(first->event_); | |
335 if (result == 0) { | |
336 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); | |
337 } | |
338 } | |
339 LeaveCriticalSection(&waiters_cs_); | |
340 } | |
341 | |
342 | |
343 void MonitorData::SignalAndRemoveAllWaiters() { | |
344 EnterCriticalSection(&waiters_cs_); | |
345 // Extract list to signal. | |
346 MonitorWaitData* current = waiters_head_; | |
347 // Clear list. | |
348 waiters_head_ = waiters_tail_ = NULL; | |
349 // Iterate and signal all events. | |
350 while (current != NULL) { | |
351 // Copy next. | |
352 MonitorWaitData* next = current->next_; | |
353 // Clear next. | |
354 current->next_ = NULL; | |
355 // Signal event. | |
356 BOOL result = SetEvent(current->event_); | |
357 if (result == 0) { | |
358 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); | |
359 } | |
360 current = next; | |
361 } | |
362 LeaveCriticalSection(&waiters_cs_); | |
363 } | |
364 | |
365 | |
366 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { | |
367 // Ensure that the thread local key for monitor wait data objects is | |
368 // initialized. | |
369 ASSERT(MonitorWaitData::monitor_wait_data_key_ != | |
370 Thread::kUnsetThreadLocalKey); | |
371 | |
372 // Get the MonitorWaitData object containing the event for this | |
373 // thread from thread local storage. Create it if it does not exist. | |
374 uword raw_wait_data = | |
375 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | |
376 MonitorWaitData* wait_data = NULL; | |
377 if (raw_wait_data == 0) { | |
378 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); | |
379 wait_data = new MonitorWaitData(event); | |
380 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, | |
381 reinterpret_cast<uword>(wait_data)); | |
382 } else { | |
383 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); | |
384 wait_data->next_ = NULL; | |
385 } | |
386 return wait_data; | |
387 } | |
388 | |
389 | |
390 Monitor::WaitResult Monitor::Wait(int64_t millis) { | |
391 Monitor::WaitResult retval = kNotified; | |
392 | |
393 // Get the wait data object containing the event to wait for. | |
394 MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread(); | |
395 | |
396 // Start waiting by adding the MonitorWaitData to the list of | |
397 // waiters. | |
398 data_.AddWaiter(wait_data); | |
399 | |
400 // Leave the monitor critical section while waiting. | |
401 LeaveCriticalSection(&data_.cs_); | |
402 | |
403 // Perform the actual wait on the event. | |
404 DWORD result = WAIT_FAILED; | |
405 if (millis == 0) { | |
406 // Wait forever for a Notify or a NotifyAll event. | |
407 result = WaitForSingleObject(wait_data->event_, INFINITE); | |
408 if (result == WAIT_FAILED) { | |
409 FATAL1("Monitor::Wait failed %d", GetLastError()); | |
410 } | |
411 } else { | |
412 // Wait for the given period of time for a Notify or a NotifyAll | |
413 // event. | |
414 result = WaitForSingleObject(wait_data->event_, millis); | |
415 if (result == WAIT_FAILED) { | |
416 FATAL1("Monitor::Wait with timeout failed %d", GetLastError()); | |
417 } | |
418 if (result == WAIT_TIMEOUT) { | |
419 // No longer waiting. Remove from the list of waiters. | |
420 data_.RemoveWaiter(wait_data); | |
421 retval = kTimedOut; | |
422 } | |
423 } | |
424 | |
425 // Reacquire the monitor critical section before continuing. | |
426 EnterCriticalSection(&data_.cs_); | |
427 | |
428 return retval; | |
429 } | |
430 | |
431 | |
432 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { | |
433 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. | |
434 int64_t millis = micros / kMicrosecondsPerMillisecond; | |
435 if ((millis * kMicrosecondsPerMillisecond) < micros) { | |
436 // We've been asked to sleep for a fraction of a millisecond, | |
437 // this isn't supported on Windows. Bumps milliseconds up by one | |
438 // so that we never return too early. We likely return late though. | |
439 millis += 1; | |
440 } | |
441 return Wait(millis); | |
442 } | |
443 | |
444 | |
445 void Monitor::Notify() { | |
446 data_.SignalAndRemoveFirstWaiter(); | |
447 } | |
448 | |
449 | |
450 void Monitor::NotifyAll() { | |
451 // If one of the objects in the list of waiters wakes because of a | |
452 // timeout before we signal it, that object will get an extra | |
453 // signal. This will be treated as a spurious wake-up and is OK | |
454 // since all uses of monitors should recheck the condition after a | |
455 // Wait. | |
456 data_.SignalAndRemoveAllWaiters(); | |
457 } | |
458 | |
459 } // namespace dart | |
460 | |
461 #endif // defined(TARGET_OS_WINDOWS) | |
OLD | NEW |