Changeset 229515 in webkit
- Timestamp:
- Mar 11, 2018 12:03:30 AM (6 years ago)
- Location:
- trunk/Source/WTF
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r229504 r229515 1 2018-03-11 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [Win] Use SRWLOCK and CONDITION_VARIABLE to simplify implementation 4 https://bugs.webkit.org/show_bug.cgi?id=183541 5 6 Reviewed by Darin Adler. 7 8 After Windows Vista, Windows offers SRWLOCK and CONDITION_VARIABLE. 9 They can simplify the implementation of our WTF::Mutex and WTF::ThreadCondition. 10 11 C++ std::mutex and std::condition_variable uses std::chrono for their timed 12 functions. Since std::chrono is not overflow-aware, we cannot reliably use 13 this functionalities. This is why we still keep WTF::Mutex and WTF::ThreadCondition. 14 They are used for ParkingLot. 15 16 * wtf/ThreadingPrimitives.h: 17 * wtf/ThreadingWin.cpp: 18 (WTF::Mutex::Mutex): 19 (WTF::Mutex::~Mutex): 20 (WTF::Mutex::lock): 21 (WTF::Mutex::tryLock): 22 (WTF::Mutex::unlock): 23 (WTF::absoluteTimeToWaitTimeoutInterval): 24 (WTF::ThreadCondition::ThreadCondition): 25 (WTF::ThreadCondition::~ThreadCondition): 26 (WTF::ThreadCondition::wait): 27 (WTF::ThreadCondition::timedWait): 28 (WTF::ThreadCondition::signal): 29 (WTF::ThreadCondition::broadcast): 30 (WTF::PlatformCondition::timedWait): Deleted. 31 (WTF::PlatformCondition::signal): Deleted. 32 1 33 2018-03-10 Commit Queue <commit-queue@webkit.org> 2 34 -
trunk/Source/WTF/wtf/ThreadingPrimitives.h
r228942 r229515 56 56 using ThreadIdentifier = uint32_t; 57 57 using PlatformThreadHandle = HANDLE; 58 struct PlatformMutex { 59 CRITICAL_SECTION m_internalMutex; 60 size_t m_recursionCount; 61 }; 62 struct PlatformCondition { 63 size_t m_waitersGone; 64 size_t m_waitersBlocked; 65 size_t m_waitersToUnblock; 66 HANDLE m_blockLock; 67 HANDLE m_blockQueue; 68 HANDLE m_unblockLock; 58 using PlatformMutex = SRWLOCK; 59 using PlatformCondition = CONDITION_VARIABLE; 60 #else 61 #error "Not supported platform" 62 #endif 69 63 70 bool timedWait(PlatformMutex&, DWORD durationMilliseconds);71 void signal(bool unblockAll);72 };73 #else74 typedef void* PlatformMutex;75 typedef void* PlatformCondition;76 #endif77 78 64 class Mutex { 79 WTF_MAKE_NONCOPYABLE(Mutex); WTF_MAKE_FAST_ALLOCATED; 65 WTF_MAKE_NONCOPYABLE(Mutex); 66 WTF_MAKE_FAST_ALLOCATED; 80 67 public: 81 68 WTF_EXPORT_PRIVATE Mutex(); … … 86 73 WTF_EXPORT_PRIVATE void unlock(); 87 74 88 public:89 75 PlatformMutex& impl() { return m_mutex; } 76 90 77 private: 91 78 PlatformMutex m_mutex; … … 96 83 class ThreadCondition { 97 84 WTF_MAKE_NONCOPYABLE(ThreadCondition); 85 WTF_MAKE_FAST_ALLOCATED; 98 86 public: 99 87 WTF_EXPORT_PRIVATE ThreadCondition(); … … 110 98 }; 111 99 112 #if OS(WINDOWS)113 // Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject).114 WTF_EXPORT_PRIVATE DWORD absoluteTimeToWaitTimeoutInterval(WallTime absoluteTime);115 #endif116 117 100 } // namespace WTF 118 101 … … 121 104 using WTF::ThreadCondition; 122 105 123 #if OS(WINDOWS)124 using WTF::absoluteTimeToWaitTimeoutInterval;125 #endif126 127 106 #endif // ThreadingPrimitives_h -
trunk/Source/WTF/wtf/ThreadingWin.cpp
r229209 r229515 368 368 Mutex::Mutex() 369 369 { 370 m_mutex.m_recursionCount = 0; 371 InitializeCriticalSection(&m_mutex.m_internalMutex); 370 InitializeSRWLock(&m_mutex); 372 371 } 373 372 374 373 Mutex::~Mutex() 375 374 { 376 DeleteCriticalSection(&m_mutex.m_internalMutex);377 375 } 378 376 379 377 void Mutex::lock() 380 378 { 381 EnterCriticalSection(&m_mutex.m_internalMutex); 382 ++m_mutex.m_recursionCount; 383 } 384 385 #pragma warning(suppress: 26115) 379 AcquireSRWLockExclusive(&m_mutex); 380 } 381 386 382 bool Mutex::tryLock() 387 383 { 388 // This method is modeled after the behavior of pthread_mutex_trylock, 389 // which will return an error if the lock is already owned by the 390 // current thread. Since the primitive Win32 'TryEnterCriticalSection' 391 // treats this as a successful case, it changes the behavior of several 392 // tests in WebKit that check to see if the current thread already 393 // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord) 394 DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex); 395 396 if (result != 0) { // We got the lock 397 // If this thread already had the lock, we must unlock and 398 // return false so that we mimic the behavior of POSIX's 399 // pthread_mutex_trylock: 400 if (m_mutex.m_recursionCount > 0) { 401 LeaveCriticalSection(&m_mutex.m_internalMutex); 402 return false; 403 } 404 405 ++m_mutex.m_recursionCount; 406 return true; 407 } 408 409 return false; 384 return TryAcquireSRWLockExclusive(&m_mutex); 410 385 } 411 386 412 387 void Mutex::unlock() 413 388 { 414 ASSERT(m_mutex.m_recursionCount); 415 --m_mutex.m_recursionCount; 416 LeaveCriticalSection(&m_mutex.m_internalMutex); 417 } 418 419 bool PlatformCondition::timedWait(PlatformMutex& mutex, DWORD durationMilliseconds) 420 { 421 // Enter the wait state. 422 DWORD res = WaitForSingleObject(m_blockLock, INFINITE); 423 ASSERT_UNUSED(res, res == WAIT_OBJECT_0); 424 ++m_waitersBlocked; 425 res = ReleaseSemaphore(m_blockLock, 1, 0); 426 ASSERT_UNUSED(res, res); 427 428 --mutex.m_recursionCount; 429 LeaveCriticalSection(&mutex.m_internalMutex); 430 431 // Main wait - use timeout. 432 bool timedOut = (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT); 433 434 res = WaitForSingleObject(m_unblockLock, INFINITE); 435 ASSERT_UNUSED(res, res == WAIT_OBJECT_0); 436 437 int signalsLeft = m_waitersToUnblock; 438 439 if (m_waitersToUnblock) 440 --m_waitersToUnblock; 441 else if (++m_waitersGone == (INT_MAX / 2)) { // timeout/canceled or spurious semaphore 442 // timeout or spurious wakeup occured, normalize the m_waitersGone count 443 // this may occur if many calls to wait with a timeout are made and 444 // no call to notify_* is made 445 res = WaitForSingleObject(m_blockLock, INFINITE); 446 ASSERT_UNUSED(res, res == WAIT_OBJECT_0); 447 m_waitersBlocked -= m_waitersGone; 448 res = ReleaseSemaphore(m_blockLock, 1, 0); 449 ASSERT_UNUSED(res, res); 450 m_waitersGone = 0; 451 } 452 453 res = ReleaseMutex(m_unblockLock); 454 ASSERT_UNUSED(res, res); 455 456 if (signalsLeft == 1) { 457 res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate. 458 ASSERT_UNUSED(res, res); 459 } 460 461 EnterCriticalSection (&mutex.m_internalMutex); 462 ++mutex.m_recursionCount; 463 464 return !timedOut; 465 } 466 467 void PlatformCondition::signal(bool unblockAll) 468 { 469 unsigned signalsToIssue = 0; 470 471 DWORD res = WaitForSingleObject(m_unblockLock, INFINITE); 472 ASSERT_UNUSED(res, res == WAIT_OBJECT_0); 473 474 if (m_waitersToUnblock) { // the gate is already closed 475 if (!m_waitersBlocked) { // no-op 476 res = ReleaseMutex(m_unblockLock); 477 ASSERT_UNUSED(res, res); 478 return; 479 } 480 481 if (unblockAll) { 482 signalsToIssue = m_waitersBlocked; 483 m_waitersToUnblock += m_waitersBlocked; 484 m_waitersBlocked = 0; 485 } else { 486 signalsToIssue = 1; 487 ++m_waitersToUnblock; 488 --m_waitersBlocked; 489 } 490 } else if (m_waitersBlocked > m_waitersGone) { 491 res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate. 492 ASSERT_UNUSED(res, res == WAIT_OBJECT_0); 493 if (m_waitersGone != 0) { 494 m_waitersBlocked -= m_waitersGone; 495 m_waitersGone = 0; 496 } 497 if (unblockAll) { 498 signalsToIssue = m_waitersBlocked; 499 m_waitersToUnblock = m_waitersBlocked; 500 m_waitersBlocked = 0; 501 } else { 502 signalsToIssue = 1; 503 m_waitersToUnblock = 1; 504 --m_waitersBlocked; 505 } 506 } else { // No-op. 507 res = ReleaseMutex(m_unblockLock); 508 ASSERT_UNUSED(res, res); 509 return; 510 } 511 512 res = ReleaseMutex(m_unblockLock); 513 ASSERT_UNUSED(res, res); 514 515 if (signalsToIssue) { 516 res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0); 517 ASSERT_UNUSED(res, res); 518 } 519 } 520 521 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1); 389 ReleaseSRWLockExclusive(&m_mutex); 390 } 391 392 // Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject). 393 static DWORD absoluteTimeToWaitTimeoutInterval(WallTime absoluteTime) 394 { 395 WallTime currentTime = WallTime::now(); 396 397 // Time is in the past - return immediately. 398 if (absoluteTime < currentTime) 399 return 0; 400 401 // Time is too far in the future (and would overflow unsigned long) - wait forever. 402 if ((absoluteTime - currentTime) > Seconds::fromMilliseconds(INT_MAX)) 403 return INFINITE; 404 405 return static_cast<DWORD>((absoluteTime - currentTime).milliseconds()); 406 } 522 407 523 408 ThreadCondition::ThreadCondition() 524 409 { 525 m_condition.m_waitersGone = 0; 526 m_condition.m_waitersBlocked = 0; 527 m_condition.m_waitersToUnblock = 0; 528 m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0); 529 m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0); 530 m_condition.m_unblockLock = CreateMutex(0, 0, 0); 531 532 if (!m_condition.m_blockLock || !m_condition.m_blockQueue || !m_condition.m_unblockLock) { 533 if (m_condition.m_blockLock) 534 CloseHandle(m_condition.m_blockLock); 535 if (m_condition.m_blockQueue) 536 CloseHandle(m_condition.m_blockQueue); 537 if (m_condition.m_unblockLock) 538 CloseHandle(m_condition.m_unblockLock); 539 } 410 InitializeConditionVariable(&m_condition); 540 411 } 541 412 542 413 ThreadCondition::~ThreadCondition() 543 414 { 544 CloseHandle(m_condition.m_blockLock);545 CloseHandle(m_condition.m_blockQueue);546 CloseHandle(m_condition.m_unblockLock);547 415 } 548 416 549 417 void ThreadCondition::wait(Mutex& mutex) 550 418 { 551 m_condition.timedWait(mutex.impl(), INFINITE);419 SleepConditionVariableSRW(&m_condition, &mutex.impl(), INFINITE, 0); 552 420 } 553 421 554 422 bool ThreadCondition::timedWait(Mutex& mutex, WallTime absoluteTime) 555 423 { 424 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686304(v=vs.85).aspx 556 425 DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime); 557 558 426 if (!interval) { 559 427 // Consider the wait to have timed out, even if our condition has already been signaled, to … … 562 430 } 563 431 564 return m_condition.timedWait(mutex.impl(), interval); 432 if (SleepConditionVariableSRW(&m_condition, &mutex.impl(), interval, 0)) 433 return true; 434 ASSERT(GetLastError() == ERROR_TIMEOUT); 435 return false; 565 436 } 566 437 567 438 void ThreadCondition::signal() 568 439 { 569 m_condition.signal(false); // Unblock only 1 thread.440 WakeConditionVariable(&m_condition); 570 441 } 571 442 572 443 void ThreadCondition::broadcast() 573 444 { 574 m_condition.signal(true); // Unblock all threads. 575 } 576 577 DWORD absoluteTimeToWaitTimeoutInterval(WallTime absoluteTime) 578 { 579 WallTime currentTime = WallTime::now(); 580 581 // Time is in the past - return immediately. 582 if (absoluteTime < currentTime) 583 return 0; 584 585 // Time is too far in the future (and would overflow unsigned long) - wait forever. 586 if ((absoluteTime - currentTime) > Seconds::fromMilliseconds(INT_MAX)) 587 return INFINITE; 588 589 return static_cast<DWORD>((absoluteTime - currentTime).milliseconds()); 445 WakeAllConditionVariable(&m_condition); 590 446 } 591 447
Note: See TracChangeset
for help on using the changeset viewer.