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" // NOLINT | 5 #include "platform/globals.h" // NOLINT |
6 #if defined(HOST_OS_WINDOWS) | 6 #if defined(HOST_OS_WINDOWS) |
7 | 7 |
8 #include "vm/growable_array.h" | 8 #include "vm/growable_array.h" |
9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
10 #include "vm/os_thread.h" | 10 #include "vm/os_thread.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 uword parameter() const { return parameter_; } | 31 uword parameter() const { return parameter_; } |
32 | 32 |
33 private: | 33 private: |
34 const char* name_; | 34 const char* name_; |
35 OSThread::ThreadStartFunction function_; | 35 OSThread::ThreadStartFunction function_; |
36 uword parameter_; | 36 uword parameter_; |
37 | 37 |
38 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); | 38 DISALLOW_COPY_AND_ASSIGN(ThreadStartData); |
39 }; | 39 }; |
40 | 40 |
41 | |
42 // Dispatch to the thread start function provided by the caller. This trampoline | 41 // Dispatch to the thread start function provided by the caller. This trampoline |
43 // is used to ensure that the thread is properly destroyed if the thread just | 42 // is used to ensure that the thread is properly destroyed if the thread just |
44 // exits. | 43 // exits. |
45 static unsigned int __stdcall ThreadEntry(void* data_ptr) { | 44 static unsigned int __stdcall ThreadEntry(void* data_ptr) { |
46 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); | 45 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr); |
47 | 46 |
48 const char* name = data->name(); | 47 const char* name = data->name(); |
49 OSThread::ThreadStartFunction function = data->function(); | 48 OSThread::ThreadStartFunction function = data->function(); |
50 uword parameter = data->parameter(); | 49 uword parameter = data->parameter(); |
51 delete data; | 50 delete data; |
52 | 51 |
53 MonitorData::GetMonitorWaitDataForThread(); | 52 MonitorData::GetMonitorWaitDataForThread(); |
54 | 53 |
55 // Create new OSThread object and set as TLS for new thread. | 54 // Create new OSThread object and set as TLS for new thread. |
56 OSThread* thread = OSThread::CreateOSThread(); | 55 OSThread* thread = OSThread::CreateOSThread(); |
57 if (thread != NULL) { | 56 if (thread != NULL) { |
58 OSThread::SetCurrent(thread); | 57 OSThread::SetCurrent(thread); |
59 thread->set_name(name); | 58 thread->set_name(name); |
60 | 59 |
61 // Call the supplied thread start function handing it its parameters. | 60 // Call the supplied thread start function handing it its parameters. |
62 function(parameter); | 61 function(parameter); |
63 } | 62 } |
64 | 63 |
65 // Clean up the monitor wait data for this thread. | 64 // Clean up the monitor wait data for this thread. |
66 MonitorWaitData::ThreadExit(); | 65 MonitorWaitData::ThreadExit(); |
67 | 66 |
68 return 0; | 67 return 0; |
69 } | 68 } |
70 | 69 |
71 | |
72 int OSThread::Start(const char* name, | 70 int OSThread::Start(const char* name, |
73 ThreadStartFunction function, | 71 ThreadStartFunction function, |
74 uword parameter) { | 72 uword parameter) { |
75 ThreadStartData* start_data = new ThreadStartData(name, function, parameter); | 73 ThreadStartData* start_data = new ThreadStartData(name, function, parameter); |
76 uint32_t tid; | 74 uint32_t tid; |
77 uintptr_t thread = _beginthreadex(NULL, OSThread::GetMaxStackSize(), | 75 uintptr_t thread = _beginthreadex(NULL, OSThread::GetMaxStackSize(), |
78 ThreadEntry, start_data, 0, &tid); | 76 ThreadEntry, start_data, 0, &tid); |
79 if (thread == -1L || thread == 0) { | 77 if (thread == -1L || thread == 0) { |
80 #ifdef DEBUG | 78 #ifdef DEBUG |
81 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); | 79 fprintf(stderr, "_beginthreadex error: %d (%s)\n", errno, strerror(errno)); |
82 #endif | 80 #endif |
83 return errno; | 81 return errno; |
84 } | 82 } |
85 | 83 |
86 // Close the handle, so we don't leak the thread object. | 84 // Close the handle, so we don't leak the thread object. |
87 CloseHandle(reinterpret_cast<HANDLE>(thread)); | 85 CloseHandle(reinterpret_cast<HANDLE>(thread)); |
88 | 86 |
89 return 0; | 87 return 0; |
90 } | 88 } |
91 | 89 |
92 | |
93 const ThreadId OSThread::kInvalidThreadId = 0; | 90 const ThreadId OSThread::kInvalidThreadId = 0; |
94 const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL; | 91 const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL; |
95 | 92 |
96 | |
97 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) { | 93 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) { |
98 ThreadLocalKey key = TlsAlloc(); | 94 ThreadLocalKey key = TlsAlloc(); |
99 if (key == kUnsetThreadLocalKey) { | 95 if (key == kUnsetThreadLocalKey) { |
100 FATAL1("TlsAlloc failed %d", GetLastError()); | 96 FATAL1("TlsAlloc failed %d", GetLastError()); |
101 } | 97 } |
102 ThreadLocalData::AddThreadLocal(key, destructor); | 98 ThreadLocalData::AddThreadLocal(key, destructor); |
103 return key; | 99 return key; |
104 } | 100 } |
105 | 101 |
106 | |
107 void OSThread::DeleteThreadLocal(ThreadLocalKey key) { | 102 void OSThread::DeleteThreadLocal(ThreadLocalKey key) { |
108 ASSERT(key != kUnsetThreadLocalKey); | 103 ASSERT(key != kUnsetThreadLocalKey); |
109 BOOL result = TlsFree(key); | 104 BOOL result = TlsFree(key); |
110 if (!result) { | 105 if (!result) { |
111 FATAL1("TlsFree failed %d", GetLastError()); | 106 FATAL1("TlsFree failed %d", GetLastError()); |
112 } | 107 } |
113 ThreadLocalData::RemoveThreadLocal(key); | 108 ThreadLocalData::RemoveThreadLocal(key); |
114 } | 109 } |
115 | 110 |
116 | |
117 intptr_t OSThread::GetMaxStackSize() { | 111 intptr_t OSThread::GetMaxStackSize() { |
118 const int kStackSize = (128 * kWordSize * KB); | 112 const int kStackSize = (128 * kWordSize * KB); |
119 return kStackSize; | 113 return kStackSize; |
120 } | 114 } |
121 | 115 |
122 | |
123 ThreadId OSThread::GetCurrentThreadId() { | 116 ThreadId OSThread::GetCurrentThreadId() { |
124 return ::GetCurrentThreadId(); | 117 return ::GetCurrentThreadId(); |
125 } | 118 } |
126 | 119 |
127 | |
128 #ifndef PRODUCT | 120 #ifndef PRODUCT |
129 ThreadId OSThread::GetCurrentThreadTraceId() { | 121 ThreadId OSThread::GetCurrentThreadTraceId() { |
130 return ::GetCurrentThreadId(); | 122 return ::GetCurrentThreadId(); |
131 } | 123 } |
132 #endif // PRODUCT | 124 #endif // PRODUCT |
133 | 125 |
134 | |
135 ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) { | 126 ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) { |
136 ASSERT(thread != NULL); | 127 ASSERT(thread != NULL); |
137 // Make sure we're filling in the join id for the current thread. | 128 // Make sure we're filling in the join id for the current thread. |
138 ThreadId id = GetCurrentThreadId(); | 129 ThreadId id = GetCurrentThreadId(); |
139 ASSERT(thread->id() == id); | 130 ASSERT(thread->id() == id); |
140 // Make sure the join_id_ hasn't been set, yet. | 131 // Make sure the join_id_ hasn't been set, yet. |
141 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId); | 132 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId); |
142 HANDLE handle = OpenThread(SYNCHRONIZE, false, id); | 133 HANDLE handle = OpenThread(SYNCHRONIZE, false, id); |
143 ASSERT(handle != NULL); | 134 ASSERT(handle != NULL); |
144 #if defined(DEBUG) | 135 #if defined(DEBUG) |
145 thread->join_id_ = handle; | 136 thread->join_id_ = handle; |
146 #endif | 137 #endif |
147 return handle; | 138 return handle; |
148 } | 139 } |
149 | 140 |
150 | |
151 void OSThread::Join(ThreadJoinId id) { | 141 void OSThread::Join(ThreadJoinId id) { |
152 HANDLE handle = static_cast<HANDLE>(id); | 142 HANDLE handle = static_cast<HANDLE>(id); |
153 ASSERT(handle != NULL); | 143 ASSERT(handle != NULL); |
154 DWORD res = WaitForSingleObject(handle, INFINITE); | 144 DWORD res = WaitForSingleObject(handle, INFINITE); |
155 CloseHandle(handle); | 145 CloseHandle(handle); |
156 ASSERT(res == WAIT_OBJECT_0); | 146 ASSERT(res == WAIT_OBJECT_0); |
157 } | 147 } |
158 | 148 |
159 | |
160 intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { | 149 intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { |
161 ASSERT(sizeof(id) <= sizeof(intptr_t)); | 150 ASSERT(sizeof(id) <= sizeof(intptr_t)); |
162 return static_cast<intptr_t>(id); | 151 return static_cast<intptr_t>(id); |
163 } | 152 } |
164 | 153 |
165 | |
166 ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { | 154 ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { |
167 return static_cast<ThreadId>(id); | 155 return static_cast<ThreadId>(id); |
168 } | 156 } |
169 | 157 |
170 | |
171 bool OSThread::Compare(ThreadId a, ThreadId b) { | 158 bool OSThread::Compare(ThreadId a, ThreadId b) { |
172 return a == b; | 159 return a == b; |
173 } | 160 } |
174 | 161 |
175 | |
176 bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) { | 162 bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) { |
177 // On Windows stack limits for the current thread are available in | 163 // On Windows stack limits for the current thread are available in |
178 // the thread information block (TIB). Its fields can be accessed through | 164 // the thread information block (TIB). Its fields can be accessed through |
179 // FS segment register on x86 and GS segment register on x86_64. | 165 // FS segment register on x86 and GS segment register on x86_64. |
180 #ifdef _WIN64 | 166 #ifdef _WIN64 |
181 *upper = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackBase))); | 167 *upper = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackBase))); |
182 *lower = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackLimit))); | 168 *lower = static_cast<uword>(__readgsqword(offsetof(NT_TIB64, StackLimit))); |
183 #else | 169 #else |
184 *upper = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackBase))); | 170 *upper = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackBase))); |
185 *lower = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackLimit))); | 171 *lower = static_cast<uword>(__readfsdword(offsetof(NT_TIB, StackLimit))); |
186 #endif | 172 #endif |
187 return true; | 173 return true; |
188 } | 174 } |
189 | 175 |
190 | |
191 void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) { | 176 void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) { |
192 ASSERT(key != kUnsetThreadLocalKey); | 177 ASSERT(key != kUnsetThreadLocalKey); |
193 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); | 178 BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value)); |
194 if (!result) { | 179 if (!result) { |
195 FATAL1("TlsSetValue failed %d", GetLastError()); | 180 FATAL1("TlsSetValue failed %d", GetLastError()); |
196 } | 181 } |
197 } | 182 } |
198 | 183 |
199 | |
200 Mutex::Mutex() { | 184 Mutex::Mutex() { |
201 // Allocate unnamed semaphore with initial count 1 and max count 1. | 185 // Allocate unnamed semaphore with initial count 1 and max count 1. |
202 data_.semaphore_ = CreateSemaphore(NULL, 1, 1, NULL); | 186 data_.semaphore_ = CreateSemaphore(NULL, 1, 1, NULL); |
203 if (data_.semaphore_ == NULL) { | 187 if (data_.semaphore_ == NULL) { |
204 FATAL1("Mutex allocation failed %d", GetLastError()); | 188 FATAL1("Mutex allocation failed %d", GetLastError()); |
205 } | 189 } |
206 #if defined(DEBUG) | 190 #if defined(DEBUG) |
207 // When running with assertions enabled we do track the owner. | 191 // When running with assertions enabled we do track the owner. |
208 owner_ = OSThread::kInvalidThreadId; | 192 owner_ = OSThread::kInvalidThreadId; |
209 #endif // defined(DEBUG) | 193 #endif // defined(DEBUG) |
210 } | 194 } |
211 | 195 |
212 | |
213 Mutex::~Mutex() { | 196 Mutex::~Mutex() { |
214 CloseHandle(data_.semaphore_); | 197 CloseHandle(data_.semaphore_); |
215 #if defined(DEBUG) | 198 #if defined(DEBUG) |
216 // When running with assertions enabled we do track the owner. | 199 // When running with assertions enabled we do track the owner. |
217 ASSERT(owner_ == OSThread::kInvalidThreadId); | 200 ASSERT(owner_ == OSThread::kInvalidThreadId); |
218 #endif // defined(DEBUG) | 201 #endif // defined(DEBUG) |
219 } | 202 } |
220 | 203 |
221 | |
222 void Mutex::Lock() { | 204 void Mutex::Lock() { |
223 DWORD result = WaitForSingleObject(data_.semaphore_, INFINITE); | 205 DWORD result = WaitForSingleObject(data_.semaphore_, INFINITE); |
224 if (result != WAIT_OBJECT_0) { | 206 if (result != WAIT_OBJECT_0) { |
225 FATAL1("Mutex lock failed %d", GetLastError()); | 207 FATAL1("Mutex lock failed %d", GetLastError()); |
226 } | 208 } |
227 #if defined(DEBUG) | 209 #if defined(DEBUG) |
228 // When running with assertions enabled we do track the owner. | 210 // When running with assertions enabled we do track the owner. |
229 owner_ = OSThread::GetCurrentThreadId(); | 211 owner_ = OSThread::GetCurrentThreadId(); |
230 #endif // defined(DEBUG) | 212 #endif // defined(DEBUG) |
231 } | 213 } |
232 | 214 |
233 | |
234 bool Mutex::TryLock() { | 215 bool Mutex::TryLock() { |
235 // Attempt to pass the semaphore but return immediately. | 216 // Attempt to pass the semaphore but return immediately. |
236 DWORD result = WaitForSingleObject(data_.semaphore_, 0); | 217 DWORD result = WaitForSingleObject(data_.semaphore_, 0); |
237 if (result == WAIT_OBJECT_0) { | 218 if (result == WAIT_OBJECT_0) { |
238 #if defined(DEBUG) | 219 #if defined(DEBUG) |
239 // When running with assertions enabled we do track the owner. | 220 // When running with assertions enabled we do track the owner. |
240 owner_ = OSThread::GetCurrentThreadId(); | 221 owner_ = OSThread::GetCurrentThreadId(); |
241 #endif // defined(DEBUG) | 222 #endif // defined(DEBUG) |
242 return true; | 223 return true; |
243 } | 224 } |
244 if (result == WAIT_ABANDONED || result == WAIT_FAILED) { | 225 if (result == WAIT_ABANDONED || result == WAIT_FAILED) { |
245 FATAL1("Mutex try lock failed %d", GetLastError()); | 226 FATAL1("Mutex try lock failed %d", GetLastError()); |
246 } | 227 } |
247 ASSERT(result == WAIT_TIMEOUT); | 228 ASSERT(result == WAIT_TIMEOUT); |
248 return false; | 229 return false; |
249 } | 230 } |
250 | 231 |
251 | |
252 void Mutex::Unlock() { | 232 void Mutex::Unlock() { |
253 #if defined(DEBUG) | 233 #if defined(DEBUG) |
254 // When running with assertions enabled we do track the owner. | 234 // When running with assertions enabled we do track the owner. |
255 ASSERT(IsOwnedByCurrentThread()); | 235 ASSERT(IsOwnedByCurrentThread()); |
256 owner_ = OSThread::kInvalidThreadId; | 236 owner_ = OSThread::kInvalidThreadId; |
257 #endif // defined(DEBUG) | 237 #endif // defined(DEBUG) |
258 BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL); | 238 BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL); |
259 if (result == 0) { | 239 if (result == 0) { |
260 FATAL1("Mutex unlock failed %d", GetLastError()); | 240 FATAL1("Mutex unlock failed %d", GetLastError()); |
261 } | 241 } |
262 } | 242 } |
263 | 243 |
264 | |
265 ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = kUnsetThreadLocalKey; | 244 ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = kUnsetThreadLocalKey; |
266 | 245 |
267 | |
268 Monitor::Monitor() { | 246 Monitor::Monitor() { |
269 InitializeCriticalSection(&data_.cs_); | 247 InitializeCriticalSection(&data_.cs_); |
270 InitializeCriticalSection(&data_.waiters_cs_); | 248 InitializeCriticalSection(&data_.waiters_cs_); |
271 data_.waiters_head_ = NULL; | 249 data_.waiters_head_ = NULL; |
272 data_.waiters_tail_ = NULL; | 250 data_.waiters_tail_ = NULL; |
273 | 251 |
274 #if defined(DEBUG) | 252 #if defined(DEBUG) |
275 // When running with assertions enabled we track the owner. | 253 // When running with assertions enabled we track the owner. |
276 owner_ = OSThread::kInvalidThreadId; | 254 owner_ = OSThread::kInvalidThreadId; |
277 #endif // defined(DEBUG) | 255 #endif // defined(DEBUG) |
278 } | 256 } |
279 | 257 |
280 | |
281 Monitor::~Monitor() { | 258 Monitor::~Monitor() { |
282 #if defined(DEBUG) | 259 #if defined(DEBUG) |
283 // When running with assertions enabled we track the owner. | 260 // When running with assertions enabled we track the owner. |
284 ASSERT(owner_ == OSThread::kInvalidThreadId); | 261 ASSERT(owner_ == OSThread::kInvalidThreadId); |
285 #endif // defined(DEBUG) | 262 #endif // defined(DEBUG) |
286 | 263 |
287 DeleteCriticalSection(&data_.cs_); | 264 DeleteCriticalSection(&data_.cs_); |
288 DeleteCriticalSection(&data_.waiters_cs_); | 265 DeleteCriticalSection(&data_.waiters_cs_); |
289 } | 266 } |
290 | 267 |
291 | |
292 bool Monitor::TryEnter() { | 268 bool Monitor::TryEnter() { |
293 // Attempt to pass the semaphore but return immediately. | 269 // Attempt to pass the semaphore but return immediately. |
294 BOOL result = TryEnterCriticalSection(&data_.cs_); | 270 BOOL result = TryEnterCriticalSection(&data_.cs_); |
295 if (!result) { | 271 if (!result) { |
296 return false; | 272 return false; |
297 } | 273 } |
298 #if defined(DEBUG) | 274 #if defined(DEBUG) |
299 // When running with assertions enabled we do track the owner. | 275 // When running with assertions enabled we do track the owner. |
300 ASSERT(owner_ == OSThread::kInvalidThreadId); | 276 ASSERT(owner_ == OSThread::kInvalidThreadId); |
301 owner_ = OSThread::GetCurrentThreadId(); | 277 owner_ = OSThread::GetCurrentThreadId(); |
302 #endif // defined(DEBUG) | 278 #endif // defined(DEBUG) |
303 return true; | 279 return true; |
304 } | 280 } |
305 | 281 |
306 | |
307 void Monitor::Enter() { | 282 void Monitor::Enter() { |
308 EnterCriticalSection(&data_.cs_); | 283 EnterCriticalSection(&data_.cs_); |
309 | 284 |
310 #if defined(DEBUG) | 285 #if defined(DEBUG) |
311 // When running with assertions enabled we track the owner. | 286 // When running with assertions enabled we track the owner. |
312 ASSERT(owner_ == OSThread::kInvalidThreadId); | 287 ASSERT(owner_ == OSThread::kInvalidThreadId); |
313 owner_ = OSThread::GetCurrentThreadId(); | 288 owner_ = OSThread::GetCurrentThreadId(); |
314 #endif // defined(DEBUG) | 289 #endif // defined(DEBUG) |
315 } | 290 } |
316 | 291 |
317 | |
318 void Monitor::Exit() { | 292 void Monitor::Exit() { |
319 #if defined(DEBUG) | 293 #if defined(DEBUG) |
320 // When running with assertions enabled we track the owner. | 294 // When running with assertions enabled we track the owner. |
321 ASSERT(IsOwnedByCurrentThread()); | 295 ASSERT(IsOwnedByCurrentThread()); |
322 owner_ = OSThread::kInvalidThreadId; | 296 owner_ = OSThread::kInvalidThreadId; |
323 #endif // defined(DEBUG) | 297 #endif // defined(DEBUG) |
324 | 298 |
325 LeaveCriticalSection(&data_.cs_); | 299 LeaveCriticalSection(&data_.cs_); |
326 } | 300 } |
327 | 301 |
328 | |
329 void MonitorWaitData::ThreadExit() { | 302 void MonitorWaitData::ThreadExit() { |
330 if (MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey) { | 303 if (MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey) { |
331 uword raw_wait_data = | 304 uword raw_wait_data = |
332 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | 305 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); |
333 // Clear in case this is called a second time. | 306 // Clear in case this is called a second time. |
334 OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, 0); | 307 OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, 0); |
335 if (raw_wait_data != 0) { | 308 if (raw_wait_data != 0) { |
336 MonitorWaitData* wait_data = | 309 MonitorWaitData* wait_data = |
337 reinterpret_cast<MonitorWaitData*>(raw_wait_data); | 310 reinterpret_cast<MonitorWaitData*>(raw_wait_data); |
338 delete wait_data; | 311 delete wait_data; |
339 } | 312 } |
340 } | 313 } |
341 } | 314 } |
342 | 315 |
343 | |
344 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { | 316 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { |
345 // Add the MonitorWaitData object to the list of objects waiting for | 317 // Add the MonitorWaitData object to the list of objects waiting for |
346 // this monitor. | 318 // this monitor. |
347 EnterCriticalSection(&waiters_cs_); | 319 EnterCriticalSection(&waiters_cs_); |
348 if (waiters_tail_ == NULL) { | 320 if (waiters_tail_ == NULL) { |
349 ASSERT(waiters_head_ == NULL); | 321 ASSERT(waiters_head_ == NULL); |
350 waiters_head_ = waiters_tail_ = wait_data; | 322 waiters_head_ = waiters_tail_ = wait_data; |
351 } else { | 323 } else { |
352 waiters_tail_->next_ = wait_data; | 324 waiters_tail_->next_ = wait_data; |
353 waiters_tail_ = wait_data; | 325 waiters_tail_ = wait_data; |
354 } | 326 } |
355 LeaveCriticalSection(&waiters_cs_); | 327 LeaveCriticalSection(&waiters_cs_); |
356 } | 328 } |
357 | 329 |
358 | |
359 void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) { | 330 void MonitorData::RemoveWaiter(MonitorWaitData* wait_data) { |
360 // Remove the MonitorWaitData object from the list of objects | 331 // Remove the MonitorWaitData object from the list of objects |
361 // waiting for this monitor. | 332 // waiting for this monitor. |
362 EnterCriticalSection(&waiters_cs_); | 333 EnterCriticalSection(&waiters_cs_); |
363 MonitorWaitData* previous = NULL; | 334 MonitorWaitData* previous = NULL; |
364 MonitorWaitData* current = waiters_head_; | 335 MonitorWaitData* current = waiters_head_; |
365 while (current != NULL) { | 336 while (current != NULL) { |
366 if (current == wait_data) { | 337 if (current == wait_data) { |
367 if (waiters_head_ == waiters_tail_) { | 338 if (waiters_head_ == waiters_tail_) { |
368 waiters_head_ = waiters_tail_ = NULL; | 339 waiters_head_ = waiters_tail_ = NULL; |
(...skipping 10 matching lines...) Expand all Loading... |
379 // Clear next. | 350 // Clear next. |
380 wait_data->next_ = NULL; | 351 wait_data->next_ = NULL; |
381 break; | 352 break; |
382 } | 353 } |
383 previous = current; | 354 previous = current; |
384 current = current->next_; | 355 current = current->next_; |
385 } | 356 } |
386 LeaveCriticalSection(&waiters_cs_); | 357 LeaveCriticalSection(&waiters_cs_); |
387 } | 358 } |
388 | 359 |
389 | |
390 void MonitorData::SignalAndRemoveFirstWaiter() { | 360 void MonitorData::SignalAndRemoveFirstWaiter() { |
391 EnterCriticalSection(&waiters_cs_); | 361 EnterCriticalSection(&waiters_cs_); |
392 MonitorWaitData* first = waiters_head_; | 362 MonitorWaitData* first = waiters_head_; |
393 if (first != NULL) { | 363 if (first != NULL) { |
394 // Remove from list. | 364 // Remove from list. |
395 if (waiters_head_ == waiters_tail_) { | 365 if (waiters_head_ == waiters_tail_) { |
396 waiters_tail_ = waiters_head_ = NULL; | 366 waiters_tail_ = waiters_head_ = NULL; |
397 } else { | 367 } else { |
398 waiters_head_ = waiters_head_->next_; | 368 waiters_head_ = waiters_head_->next_; |
399 } | 369 } |
400 // Clear next. | 370 // Clear next. |
401 first->next_ = NULL; | 371 first->next_ = NULL; |
402 // Signal event. | 372 // Signal event. |
403 BOOL result = SetEvent(first->event_); | 373 BOOL result = SetEvent(first->event_); |
404 if (result == 0) { | 374 if (result == 0) { |
405 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); | 375 FATAL1("Monitor::Notify failed to signal event %d", GetLastError()); |
406 } | 376 } |
407 } | 377 } |
408 LeaveCriticalSection(&waiters_cs_); | 378 LeaveCriticalSection(&waiters_cs_); |
409 } | 379 } |
410 | 380 |
411 | |
412 void MonitorData::SignalAndRemoveAllWaiters() { | 381 void MonitorData::SignalAndRemoveAllWaiters() { |
413 EnterCriticalSection(&waiters_cs_); | 382 EnterCriticalSection(&waiters_cs_); |
414 // Extract list to signal. | 383 // Extract list to signal. |
415 MonitorWaitData* current = waiters_head_; | 384 MonitorWaitData* current = waiters_head_; |
416 // Clear list. | 385 // Clear list. |
417 waiters_head_ = waiters_tail_ = NULL; | 386 waiters_head_ = waiters_tail_ = NULL; |
418 // Iterate and signal all events. | 387 // Iterate and signal all events. |
419 while (current != NULL) { | 388 while (current != NULL) { |
420 // Copy next. | 389 // Copy next. |
421 MonitorWaitData* next = current->next_; | 390 MonitorWaitData* next = current->next_; |
422 // Clear next. | 391 // Clear next. |
423 current->next_ = NULL; | 392 current->next_ = NULL; |
424 // Signal event. | 393 // Signal event. |
425 BOOL result = SetEvent(current->event_); | 394 BOOL result = SetEvent(current->event_); |
426 if (result == 0) { | 395 if (result == 0) { |
427 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); | 396 FATAL1("Failed to set event for NotifyAll %d", GetLastError()); |
428 } | 397 } |
429 current = next; | 398 current = next; |
430 } | 399 } |
431 LeaveCriticalSection(&waiters_cs_); | 400 LeaveCriticalSection(&waiters_cs_); |
432 } | 401 } |
433 | 402 |
434 | |
435 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { | 403 MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() { |
436 // Ensure that the thread local key for monitor wait data objects is | 404 // Ensure that the thread local key for monitor wait data objects is |
437 // initialized. | 405 // initialized. |
438 ASSERT(MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey); | 406 ASSERT(MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey); |
439 | 407 |
440 // Get the MonitorWaitData object containing the event for this | 408 // Get the MonitorWaitData object containing the event for this |
441 // thread from thread local storage. Create it if it does not exist. | 409 // thread from thread local storage. Create it if it does not exist. |
442 uword raw_wait_data = | 410 uword raw_wait_data = |
443 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | 411 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); |
444 MonitorWaitData* wait_data = NULL; | 412 MonitorWaitData* wait_data = NULL; |
445 if (raw_wait_data == 0) { | 413 if (raw_wait_data == 0) { |
446 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); | 414 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); |
447 wait_data = new MonitorWaitData(event); | 415 wait_data = new MonitorWaitData(event); |
448 OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, | 416 OSThread::SetThreadLocal(MonitorWaitData::monitor_wait_data_key_, |
449 reinterpret_cast<uword>(wait_data)); | 417 reinterpret_cast<uword>(wait_data)); |
450 } else { | 418 } else { |
451 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); | 419 wait_data = reinterpret_cast<MonitorWaitData*>(raw_wait_data); |
452 wait_data->next_ = NULL; | 420 wait_data->next_ = NULL; |
453 } | 421 } |
454 return wait_data; | 422 return wait_data; |
455 } | 423 } |
456 | 424 |
457 | |
458 Monitor::WaitResult Monitor::Wait(int64_t millis) { | 425 Monitor::WaitResult Monitor::Wait(int64_t millis) { |
459 #if defined(DEBUG) | 426 #if defined(DEBUG) |
460 // When running with assertions enabled we track the owner. | 427 // When running with assertions enabled we track the owner. |
461 ASSERT(IsOwnedByCurrentThread()); | 428 ASSERT(IsOwnedByCurrentThread()); |
462 ThreadId saved_owner = owner_; | 429 ThreadId saved_owner = owner_; |
463 owner_ = OSThread::kInvalidThreadId; | 430 owner_ = OSThread::kInvalidThreadId; |
464 #endif // defined(DEBUG) | 431 #endif // defined(DEBUG) |
465 | 432 |
466 Monitor::WaitResult retval = kNotified; | 433 Monitor::WaitResult retval = kNotified; |
467 | 434 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 | 469 |
503 #if defined(DEBUG) | 470 #if defined(DEBUG) |
504 // When running with assertions enabled we track the owner. | 471 // When running with assertions enabled we track the owner. |
505 ASSERT(owner_ == OSThread::kInvalidThreadId); | 472 ASSERT(owner_ == OSThread::kInvalidThreadId); |
506 owner_ = OSThread::GetCurrentThreadId(); | 473 owner_ = OSThread::GetCurrentThreadId(); |
507 ASSERT(owner_ == saved_owner); | 474 ASSERT(owner_ == saved_owner); |
508 #endif // defined(DEBUG) | 475 #endif // defined(DEBUG) |
509 return retval; | 476 return retval; |
510 } | 477 } |
511 | 478 |
512 | |
513 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { | 479 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { |
514 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. | 480 // TODO(johnmccutchan): Investigate sub-millisecond sleep times on Windows. |
515 int64_t millis = micros / kMicrosecondsPerMillisecond; | 481 int64_t millis = micros / kMicrosecondsPerMillisecond; |
516 if ((millis * kMicrosecondsPerMillisecond) < micros) { | 482 if ((millis * kMicrosecondsPerMillisecond) < micros) { |
517 // We've been asked to sleep for a fraction of a millisecond, | 483 // We've been asked to sleep for a fraction of a millisecond, |
518 // this isn't supported on Windows. Bumps milliseconds up by one | 484 // this isn't supported on Windows. Bumps milliseconds up by one |
519 // so that we never return too early. We likely return late though. | 485 // so that we never return too early. We likely return late though. |
520 millis += 1; | 486 millis += 1; |
521 } | 487 } |
522 return Wait(millis); | 488 return Wait(millis); |
523 } | 489 } |
524 | 490 |
525 | |
526 void Monitor::Notify() { | 491 void Monitor::Notify() { |
527 // When running with assertions enabled we track the owner. | 492 // When running with assertions enabled we track the owner. |
528 ASSERT(IsOwnedByCurrentThread()); | 493 ASSERT(IsOwnedByCurrentThread()); |
529 data_.SignalAndRemoveFirstWaiter(); | 494 data_.SignalAndRemoveFirstWaiter(); |
530 } | 495 } |
531 | 496 |
532 | |
533 void Monitor::NotifyAll() { | 497 void Monitor::NotifyAll() { |
534 // When running with assertions enabled we track the owner. | 498 // When running with assertions enabled we track the owner. |
535 ASSERT(IsOwnedByCurrentThread()); | 499 ASSERT(IsOwnedByCurrentThread()); |
536 // If one of the objects in the list of waiters wakes because of a | 500 // If one of the objects in the list of waiters wakes because of a |
537 // timeout before we signal it, that object will get an extra | 501 // timeout before we signal it, that object will get an extra |
538 // signal. This will be treated as a spurious wake-up and is OK | 502 // signal. This will be treated as a spurious wake-up and is OK |
539 // since all uses of monitors should recheck the condition after a | 503 // since all uses of monitors should recheck the condition after a |
540 // Wait. | 504 // Wait. |
541 data_.SignalAndRemoveAllWaiters(); | 505 data_.SignalAndRemoveAllWaiters(); |
542 } | 506 } |
543 | 507 |
544 | |
545 void ThreadLocalData::AddThreadLocal(ThreadLocalKey key, | 508 void ThreadLocalData::AddThreadLocal(ThreadLocalKey key, |
546 ThreadDestructor destructor) { | 509 ThreadDestructor destructor) { |
547 ASSERT(thread_locals_ != NULL); | 510 ASSERT(thread_locals_ != NULL); |
548 if (destructor == NULL) { | 511 if (destructor == NULL) { |
549 // We only care about thread locals with destructors. | 512 // We only care about thread locals with destructors. |
550 return; | 513 return; |
551 } | 514 } |
552 MutexLocker ml(mutex_, false); | 515 MutexLocker ml(mutex_, false); |
553 #if defined(DEBUG) | 516 #if defined(DEBUG) |
554 // Verify that we aren't added twice. | 517 // Verify that we aren't added twice. |
555 for (intptr_t i = 0; i < thread_locals_->length(); i++) { | 518 for (intptr_t i = 0; i < thread_locals_->length(); i++) { |
556 const ThreadLocalEntry& entry = thread_locals_->At(i); | 519 const ThreadLocalEntry& entry = thread_locals_->At(i); |
557 ASSERT(entry.key() != key); | 520 ASSERT(entry.key() != key); |
558 } | 521 } |
559 #endif | 522 #endif |
560 // Add to list. | 523 // Add to list. |
561 thread_locals_->Add(ThreadLocalEntry(key, destructor)); | 524 thread_locals_->Add(ThreadLocalEntry(key, destructor)); |
562 } | 525 } |
563 | 526 |
564 | |
565 void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) { | 527 void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) { |
566 ASSERT(thread_locals_ != NULL); | 528 ASSERT(thread_locals_ != NULL); |
567 MutexLocker ml(mutex_, false); | 529 MutexLocker ml(mutex_, false); |
568 intptr_t i = 0; | 530 intptr_t i = 0; |
569 for (; i < thread_locals_->length(); i++) { | 531 for (; i < thread_locals_->length(); i++) { |
570 const ThreadLocalEntry& entry = thread_locals_->At(i); | 532 const ThreadLocalEntry& entry = thread_locals_->At(i); |
571 if (entry.key() == key) { | 533 if (entry.key() == key) { |
572 break; | 534 break; |
573 } | 535 } |
574 } | 536 } |
575 if (i == thread_locals_->length()) { | 537 if (i == thread_locals_->length()) { |
576 // Not found. | 538 // Not found. |
577 return; | 539 return; |
578 } | 540 } |
579 thread_locals_->RemoveAt(i); | 541 thread_locals_->RemoveAt(i); |
580 } | 542 } |
581 | 543 |
582 | |
583 // This function is executed on the thread that is exiting. It is invoked | 544 // This function is executed on the thread that is exiting. It is invoked |
584 // by |OnDartThreadExit| (see below for notes on TLS destructors on Windows). | 545 // by |OnDartThreadExit| (see below for notes on TLS destructors on Windows). |
585 void ThreadLocalData::RunDestructors() { | 546 void ThreadLocalData::RunDestructors() { |
586 ASSERT(thread_locals_ != NULL); | 547 ASSERT(thread_locals_ != NULL); |
587 ASSERT(mutex_ != NULL); | 548 ASSERT(mutex_ != NULL); |
588 MutexLocker ml(mutex_, false); | 549 MutexLocker ml(mutex_, false); |
589 for (intptr_t i = 0; i < thread_locals_->length(); i++) { | 550 for (intptr_t i = 0; i < thread_locals_->length(); i++) { |
590 const ThreadLocalEntry& entry = thread_locals_->At(i); | 551 const ThreadLocalEntry& entry = thread_locals_->At(i); |
591 // We access the exiting thread's TLS variable here. | 552 // We access the exiting thread's TLS variable here. |
592 void* p = reinterpret_cast<void*>(OSThread::GetThreadLocal(entry.key())); | 553 void* p = reinterpret_cast<void*>(OSThread::GetThreadLocal(entry.key())); |
593 // We invoke the constructor here. | 554 // We invoke the constructor here. |
594 entry.destructor()(p); | 555 entry.destructor()(p); |
595 } | 556 } |
596 } | 557 } |
597 | 558 |
598 | |
599 Mutex* ThreadLocalData::mutex_ = NULL; | 559 Mutex* ThreadLocalData::mutex_ = NULL; |
600 MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL; | 560 MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL; |
601 | 561 |
602 | |
603 void ThreadLocalData::InitOnce() { | 562 void ThreadLocalData::InitOnce() { |
604 mutex_ = new Mutex(); | 563 mutex_ = new Mutex(); |
605 thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>(); | 564 thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>(); |
606 } | 565 } |
607 | 566 |
608 | |
609 void ThreadLocalData::Shutdown() { | 567 void ThreadLocalData::Shutdown() { |
610 if (mutex_ != NULL) { | 568 if (mutex_ != NULL) { |
611 delete mutex_; | 569 delete mutex_; |
612 mutex_ = NULL; | 570 mutex_ = NULL; |
613 } | 571 } |
614 if (thread_locals_ != NULL) { | 572 if (thread_locals_ != NULL) { |
615 delete thread_locals_; | 573 delete thread_locals_; |
616 thread_locals_ = NULL; | 574 thread_locals_ = NULL; |
617 } | 575 } |
618 } | 576 } |
619 | 577 |
620 | |
621 } // namespace dart | 578 } // namespace dart |
622 | 579 |
623 // The following was adapted from Chromium: | 580 // The following was adapted from Chromium: |
624 // src/base/threading/thread_local_storage_win.cc | 581 // src/base/threading/thread_local_storage_win.cc |
625 | 582 |
626 // Thread Termination Callbacks. | 583 // Thread Termination Callbacks. |
627 // Windows doesn't support a per-thread destructor with its | 584 // Windows doesn't support a per-thread destructor with its |
628 // TLS primitives. So, we build it manually by inserting a | 585 // TLS primitives. So, we build it manually by inserting a |
629 // function to be called on each thread's exit. | 586 // function to be called on each thread's exit. |
630 // This magic is from http://www.codeproject.com/threads/tls.asp | 587 // This magic is from http://www.codeproject.com/threads/tls.asp |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 #pragma data_seg(".CRT$XLB") | 651 #pragma data_seg(".CRT$XLB") |
695 PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit; | 652 PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit; |
696 | 653 |
697 // Reset the default section. | 654 // Reset the default section. |
698 #pragma data_seg() | 655 #pragma data_seg() |
699 | 656 |
700 #endif // _WIN64 | 657 #endif // _WIN64 |
701 } // extern "C" | 658 } // extern "C" |
702 | 659 |
703 #endif // defined(HOST_OS_WINDOWS) | 660 #endif // defined(HOST_OS_WINDOWS) |
OLD | NEW |