| OLD | NEW |
| 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 15 matching lines...) Expand all Loading... |
| 26 uword parameter_; | 26 uword parameter_; |
| 27 | 27 |
| 28 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); | 28 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); |
| 29 }; | 29 }; |
| 30 | 30 |
| 31 | 31 |
| 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(); | 42 MonitorData::GetMonitorWaitDataForThread(); |
| 49 | 43 |
| 50 // Call the supplied thread start function handing it its parameters. | 44 // Call the supplied thread start function handing it its parameters. |
| 51 function(parameter); | 45 function(parameter); |
| 52 | 46 |
| 53 // Clean up the monitor wait data for this thread. | 47 // Clean up the monitor wait data for this thread. |
| 54 MonitorWaitData::ThreadExit(); | 48 MonitorWaitData::ThreadExit(); |
| 55 | 49 |
| 56 // Clear thread ID in TLS. | |
| 57 Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, NULL); | |
| 58 ThreadInlineImpl::DestroyThreadId(thread_id); | |
| 59 | |
| 60 return 0; | 50 return 0; |
| 61 } | 51 } |
| 62 | 52 |
| 63 | 53 |
| 64 int Thread::Start(ThreadStartFunction function, uword parameter) { | 54 int Thread::Start(ThreadStartFunction function, uword parameter) { |
| 65 ThreadStartData* start_data = new ThreadStartData(function, parameter); | 55 ThreadStartData* start_data = new ThreadStartData(function, parameter); |
| 66 uint32_t tid; | 56 uint32_t tid; |
| 67 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(), | 57 uintptr_t thread = _beginthreadex(NULL, Thread::GetMaxStackSize(), |
| 68 ThreadEntry, start_data, 0, &tid); | 58 ThreadEntry, start_data, 0, &tid); |
| 69 if (thread == -1L || thread == 0) { | 59 if (thread == -1L || thread == 0) { |
| 70 #ifdef DEBUG | 60 #ifdef DEBUG |
| 71 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); | 61 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); |
| 72 #endif | 62 #endif |
| 73 return errno; | 63 return errno; |
| 74 } | 64 } |
| 75 | 65 |
| 66 // Close the handle, so we don't leak the thread object. |
| 67 CloseHandle(reinterpret_cast<HANDLE>(thread)); |
| 68 |
| 76 return 0; | 69 return 0; |
| 77 } | 70 } |
| 78 | 71 |
| 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 | |
| 101 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; | 72 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; |
| 102 ThreadId Thread::kInvalidThreadId = | 73 ThreadId Thread::kInvalidThreadId = 0; |
| 103 reinterpret_cast<ThreadId>(INVALID_HANDLE_VALUE); | |
| 104 | 74 |
| 105 ThreadLocalKey Thread::CreateThreadLocal() { | 75 ThreadLocalKey Thread::CreateThreadLocal() { |
| 106 ThreadLocalKey key = TlsAlloc(); | 76 ThreadLocalKey key = TlsAlloc(); |
| 107 if (key == kUnsetThreadLocalKey) { | 77 if (key == kUnsetThreadLocalKey) { |
| 108 FATAL1("TlsAlloc failed %d", GetLastError()); | 78 FATAL1("TlsAlloc failed %d", GetLastError()); |
| 109 } | 79 } |
| 110 return key; | 80 return key; |
| 111 } | 81 } |
| 112 | 82 |
| 113 | 83 |
| 114 void Thread::DeleteThreadLocal(ThreadLocalKey key) { | 84 void Thread::DeleteThreadLocal(ThreadLocalKey key) { |
| 115 ASSERT(key != kUnsetThreadLocalKey); | 85 ASSERT(key != kUnsetThreadLocalKey); |
| 116 BOOL result = TlsFree(key); | 86 BOOL result = TlsFree(key); |
| 117 if (!result) { | 87 if (!result) { |
| 118 FATAL1("TlsFree failed %d", GetLastError()); | 88 FATAL1("TlsFree failed %d", GetLastError()); |
| 119 } | 89 } |
| 120 } | 90 } |
| 121 | 91 |
| 122 | 92 |
| 123 intptr_t Thread::GetMaxStackSize() { | 93 intptr_t Thread::GetMaxStackSize() { |
| 124 const int kStackSize = (128 * kWordSize * KB); | 94 const int kStackSize = (128 * kWordSize * KB); |
| 125 return kStackSize; | 95 return kStackSize; |
| 126 } | 96 } |
| 127 | 97 |
| 128 | 98 |
| 129 ThreadId Thread::GetCurrentThreadId() { | 99 ThreadId Thread::GetCurrentThreadId() { |
| 130 ThreadId id = reinterpret_cast<ThreadId>( | 100 return ::GetCurrentThreadId(); |
| 131 Thread::GetThreadLocal(ThreadInlineImpl::thread_id_key)); | 101 } |
| 132 ASSERT(id != NULL); | 102 |
| 133 return id; | 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; |
| 134 } | 112 } |
| 135 | 113 |
| 136 | 114 |
| 137 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { | 115 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) { |
| 138 ASSERT(sizeof(id) == sizeof(intptr_t)); | 116 ASSERT(sizeof(id) <= sizeof(intptr_t)); |
| 139 return reinterpret_cast<intptr_t>(id); | 117 return static_cast<intptr_t>(id); |
| 140 } | 118 } |
| 141 | 119 |
| 142 | 120 |
| 143 bool Thread::Compare(ThreadId a, ThreadId b) { | 121 bool Thread::Compare(ThreadId a, ThreadId b) { |
| 144 return a == b; | 122 return a == b; |
| 145 } | 123 } |
| 146 | 124 |
| 147 | 125 |
| 148 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) { | 126 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) { |
| 149 static const int64_t kTimeEpoc = 116444736000000000LL; | 127 static const int64_t kTimeEpoc = 116444736000000000LL; |
| 150 static const int64_t kTimeScaler = 10; // 100 ns to us. | 128 static const int64_t kTimeScaler = 10; // 100 ns to us. |
| 151 // Although win32 uses 64-bit integers for representing timestamps, | 129 // Although win32 uses 64-bit integers for representing timestamps, |
| 152 // these are packed into a FILETIME structure. The FILETIME | 130 // these are packed into a FILETIME structure. The FILETIME |
| 153 // structure is just a struct representing a 64-bit integer. The | 131 // structure is just a struct representing a 64-bit integer. The |
| 154 // TimeStamp union allows access to both a FILETIME and an integer | 132 // TimeStamp union allows access to both a FILETIME and an integer |
| 155 // representation of the timestamp. The Windows timestamp is in | 133 // representation of the timestamp. The Windows timestamp is in |
| 156 // 100-nanosecond intervals since January 1, 1601. | 134 // 100-nanosecond intervals since January 1, 1601. |
| 157 union TimeStamp { | 135 union TimeStamp { |
| 158 FILETIME ft_; | 136 FILETIME ft_; |
| 159 int64_t t_; | 137 int64_t t_; |
| 160 }; | 138 }; |
| 161 ASSERT(cpu_usage != NULL); | 139 ASSERT(cpu_usage != NULL); |
| 162 TimeStamp created; | 140 TimeStamp created; |
| 163 TimeStamp exited; | 141 TimeStamp exited; |
| 164 TimeStamp kernel; | 142 TimeStamp kernel; |
| 165 TimeStamp user; | 143 TimeStamp user; |
| 166 BOOL result = GetThreadTimes(thread_id, | 144 HANDLE handle = OpenThread(THREAD_QUERY_INFORMATION, false, thread_id); |
| 145 BOOL result = GetThreadTimes(handle, |
| 167 &created.ft_, | 146 &created.ft_, |
| 168 &exited.ft_, | 147 &exited.ft_, |
| 169 &kernel.ft_, | 148 &kernel.ft_, |
| 170 &user.ft_); | 149 &user.ft_); |
| 150 CloseHandle(handle); |
| 171 if (!result) { | 151 if (!result) { |
| 172 FATAL1("GetThreadCpuUsage failed %d\n", GetLastError()); | 152 FATAL1("GetThreadCpuUsage failed %d\n", GetLastError()); |
| 173 } | 153 } |
| 174 *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler; | 154 *cpu_usage = (user.t_ - kTimeEpoc) / kTimeScaler; |
| 175 } | 155 } |
| 176 | 156 |
| 177 | 157 |
| 178 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { | 158 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) { |
| 179 ASSERT(key != kUnsetThreadLocalKey); | 159 ASSERT(key != kUnsetThreadLocalKey); |
| 180 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); | 160 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 // timeout before we signal it, that object will get an extra | 430 // timeout before we signal it, that object will get an extra |
| 451 // signal. This will be treated as a spurious wake-up and is OK | 431 // signal. This will be treated as a spurious wake-up and is OK |
| 452 // since all uses of monitors should recheck the condition after a | 432 // since all uses of monitors should recheck the condition after a |
| 453 // Wait. | 433 // Wait. |
| 454 data_.SignalAndRemoveAllWaiters(); | 434 data_.SignalAndRemoveAllWaiters(); |
| 455 } | 435 } |
| 456 | 436 |
| 457 } // namespace dart | 437 } // namespace dart |
| 458 | 438 |
| 459 #endif // defined(TARGET_OS_WINDOWS) | 439 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |