Index: runtime/platform/thread_win.cc |
diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc |
index e8be678cb6d0a1563aa38995f136ea9821cd4c91..d3712d299677cd600627b26835e0936528df5b3e 100644 |
--- a/runtime/platform/thread_win.cc |
+++ b/runtime/platform/thread_win.cc |
@@ -39,12 +39,24 @@ static unsigned int __stdcall ThreadEntry(void* data_ptr) { |
uword parameter = data->parameter(); |
delete data; |
+ ASSERT(ThreadInlineImpl::thread_id_key != Thread::kUnsetThreadLocalKey); |
+ |
+ ThreadId thread_id = ThreadInlineImpl::CreateThreadId(); |
+ // Set thread ID in TLS. |
+ Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, |
+ reinterpret_cast<DWORD>(thread_id)); |
+ MonitorData::GetMonitorWaitDataForThread(); |
+ |
// Call the supplied thread start function handing it its parameters. |
function(parameter); |
// Clean up the monitor wait data for this thread. |
MonitorWaitData::ThreadExit(); |
+ // Clear thread ID in TLS. |
+ Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, NULL); |
+ ThreadInlineImpl::DestroyThreadId(thread_id); |
+ |
return 0; |
} |
@@ -65,6 +77,27 @@ int Thread::Start(ThreadStartFunction function, uword parameter) { |
} |
+ThreadId ThreadInlineImpl::CreateThreadId() { |
+ // Create an ID for this thread that can be shared with other threads. |
+ HANDLE thread_id = OpenThread(THREAD_GET_CONTEXT | |
+ THREAD_SUSPEND_RESUME | |
+ THREAD_QUERY_INFORMATION, |
+ false, |
+ GetCurrentThreadId()); |
+ ASSERT(thread_id != NULL); |
+ return thread_id; |
+} |
+ |
+ |
+void ThreadInlineImpl::DestroyThreadId(ThreadId thread_id) { |
+ ASSERT(thread_id != NULL); |
+ // Destroy thread ID. |
+ CloseHandle(thread_id); |
+} |
+ |
+ |
+ThreadLocalKey ThreadInlineImpl::thread_id_key = Thread::kUnsetThreadLocalKey; |
+ |
ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; |
@@ -92,6 +125,44 @@ intptr_t Thread::GetMaxStackSize() { |
} |
+ThreadId Thread::GetCurrentThreadId() { |
+ ThreadId id = reinterpret_cast<ThreadId>( |
+ Thread::GetThreadLocal(ThreadInlineImpl::thread_id_key)); |
+ ASSERT(id != NULL); |
+ return id; |
+} |
+ |
+ |
+void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) { |
+ static const int64_t kTimeEpoc = 116444736000000000LL; |
+ static const int64_t kTimeScaler = 10; // 100 ns to us. |
+ // Although win32 uses 64-bit integers for representing timestamps, |
+ // these are packed into a FILETIME structure. The FILETIME |
+ // structure is just a struct representing a 64-bit integer. The |
+ // TimeStamp union allows access to both a FILETIME and an integer |
+ // representation of the timestamp. The Windows timestamp is in |
+ // 100-nanosecond intervals since January 1, 1601. |
+ union TimeStamp { |
+ FILETIME ft_; |
+ int64_t t_; |
+ }; |
+ ASSERT(cpu_usage != NULL); |
+ TimeStamp created; |
+ TimeStamp exited; |
+ TimeStamp kernel; |
+ TimeStamp user; |
+ BOOL result = GetThreadTimes(thread_id, |
+ &created.ft_, |
+ &exited.ft_, |
+ &kernel.ft_, |
+ &user.ft_); |
+ if (!result) { |
+ FATAL1("GetThreadCpuUsage failed %d\n", GetLastError()); |
+ } |
+ *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler; |
+} |
+ |
+ |
void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { |
ASSERT(key != kUnsetThreadLocalKey); |
BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); |
@@ -241,6 +312,8 @@ void MonitorData::SignalAndRemoveFirstWaiter() { |
} else { |
waiters_head_ = waiters_head_->next_; |
} |
+ // Clear next. |
+ first->next_ = NULL; |
// Signal event. |
BOOL result = SetEvent(first->event_); |
if (result == 0) { |
@@ -259,11 +332,16 @@ void MonitorData::SignalAndRemoveAllWaiters() { |
waiters_head_ = waiters_tail_ = NULL; |
// Iterate and signal all events. |
while (current != NULL) { |
+ // Copy next. |
+ MonitorWaitData* next = current->next_; |
+ // Clear next. |
+ current->next_ = NULL; |
+ // Signal event. |
BOOL result = SetEvent(current->event_); |
if (result == 0) { |
FATAL1("Failed to set event for NotifyAll %d", GetLastError()); |
} |
- current = current->next_; |
+ current = next; |
} |
LeaveCriticalSection(&waiters_cs_); |
} |
@@ -272,11 +350,8 @@ void MonitorData::SignalAndRemoveAllWaiters() { |
MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { |
// Ensure that the thread local key for monitor wait data objects is |
// initialized. |
- EnterCriticalSection(&waiters_cs_); |
- if (MonitorWaitData::monitor_wait_data_key_ == Thread::kUnsetThreadLocalKey) { |
- MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal(); |
- } |
- LeaveCriticalSection(&waiters_cs_); |
+ ASSERT(MonitorWaitData::monitor_wait_data_key_ != |
+ Thread::kUnsetThreadLocalKey); |
// Get the MonitorWaitData object containing the event for this |
// thread from thread local storage. Create it if it does not exist. |
@@ -300,7 +375,7 @@ Monitor::WaitResult Monitor::Wait(int64_t millis) { |
Monitor::WaitResult retval = kNotified; |
// Get the wait data object containing the event to wait for. |
- MonitorWaitData* wait_data = data_.GetMonitorWaitDataForThread(); |
+ MonitorWaitData* wait_data = MonitorData::GetMonitorWaitDataForThread(); |
// Start waiting by adding the MonitorWaitData to the list of |
// waiters. |
@@ -338,6 +413,19 @@ Monitor::WaitResult Monitor::Wait(int64_t millis) { |
} |
+Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { |
+ // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. |
+ int64_t millis = micros / kMicrosecondsPerMillisecond; |
+ if ((millis * kMicrosecondsPerMillisecond) < micros) { |
+ // We've been asked to sleep for a fraction of a millisecond, |
+ // this isn't supported on Windows. Bumps milliseconds up by one |
+ // so that we never return too early. We likely return late though. |
+ millis += 1; |
+ } |
+ return Wait(millis); |
+} |
+ |
+ |
void Monitor::Notify() { |
data_.SignalAndRemoveFirstWaiter(); |
} |