| 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 |