| 42 | } |
| 43 | |
| 44 | concurrencpp::lazy_result<scoped_async_lock> async_lock::lock_impl(std::shared_ptr<executor> resume_executor, bool with_raii_guard) { |
| 45 | auto resume_synchronously = true; // indicates if the locking coroutine managed to lock the lock on first attempt |
| 46 | |
| 47 | while (true) { |
| 48 | std::unique_lock<std::mutex> lock(m_awaiter_lock); |
| 49 | if (!m_locked) { |
| 50 | m_locked = true; |
| 51 | lock.unlock(); |
| 52 | break; |
| 53 | } |
| 54 | |
| 55 | co_await async_lock_awaiter(*this, lock); |
| 56 | |
| 57 | resume_synchronously = |
| 58 | false; // if we haven't managed to lock the lock on first attempt, we need to resume using resume_executor |
| 59 | } |
| 60 | |
| 61 | if (!resume_synchronously) { |
| 62 | try { |
| 63 | co_await resume_on(resume_executor); |
| 64 | } catch (...) { |
| 65 | std::unique_lock<std::mutex> lock(m_awaiter_lock); |
| 66 | assert(m_locked); |
| 67 | m_locked = false; |
| 68 | const auto awaiter = m_awaiters.pop_front(); |
| 69 | lock.unlock(); |
| 70 | |
| 71 | if (awaiter != nullptr) { |
| 72 | awaiter->retry(); |
| 73 | } |
| 74 | |
| 75 | throw; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | #ifdef CRCPP_DEBUG_MODE |
| 80 | const auto current_count = m_thread_count_in_critical_section.fetch_add(1, std::memory_order_relaxed); |
| 81 | assert(current_count == 0); |
| 82 | #endif |
| 83 | |
| 84 | if (with_raii_guard) { |
| 85 | co_return scoped_async_lock(*this, std::adopt_lock); |
| 86 | } |
| 87 | |
| 88 | co_return scoped_async_lock(*this, std::defer_lock); |
| 89 | } |
| 90 | |
| 91 | concurrencpp::lazy_result<scoped_async_lock> async_lock::lock(std::shared_ptr<executor> resume_executor) { |
| 92 | if (!static_cast<bool>(resume_executor)) { |
no test coverage detected