Chromium Code Reviews| 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 |