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

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

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

Powered by Google App Engine
This is Rietveld 408576698