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 |