1 //
2 // detail/posix_event.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef ASIO_DETAIL_POSIX_EVENT_HPP
12 #define ASIO_DETAIL_POSIX_EVENT_HPP
13 
14 
15 #include "asio/detail/config.hpp"
16 
17 #if defined(ASIO_HAS_PTHREADS)
18 
19 #include <pthread.h>
20 #include "asio/detail/assert.hpp"
21 #include "asio/detail/noncopyable.hpp"
22 
23 #include "asio/detail/push_options.hpp"
24 
25 namespace asio {
26 namespace detail {
27 
28 class posix_event
29   : private noncopyable
30 {
31 public:
32   // Constructor.
33   ASIO_DECL posix_event();
34 
35   // Destructor.
~posix_event()36   ~posix_event()
37   {
38     ::pthread_cond_destroy(&cond_);
39   }
40 
41   // Signal the event. (Retained for backward compatibility.)
42   template <typename Lock>
signal(Lock & lock)43   void signal(Lock& lock)
44   {
45     this->signal_all(lock);
46   }
47 
48   // Signal all waiters.
49   template <typename Lock>
signal_all(Lock & lock)50   void signal_all(Lock& lock)
51   {
52     ASIO_ASSERT(lock.locked());
53     (void)lock;
54     state_ |= 1;
55     ::pthread_cond_broadcast(&cond_); // Ignore EINVAL.
56   }
57 
58   // Unlock the mutex and signal one waiter.
59   template <typename Lock>
unlock_and_signal_one(Lock & lock)60   void unlock_and_signal_one(Lock& lock)
61   {
62     ASIO_ASSERT(lock.locked());
63     state_ |= 1;
64     bool have_waiters = (state_ > 1);
65     lock.unlock();
66     if (have_waiters)
67       ::pthread_cond_signal(&cond_); // Ignore EINVAL.
68   }
69 
70   // If there's a waiter, unlock the mutex and signal it.
71   template <typename Lock>
maybe_unlock_and_signal_one(Lock & lock)72   bool maybe_unlock_and_signal_one(Lock& lock)
73   {
74     ASIO_ASSERT(lock.locked());
75     state_ |= 1;
76     if (state_ > 1)
77     {
78       lock.unlock();
79       ::pthread_cond_signal(&cond_); // Ignore EINVAL.
80       return true;
81     }
82     return false;
83   }
84 
85   // Reset the event.
86   template <typename Lock>
clear(Lock & lock)87   void clear(Lock& lock)
88   {
89     ASIO_ASSERT(lock.locked());
90     (void)lock;
91     state_ &= ~std::size_t(1);
92   }
93 
94   // Wait for the event to become signalled.
95   template <typename Lock>
wait(Lock & lock)96   void wait(Lock& lock)
97   {
98     ASIO_ASSERT(lock.locked());
99     while ((state_ & 1) == 0)
100     {
101       state_ += 2;
102       ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
103       state_ -= 2;
104     }
105   }
106 
107 private:
108   ::pthread_cond_t cond_;
109   std::size_t state_;
110 };
111 
112 } // namespace detail
113 } // namespace asio
114 
115 #include "asio/detail/pop_options.hpp"
116 
117 # include "asio/detail/impl/posix_event.ipp"
118 
119 #endif // defined(ASIO_HAS_PTHREADS)
120 
121 #endif // ASIO_DETAIL_POSIX_EVENT_HPP
122