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