189 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| //
 | |
| // detail/std_event.hpp
 | |
| // ~~~~~~~~~~~~~~~~~~~~
 | |
| //
 | |
| // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
| //
 | |
| 
 | |
| #ifndef ASIO_DETAIL_STD_EVENT_HPP
 | |
| #define ASIO_DETAIL_STD_EVENT_HPP
 | |
| 
 | |
| #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 | |
| # pragma once
 | |
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 | |
| 
 | |
| #include "asio/detail/config.hpp"
 | |
| 
 | |
| #if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
 | |
| 
 | |
| #include <chrono>
 | |
| #include <condition_variable>
 | |
| #include "asio/detail/assert.hpp"
 | |
| #include "asio/detail/noncopyable.hpp"
 | |
| 
 | |
| #include "asio/detail/push_options.hpp"
 | |
| 
 | |
| namespace asio {
 | |
| namespace detail {
 | |
| 
 | |
| class std_event
 | |
|   : private noncopyable
 | |
| {
 | |
| public:
 | |
|   // Constructor.
 | |
|   std_event()
 | |
|     : state_(0)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   // Destructor.
 | |
|   ~std_event()
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   // Signal the event. (Retained for backward compatibility.)
 | |
|   template <typename Lock>
 | |
|   void signal(Lock& lock)
 | |
|   {
 | |
|     this->signal_all(lock);
 | |
|   }
 | |
| 
 | |
|   // Signal all waiters.
 | |
|   template <typename Lock>
 | |
|   void signal_all(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     (void)lock;
 | |
|     state_ |= 1;
 | |
|     cond_.notify_all();
 | |
|   }
 | |
| 
 | |
|   // Unlock the mutex and signal one waiter.
 | |
|   template <typename Lock>
 | |
|   void unlock_and_signal_one(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     state_ |= 1;
 | |
|     bool have_waiters = (state_ > 1);
 | |
|     lock.unlock();
 | |
|     if (have_waiters)
 | |
|       cond_.notify_one();
 | |
|   }
 | |
| 
 | |
|   // Unlock the mutex and signal one waiter who may destroy us.
 | |
|   template <typename Lock>
 | |
|   void unlock_and_signal_one_for_destruction(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     state_ |= 1;
 | |
|     bool have_waiters = (state_ > 1);
 | |
|     if (have_waiters)
 | |
|       cond_.notify_one();
 | |
|     lock.unlock();
 | |
|   }
 | |
| 
 | |
|   // If there's a waiter, unlock the mutex and signal it.
 | |
|   template <typename Lock>
 | |
|   bool maybe_unlock_and_signal_one(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     state_ |= 1;
 | |
|     if (state_ > 1)
 | |
|     {
 | |
|       lock.unlock();
 | |
|       cond_.notify_one();
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Reset the event.
 | |
|   template <typename Lock>
 | |
|   void clear(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     (void)lock;
 | |
|     state_ &= ~std::size_t(1);
 | |
|   }
 | |
| 
 | |
|   // Wait for the event to become signalled.
 | |
|   template <typename Lock>
 | |
|   void wait(Lock& lock)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     unique_lock_adapter u_lock(lock);
 | |
|     while ((state_ & 1) == 0)
 | |
|     {
 | |
|       waiter w(state_);
 | |
|       cond_.wait(u_lock.unique_lock_);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Timed wait for the event to become signalled.
 | |
|   template <typename Lock>
 | |
|   bool wait_for_usec(Lock& lock, long usec)
 | |
|   {
 | |
|     ASIO_ASSERT(lock.locked());
 | |
|     unique_lock_adapter u_lock(lock);
 | |
|     if ((state_ & 1) == 0)
 | |
|     {
 | |
|       waiter w(state_);
 | |
|       cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec));
 | |
|     }
 | |
|     return (state_ & 1) != 0;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   // Helper class to temporarily adapt a scoped_lock into a unique_lock so that
 | |
|   // it can be passed to std::condition_variable::wait().
 | |
|   struct unique_lock_adapter
 | |
|   {
 | |
|     template <typename Lock>
 | |
|     explicit unique_lock_adapter(Lock& lock)
 | |
|       : unique_lock_(lock.mutex().mutex_, std::adopt_lock)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     ~unique_lock_adapter()
 | |
|     {
 | |
|       unique_lock_.release();
 | |
|     }
 | |
| 
 | |
|     std::unique_lock<std::mutex> unique_lock_;
 | |
|   };
 | |
| 
 | |
|   // Helper to increment and decrement the state to track outstanding waiters.
 | |
|   class waiter
 | |
|   {
 | |
|   public:
 | |
|     explicit waiter(std::size_t& state)
 | |
|       : state_(state)
 | |
|     {
 | |
|       state_ += 2;
 | |
|     }
 | |
| 
 | |
|     ~waiter()
 | |
|     {
 | |
|       state_ -= 2;
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     std::size_t& state_;
 | |
|   };
 | |
| 
 | |
|   std::condition_variable cond_;
 | |
|   std::size_t state_;
 | |
| };
 | |
| 
 | |
| } // namespace detail
 | |
| } // namespace asio
 | |
| 
 | |
| #include "asio/detail/pop_options.hpp"
 | |
| 
 | |
| #endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
 | |
| 
 | |
| #endif // ASIO_DETAIL_STD_EVENT_HPP
 |