Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: runtime/vm/os_thread_win.cc

Issue 1410493002: Complete support for Windows TLS destructors (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/growable_array.h"
8 #include "vm/os_thread.h" 9 #include "vm/os_thread.h"
9 10
10 #include <process.h> // NOLINT 11 #include <process.h> // NOLINT
11 12
12 #include "platform/assert.h" 13 #include "platform/assert.h"
13 14
14 namespace dart { 15 namespace dart {
15 16
16 class ThreadStartData { 17 class ThreadStartData {
17 public: 18 public:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 // Close the handle, so we don't leak the thread object. 67 // Close the handle, so we don't leak the thread object.
67 CloseHandle(reinterpret_cast<HANDLE>(thread)); 68 CloseHandle(reinterpret_cast<HANDLE>(thread));
68 69
69 return 0; 70 return 0;
70 } 71 }
71 72
72 ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES; 73 ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
73 ThreadId OSThread::kInvalidThreadId = 0; 74 ThreadId OSThread::kInvalidThreadId = 0;
74 ThreadJoinId OSThread::kInvalidThreadJoinId = 0; 75 ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
75 76
76 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor unused) { 77 ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
77 ThreadLocalKey key = TlsAlloc(); 78 ThreadLocalKey key = TlsAlloc();
78 if (key == kUnsetThreadLocalKey) { 79 if (key == kUnsetThreadLocalKey) {
79 FATAL1("TlsAlloc failed %d", GetLastError()); 80 FATAL1("TlsAlloc failed %d", GetLastError());
80 } 81 }
82 ThreadLocalData::AddThreadLocal(key, destructor);
81 return key; 83 return key;
82 } 84 }
83 85
84 86
85 void OSThread::DeleteThreadLocal(ThreadLocalKey key) { 87 void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
86 ASSERT(key != kUnsetThreadLocalKey); 88 ASSERT(key != kUnsetThreadLocalKey);
87 BOOL result = TlsFree(key); 89 BOOL result = TlsFree(key);
88 if (!result) { 90 if (!result) {
89 FATAL1("TlsFree failed %d", GetLastError()); 91 FATAL1("TlsFree failed %d", GetLastError());
90 } 92 }
93 ThreadLocalData::RemoveThreadLocal(key);
91 } 94 }
92 95
93 96
94 intptr_t OSThread::GetMaxStackSize() { 97 intptr_t OSThread::GetMaxStackSize() {
95 const int kStackSize = (128 * kWordSize * KB); 98 const int kStackSize = (128 * kWordSize * KB);
96 return kStackSize; 99 return kStackSize;
97 } 100 }
98 101
99 102
100 ThreadId OSThread::GetCurrentThreadId() { 103 ThreadId OSThread::GetCurrentThreadId() {
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 478
476 void Monitor::NotifyAll() { 479 void Monitor::NotifyAll() {
477 // If one of the objects in the list of waiters wakes because of a 480 // If one of the objects in the list of waiters wakes because of a
478 // timeout before we signal it, that object will get an extra 481 // timeout before we signal it, that object will get an extra
479 // signal. This will be treated as a spurious wake-up and is OK 482 // signal. This will be treated as a spurious wake-up and is OK
480 // since all uses of monitors should recheck the condition after a 483 // since all uses of monitors should recheck the condition after a
481 // Wait. 484 // Wait.
482 data_.SignalAndRemoveAllWaiters(); 485 data_.SignalAndRemoveAllWaiters();
483 } 486 }
484 487
485 // This function is defined in thread.cc. 488
486 extern void ThreadCleanupOnExit(); 489 void ThreadLocalData::AddThreadLocal(ThreadLocalKey key,
490 ThreadDestructor destructor) {
491 if (thread_locals_ == NULL) {
492 return;
493 }
siva 2015/10/15 22:42:48 Should this be ASSERT(thread_locals_ != NULL);
Cutch 2015/10/16 16:53:25 Done.
494 if (destructor == NULL) {
495 // We only care about thread locals with destructors.
496 return;
497 }
498 mutex_->Lock();
499 #if defined(DEBUG)
500 // Verify that we aren't added twice.
501 for (intptr_t i = 0; i < thread_locals_->length(); i++) {
502 const ThreadLocalEntry& entry = thread_locals_->At(i);
503 ASSERT(entry.key() != key);
504 }
505 #endif
506 // Add to list.
507 thread_locals_->Add(ThreadLocalEntry(key, destructor));
508 mutex_->Unlock();
509 }
510
511
512 void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) {
513 if (thread_locals_ == NULL) {
514 return;
515 }
siva 2015/10/15 22:42:48 Ditto comment.
Cutch 2015/10/16 16:53:25 Done.
516 mutex_->Lock();
517 intptr_t i = 0;
518 for (; i < thread_locals_->length(); i++) {
519 const ThreadLocalEntry& entry = thread_locals_->At(i);
520 if (entry.key() == key) {
521 break;
522 }
523 }
524 if (i == thread_locals_->length()) {
525 // Not found.
526 mutex_->Unlock();
527 return;
528 }
529 thread_locals_->RemoveAt(i);
530 mutex_->Unlock();
531 }
532
533
534 void ThreadLocalData::RunDestructors() {
535 ASSERT(mutex_ != NULL);
536 mutex_->Lock();
537 ASSERT(thread_locals_ != NULL);
538 for (intptr_t i = 0; i < thread_locals_->length(); i++) {
539 const ThreadLocalEntry& entry = thread_locals_->At(i);
540 void* p = reinterpret_cast<void*>(OSThread::GetThreadLocal(entry.key()));
541 entry.destructor()(p);
542 }
543 mutex_->Unlock();
544 }
545
546
547 Mutex* ThreadLocalData::mutex_ = NULL;
548 MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL;
549
550
551 void ThreadLocalData::InitOnce() {
552 mutex_ = new Mutex();
553 thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>();
554 }
555
556
557 void ThreadLocalData::Shutdown() {
558 if (mutex_ != NULL) {
559 delete mutex_;
560 mutex_ = NULL;
561 }
562 if (thread_locals_ != NULL) {
563 delete thread_locals_;
564 thread_locals_ = NULL;
565 }
566 }
567
487 568
488 } // namespace dart 569 } // namespace dart
489 570
490 // NOTE: We still do not respect arbitrary TLS destructors on Windows, but,
491 // we do run known TLS cleanup functions. See |OnThreadExit| below for
492 // the list of functions that are called.
493
494 // The following was adapted from Chromium: 571 // The following was adapted from Chromium:
495 // src/base/threading/thread_local_storage_win.cc 572 // src/base/threading/thread_local_storage_win.cc
496 573
497 // Thread Termination Callbacks. 574 // Thread Termination Callbacks.
498 // Windows doesn't support a per-thread destructor with its 575 // Windows doesn't support a per-thread destructor with its
499 // TLS primitives. So, we build it manually by inserting a 576 // TLS primitives. So, we build it manually by inserting a
500 // function to be called on each thread's exit. 577 // function to be called on each thread's exit.
501 // This magic is from http://www.codeproject.com/threads/tls.asp 578 // This magic is from http://www.codeproject.com/threads/tls.asp
502 // and it works for VC++ 7.0 and later. 579 // and it works for VC++ 7.0 and later.
503 580
(...skipping 11 matching lines...) Expand all
515 #pragma comment(linker, "/INCLUDE:__tls_used") 592 #pragma comment(linker, "/INCLUDE:__tls_used")
516 #pragma comment(linker, "/INCLUDE:_p_thread_callback_dart") 593 #pragma comment(linker, "/INCLUDE:_p_thread_callback_dart")
517 594
518 #endif // _WIN64 595 #endif // _WIN64
519 596
520 // Static callback function to call with each thread termination. 597 // Static callback function to call with each thread termination.
521 void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) { 598 void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) {
522 // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+ 599 // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
523 // and on W2K and W2K3. So don't assume it is sent. 600 // and on W2K and W2K3. So don't assume it is sent.
524 if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) { 601 if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) {
525 dart::ThreadCleanupOnExit(); 602 dart::ThreadLocalData::RunDestructors();
526 dart::MonitorWaitData::ThreadExit(); 603 dart::MonitorWaitData::ThreadExit();
527 } 604 }
528 } 605 }
529 606
530 // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are 607 // .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 608 // 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 609 // 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 610 // loaded by a LoadLibrary() call. It must have implicitly been loaded at
534 // process startup. 611 // process startup.
535 // By implicitly loaded, I mean that it is directly referenced by the main EXE 612 // By implicitly loaded, I mean that it is directly referenced by the main EXE
(...skipping 26 matching lines...) Expand all
562 #pragma data_seg(".CRT$XLB") 639 #pragma data_seg(".CRT$XLB")
563 PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit; 640 PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit;
564 641
565 // Reset the default section. 642 // Reset the default section.
566 #pragma data_seg() 643 #pragma data_seg()
567 644
568 #endif // _WIN64 645 #endif // _WIN64
569 } // extern "C" 646 } // extern "C"
570 647
571 #endif // defined(TARGET_OS_WINDOWS) 648 #endif // defined(TARGET_OS_WINDOWS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698