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/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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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) |
OLD | NEW |