Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: runtime/vm/thread_win.cc

Issue 796063006: Rename Thread -> OSThread. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/thread_win.h ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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)
OLDNEW
« no previous file with comments | « runtime/vm/thread_win.h ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698