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(TARGET_OS_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
7 | 7 |
8 #include "vm/os_thread.h" | 8 #include "vm/os_thread.h" |
9 | 9 |
10 #include <process.h> // NOLINT | 10 #include <process.h> // NOLINT |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 void Monitor::Exit() { | 280 void Monitor::Exit() { |
281 LeaveCriticalSection(&data_.cs_); | 281 LeaveCriticalSection(&data_.cs_); |
282 } | 282 } |
283 | 283 |
284 | 284 |
285 void MonitorWaitData::ThreadExit() { | 285 void MonitorWaitData::ThreadExit() { |
286 if (MonitorWaitData::monitor_wait_data_key_ != | 286 if (MonitorWaitData::monitor_wait_data_key_ != |
287 OSThread::kUnsetThreadLocalKey) { | 287 OSThread::kUnsetThreadLocalKey) { |
288 uword raw_wait_data = | 288 uword raw_wait_data = |
289 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); | 289 OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_); |
| 290 // This may be called more than once- clear tls key. |
| 291 MonitorWaitData::monitor_wait_data_key_ = OSThread::kUnsetThreadLocalKey; |
290 if (raw_wait_data != 0) { | 292 if (raw_wait_data != 0) { |
291 MonitorWaitData* wait_data = | 293 MonitorWaitData* wait_data = |
292 reinterpret_cast<MonitorWaitData*>(raw_wait_data); | 294 reinterpret_cast<MonitorWaitData*>(raw_wait_data); |
293 delete wait_data; | 295 delete wait_data; |
294 } | 296 } |
295 } | 297 } |
296 } | 298 } |
297 | 299 |
298 | 300 |
299 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { | 301 void MonitorData::AddWaiter(MonitorWaitData* wait_data) { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 | 475 |
474 void Monitor::NotifyAll() { | 476 void Monitor::NotifyAll() { |
475 // If one of the objects in the list of waiters wakes because of a | 477 // If one of the objects in the list of waiters wakes because of a |
476 // timeout before we signal it, that object will get an extra | 478 // timeout before we signal it, that object will get an extra |
477 // signal. This will be treated as a spurious wake-up and is OK | 479 // signal. This will be treated as a spurious wake-up and is OK |
478 // since all uses of monitors should recheck the condition after a | 480 // since all uses of monitors should recheck the condition after a |
479 // Wait. | 481 // Wait. |
480 data_.SignalAndRemoveAllWaiters(); | 482 data_.SignalAndRemoveAllWaiters(); |
481 } | 483 } |
482 | 484 |
| 485 extern void WindowsThreadCleanUp(); |
| 486 |
483 } // namespace dart | 487 } // namespace dart |
484 | 488 |
| 489 // NOTE: We still do not respect arbitrary TLS destructors on Windows, but, |
| 490 // we do cleanup the VM's Thread and MonitorWaitData TLS. |
| 491 |
| 492 // The following was adapted from Chromium: |
| 493 // src/base/threading/thread_local_storage_win.cc |
| 494 |
| 495 // Thread Termination Callbacks. |
| 496 // Windows doesn't support a per-thread destructor with its |
| 497 // TLS primitives. So, we build it manually by inserting a |
| 498 // function to be called on each thread's exit. |
| 499 // This magic is from http://www.codeproject.com/threads/tls.asp |
| 500 // and it works for VC++ 7.0 and later. |
| 501 |
| 502 // Force a reference to _tls_used to make the linker create the TLS directory |
| 503 // if it's not already there. (e.g. if __declspec(thread) is not used). |
| 504 // Force a reference to p_thread_callback_dart to prevent whole program |
| 505 // optimization from discarding the variable. |
| 506 #ifdef _WIN64 |
| 507 |
| 508 #pragma comment(linker, "/INCLUDE:_tls_used") |
| 509 #pragma comment(linker, "/INCLUDE:p_thread_callback_dart") |
| 510 |
| 511 #else // _WIN64 |
| 512 |
| 513 #pragma comment(linker, "/INCLUDE:__tls_used") |
| 514 #pragma comment(linker, "/INCLUDE:p_thread_callback_dart") |
| 515 |
| 516 #endif // _WIN64 |
| 517 |
| 518 // Static callback function to call with each thread termination. |
| 519 void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved) { |
| 520 // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+ |
| 521 // and on W2K and W2K3. So don't assume it is sent. |
| 522 if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) { |
| 523 // Cleanup the Thread's TLS. |
| 524 dart::WindowsThreadCleanUp(); |
| 525 // Cleanup the MonitorWaitData's TLS. |
| 526 MonitorWaitData::ThreadExit(); |
| 527 } |
| 528 } |
| 529 |
| 530 // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are |
| 531 // called automatically by the OS loader code (not the CRT) when the module is |
| 532 // loaded and on thread creation. They are NOT called if the module has been |
| 533 // loaded by a LoadLibrary() call. It must have implicitly been loaded at |
| 534 // process startup. |
| 535 // By implicitly loaded, I mean that it is directly referenced by the main EXE |
| 536 // or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being |
| 537 // implicitly loaded. |
| 538 // |
| 539 // See VC\crt\src\tlssup.c for reference. |
| 540 |
| 541 // extern "C" suppresses C++ name mangling so we know the symbol name for the |
| 542 // linker /INCLUDE:symbol pragma above. |
| 543 extern "C" { |
| 544 // The linker must not discard p_thread_callback_dart. (We force a reference |
| 545 // to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If |
| 546 // this variable is discarded, the OnThreadExit function will never be called. |
| 547 #ifdef _WIN64 |
| 548 |
| 549 // .CRT section is merged with .rdata on x64 so it must be constant data. |
| 550 #pragma const_seg(".CRT$XLB") |
| 551 // When defining a const variable, it must have external linkage to be sure the |
| 552 // linker doesn't discard it. |
| 553 extern const PIMAGE_TLS_CALLBACK p_thread_callback_dart; |
| 554 const PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnThreadExit; |
| 555 |
| 556 // Reset the default section. |
| 557 #pragma const_seg() |
| 558 |
| 559 #else // _WIN64 |
| 560 |
| 561 #pragma data_seg(".CRT$XLB") |
| 562 PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnThreadExit; |
| 563 |
| 564 // Reset the default section. |
| 565 #pragma data_seg() |
| 566 |
| 567 #endif // _WIN64 |
| 568 } // extern "C" |
| 569 |
485 #endif // defined(TARGET_OS_WINDOWS) | 570 #endif // defined(TARGET_OS_WINDOWS) |
OLD | NEW |