| 667 | // LightweightSemaphore |
| 668 | //--------------------------------------------------------- |
| 669 | class LightweightSemaphore |
| 670 | { |
| 671 | public: |
| 672 | typedef std::make_signed<std::size_t>::type ssize_t; |
| 673 | |
| 674 | private: |
| 675 | weak_atomic<ssize_t> m_count; |
| 676 | Semaphore m_sema; |
| 677 | |
| 678 | bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) AE_NO_TSAN |
| 679 | { |
| 680 | ssize_t oldCount; |
| 681 | // Is there a better way to set the initial spin count? |
| 682 | // If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC, |
| 683 | // as threads start hitting the kernel semaphore. |
| 684 | int spin = 1024; |
| 685 | while (--spin >= 0) |
| 686 | { |
| 687 | if (m_count.load() > 0) |
| 688 | { |
| 689 | m_count.fetch_add_acquire(-1); |
| 690 | return true; |
| 691 | } |
| 692 | compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop. |
| 693 | } |
| 694 | oldCount = m_count.fetch_add_acquire(-1); |
| 695 | if (oldCount > 0) |
| 696 | return true; |
| 697 | if (timeout_usecs < 0) |
| 698 | { |
| 699 | if (m_sema.wait()) |
| 700 | return true; |
| 701 | } |
| 702 | if (timeout_usecs > 0 && m_sema.timed_wait(static_cast<uint64_t>(timeout_usecs))) |
| 703 | return true; |
| 704 | // At this point, we've timed out waiting for the semaphore, but the |
| 705 | // count is still decremented indicating we may still be waiting on |
| 706 | // it. So we have to re-adjust the count, but only if the semaphore |
| 707 | // wasn't signaled enough times for us too since then. If it was, we |
| 708 | // need to release the semaphore too. |
| 709 | while (true) |
| 710 | { |
| 711 | oldCount = m_count.fetch_add_release(1); |
| 712 | if (oldCount < 0) |
| 713 | return false; // successfully restored things to the way they were |
| 714 | // Oh, the producer thread just signaled the semaphore after all. Try again: |
| 715 | oldCount = m_count.fetch_add_acquire(-1); |
| 716 | if (oldCount > 0 && m_sema.try_wait()) |
| 717 | return true; |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | public: |
| 722 | AE_NO_TSAN LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount), m_sema() |
| 723 | { |
| 724 | assert(initialCount >= 0); |
| 725 | } |
| 726 |
nothing calls this directly
no outgoing calls
no test coverage detected