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

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

Issue 25909002: Sampling profiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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/platform/thread_win.h ('k') | runtime/vm/dart.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_WINDOWS) 6 #if defined(TARGET_OS_WINDOWS)
7 7
8 #include "platform/thread.h" 8 #include "platform/thread.h"
9 9
10 #include <process.h> // NOLINT 10 #include <process.h> // NOLINT
(...skipping 21 matching lines...) Expand all
32 // Dispatch to the thread start function provided by the caller. This trampoline 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 33 // is used to ensure that the thread is properly destroyed if the thread just
34 // exits. 34 // exits.
35 static unsigned int __stdcall ThreadEntry(void* data_ptr) { 35 static unsigned int __stdcall ThreadEntry(void* data_ptr) {
36 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); 36 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
37 37
38 Thread::ThreadStartFunction function = data->function(); 38 Thread::ThreadStartFunction function = data->function();
39 uword parameter = data->parameter(); 39 uword parameter = data->parameter();
40 delete data; 40 delete data;
41 41
42 ASSERT(ThreadInlineImpl::thread_id_key != Thread::kUnsetThreadLocalKey);
43
44 ThreadId thread_id = ThreadInlineImpl::CreateThreadId();
45 // Set thread ID in TLS.
46 Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key,
47 reinterpret_cast<DWORD>(thread_id));
48 MonitorData::GetMonitorWaitDataForThread();
49
42 // Call the supplied thread start function handing it its parameters. 50 // Call the supplied thread start function handing it its parameters.
43 function(parameter); 51 function(parameter);
44 52
45 // Clean up the monitor wait data for this thread. 53 // Clean up the monitor wait data for this thread.
46 MonitorWaitData::ThreadExit(); 54 MonitorWaitData::ThreadExit();
47 55
56 // Clear thread ID in TLS.
57 Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, NULL);
58 ThreadInlineImpl::DestroyThreadId(thread_id);
59
48 return 0; 60 return 0;
49 } 61 }
50 62
51 63
52 int Thread::Start(ThreadStartFunction function, uword parameter) { 64 int Thread::Start(ThreadStartFunction function, uword parameter) {
53 ThreadStartData* start_data = new ThreadStartData(function, parameter); 65 ThreadStartData* start_data = new ThreadStartData(function, parameter);
54 uint32_t tid; 66 uint32_t tid;
55 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(), 67 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(),
56 ThreadEntry, start_data, 0, &tid); 68 ThreadEntry, start_data, 0, &tid);
57 if (thread == -1L || thread == 0) { 69 if (thread == -1L || thread == 0) {
58 #ifdef DEBUG 70 #ifdef DEBUG
59 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); 71 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno));
60 #endif 72 #endif
61 return errno; 73 return errno;
62 } 74 }
63 75
64 return 0; 76 return 0;
65 } 77 }
66 78
67 79
80 ThreadId ThreadInlineImpl::CreateThreadId() {
81 // Create an ID for this thread that can be shared with other threads.
82 HANDLE thread_id = OpenThread(THREAD_GET_CONTEXT |
83 THREAD_SUSPEND_RESUME |
84 THREAD_QUERY_INFORMATION,
85 false,
86 GetCurrentThreadId());
87 ASSERT(thread_id != NULL);
88 return thread_id;
89 }
90
91
92 void ThreadInlineImpl::DestroyThreadId(ThreadId thread_id) {
93 ASSERT(thread_id != NULL);
94 // Destroy thread ID.
95 CloseHandle(thread_id);
96 }
97
98
99 ThreadLocalKey ThreadInlineImpl::thread_id_key = Thread::kUnsetThreadLocalKey;
100
68 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; 101 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
69 102
70 103
71 ThreadLocalKey Thread::CreateThreadLocal() { 104 ThreadLocalKey Thread::CreateThreadLocal() {
72 ThreadLocalKey key = TlsAlloc(); 105 ThreadLocalKey key = TlsAlloc();
73 if (key == kUnsetThreadLocalKey) { 106 if (key == kUnsetThreadLocalKey) {
74 FATAL1("TlsAlloc failed %d", GetLastError()); 107 FATAL1("TlsAlloc failed %d", GetLastError());
75 } 108 }
76 return key; 109 return key;
77 } 110 }
78 111
79 112
80 void Thread::DeleteThreadLocal(ThreadLocalKey key) { 113 void Thread::DeleteThreadLocal(ThreadLocalKey key) {
81 ASSERT(key != kUnsetThreadLocalKey); 114 ASSERT(key != kUnsetThreadLocalKey);
82 BOOL result = TlsFree(key); 115 BOOL result = TlsFree(key);
83 if (!result) { 116 if (!result) {
84 FATAL1("TlsFree failed %d", GetLastError()); 117 FATAL1("TlsFree failed %d", GetLastError());
85 } 118 }
86 } 119 }
87 120
88 121
89 intptr_t Thread::GetMaxStackSize() { 122 intptr_t Thread::GetMaxStackSize() {
90 const int kStackSize = (128 * kWordSize * KB); 123 const int kStackSize = (128 * kWordSize * KB);
91 return kStackSize; 124 return kStackSize;
92 } 125 }
93 126
94 127
128 ThreadId Thread::GetCurrentThreadId() {
129 ThreadId id = reinterpret_cast<ThreadId>(
130 Thread::GetThreadLocal(ThreadInlineImpl::thread_id_key));
131 ASSERT(id != NULL);
132 return id;
133 }
134
135
136 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) {
137 static const int64_t kTimeEpoc = 116444736000000000LL;
138 static const int64_t kTimeScaler = 10; // 100 ns to us.
139 // Although win32 uses 64-bit integers for representing timestamps,
140 // these are packed into a FILETIME structure. The FILETIME
141 // structure is just a struct representing a 64-bit integer. The
142 // TimeStamp union allows access to both a FILETIME and an integer
143 // representation of the timestamp. The Windows timestamp is in
144 // 100-nanosecond intervals since January 1, 1601.
145 union TimeStamp {
146 FILETIME ft_;
147 int64_t t_;
148 };
149 ASSERT(cpu_usage != NULL);
150 TimeStamp created;
151 TimeStamp exited;
152 TimeStamp kernel;
153 TimeStamp user;
154 BOOL result = GetThreadTimes(thread_id,
155 &created.ft_,
156 &exited.ft_,
157 &kernel.ft_,
158 &user.ft_);
159 if (!result) {
160 FATAL1("GetThreadCpuUsage failed %d\n", GetLastError());
161 }
162 *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler;
163 }
164
165
95 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { 166 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
96 ASSERT(key != kUnsetThreadLocalKey); 167 ASSERT(key != kUnsetThreadLocalKey);
97 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); 168 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value));
98 if (!result) { 169 if (!result) {
99 FATAL1("TlsSetValue failed %d", GetLastError()); 170 FATAL1("TlsSetValue failed %d", GetLastError());
100 } 171 }
101 } 172 }
102 173
103 174
104 Mutex::Mutex() { 175 Mutex::Mutex() {
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 void MonitorData::SignalAndRemoveFirstWaiter() { 305 void MonitorData::SignalAndRemoveFirstWaiter() {
235 EnterCriticalSection(&waiters_cs_); 306 EnterCriticalSection(&waiters_cs_);
236 MonitorWaitData* first = waiters_head_; 307 MonitorWaitData* first = waiters_head_;
237 if (first != NULL) { 308 if (first != NULL) {
238 // Remove from list. 309 // Remove from list.
239 if (waiters_head_ == waiters_tail_) { 310 if (waiters_head_ == waiters_tail_) {
240 waiters_tail_ = waiters_head_ = NULL; 311 waiters_tail_ = waiters_head_ = NULL;
241 } else { 312 } else {
242 waiters_head_ = waiters_head_->next_; 313 waiters_head_ = waiters_head_->next_;
243 } 314 }
315 // Clear next.
316 first->next_ = NULL;
244 // Signal event. 317 // Signal event.
245 BOOL result = SetEvent(first->event_); 318 BOOL result = SetEvent(first->event_);
246 if (result == 0) { 319 if (result == 0) {
247 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); 320 FATAL1("Monitor::Notify failed to signal event %d", GetLastError());
248 } 321 }
249 } 322 }
250 LeaveCriticalSection(&waiters_cs_); 323 LeaveCriticalSection(&waiters_cs_);
251 } 324 }
252 325
253 326
254 void MonitorData::SignalAndRemoveAllWaiters() { 327 void MonitorData::SignalAndRemoveAllWaiters() {
255 EnterCriticalSection(&waiters_cs_); 328 EnterCriticalSection(&waiters_cs_);
256 // Extract list to signal. 329 // Extract list to signal.
257 MonitorWaitData* current = waiters_head_; 330 MonitorWaitData* current = waiters_head_;
258 // Clear list. 331 // Clear list.
259 waiters_head_ = waiters_tail_ = NULL; 332 waiters_head_ = waiters_tail_ = NULL;
260 // Iterate and signal all events. 333 // Iterate and signal all events.
261 while (current != NULL) { 334 while (current != NULL) {
335 // Copy next.
336 MonitorWaitData* next = current->next_;
337 // Clear next.
338 current->next_ = NULL;
339 // Signal event.
262 BOOL result = SetEvent(current->event_); 340 BOOL result = SetEvent(current->event_);
263 if (result == 0) { 341 if (result == 0) {
264 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); 342 FATAL1("Failed to set event for NotifyAll %d", GetLastError());
265 } 343 }
266 current = current->next_; 344 current = next;
267 } 345 }
268 LeaveCriticalSection(&waiters_cs_); 346 LeaveCriticalSection(&waiters_cs_);
269 } 347 }
270 348
271 349
272 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { 350 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() {
273 // Ensure that the thread local key for monitor wait data objects is 351 // Ensure that the thread local key for monitor wait data objects is
274 // initialized. 352 // initialized.
275 EnterCriticalSection(&waiters_cs_); 353 ASSERT(MonitorWaitData::monitor_wait_data_key_ !=
276 if (MonitorWaitData::monitor_wait_data_key_ == Thread::kUnsetThreadLocalKey) { 354 Thread::kUnsetThreadLocalKey);
277 MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal();
278 }
279 LeaveCriticalSection(&waiters_cs_);
280 355
281 // Get the MonitorWaitData object containing the event for this 356 // Get the MonitorWaitData object containing the event for this
282 // thread from thread local storage. Create it if it does not exist. 357 // thread from thread local storage. Create it if it does not exist.
283 uword raw_wait_data = 358 uword raw_wait_data =
284 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); 359 Thread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
285 MonitorWaitData* wait_data = NULL; 360 MonitorWaitData* wait_data = NULL;
286 if (raw_wait_data == 0) { 361 if (raw_wait_data == 0) {
287 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); 362 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
288 wait_data = new MonitorWaitData(event); 363 wait_data = new MonitorWaitData(event);
289 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, 364 Thread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_,
290 reinterpret_cast<uword>(wait_data)); 365 reinterpret_cast<uword>(wait_data));
291 } else { 366 } else {
292 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); 367 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data);
293 wait_data->next_ = NULL; 368 wait_data->next_ = NULL;
294 } 369 }
295 return wait_data; 370 return wait_data;
296 } 371 }
297 372
298 373
299 Monitor::WaitResult Monitor::Wait(int64_t millis) { 374 Monitor::WaitResult Monitor::Wait(int64_t millis) {
300 Monitor::WaitResult retval = kNotified; 375 Monitor::WaitResult retval = kNotified;
301 376
302 // Get the wait data object containing the event to wait for. 377 // Get the wait data object containing the event to wait for.
303 MonitorWaitData* wait_data = data_.GetMonitorWaitDataForThread(); 378 MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread();
304 379
305 // Start waiting by adding the MonitorWaitData to the list of 380 // Start waiting by adding the MonitorWaitData to the list of
306 // waiters. 381 // waiters.
307 data_.AddWaiter(wait_data); 382 data_.AddWaiter(wait_data);
308 383
309 // Leave the monitor critical section while waiting. 384 // Leave the monitor critical section while waiting.
310 LeaveCriticalSection(&data_.cs_); 385 LeaveCriticalSection(&data_.cs_);
311 386
312 // Perform the actual wait on the event. 387 // Perform the actual wait on the event.
313 DWORD result = WAIT_FAILED; 388 DWORD result = WAIT_FAILED;
(...skipping 17 matching lines...) Expand all
331 } 406 }
332 } 407 }
333 408
334 // Reacquire the monitor critical section before continuing. 409 // Reacquire the monitor critical section before continuing.
335 EnterCriticalSection(&data_.cs_); 410 EnterCriticalSection(&data_.cs_);
336 411
337 return retval; 412 return retval;
338 } 413 }
339 414
340 415
416 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
417 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows.
418 int64_t millis = micros / kMicrosecondsPerMillisecond;
419 if ((millis * kMicrosecondsPerMillisecond) < micros) {
420 // We've been asked to sleep for a fraction of a millisecond,
421 // this isn't supported on Windows. Bumps milliseconds up by one
422 // so that we never return too early. We likely return late though.
423 millis += 1;
424 }
425 return Wait(millis);
426 }
427
428
341 void Monitor::Notify() { 429 void Monitor::Notify() {
342 data_.SignalAndRemoveFirstWaiter(); 430 data_.SignalAndRemoveFirstWaiter();
343 } 431 }
344 432
345 433
346 void Monitor::NotifyAll() { 434 void Monitor::NotifyAll() {
347 // If one of the objects in the list of waiters wakes because of a 435 // If one of the objects in the list of waiters wakes because of a
348 // timeout before we signal it, that object will get an extra 436 // timeout before we signal it, that object will get an extra
349 // signal. This will be treated as a spurious wake-up and is OK 437 // signal. This will be treated as a spurious wake-up and is OK
350 // since all uses of monitors should recheck the condition after a 438 // since all uses of monitors should recheck the condition after a
351 // Wait. 439 // Wait.
352 data_.SignalAndRemoveAllWaiters(); 440 data_.SignalAndRemoveAllWaiters();
353 } 441 }
354 442
355 } // namespace dart 443 } // namespace dart
356 444
357 #endif // defined(TARGET_OS_WINDOWS) 445 #endif // defined(TARGET_OS_WINDOWS)
OLDNEW
« no previous file with comments | « runtime/platform/thread_win.h ('k') | runtime/vm/dart.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698