| 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 "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) | |
| OLD | NEW |