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 BOOST_ASIO_DETAIL_POSIX_EVENT_HPP |
12 | #define BOOST_ASIO_DETAIL_POSIX_EVENT_HPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | |
20 | #if defined(BOOST_ASIO_HAS_PTHREADS) |
21 | |
22 | #include <pthread.h> |
23 | #include <boost/asio/detail/assert.hpp> |
24 | #include <boost/asio/detail/noncopyable.hpp> |
25 | |
26 | #include <boost/asio/detail/push_options.hpp> |
27 | |
28 | namespace boost { |
29 | namespace asio { |
30 | namespace detail { |
31 | |
32 | class posix_event |
33 | : private noncopyable |
34 | { |
35 | public: |
36 | // Constructor. |
37 | BOOST_ASIO_DECL posix_event(); |
38 | |
39 | // Destructor. |
40 | ~posix_event() |
41 | { |
42 | ::pthread_cond_destroy(cond: &cond_); |
43 | } |
44 | |
45 | // Signal the event. (Retained for backward compatibility.) |
46 | template <typename Lock> |
47 | void signal(Lock& lock) |
48 | { |
49 | this->signal_all(lock); |
50 | } |
51 | |
52 | // Signal all waiters. |
53 | template <typename Lock> |
54 | void signal_all(Lock& lock) |
55 | { |
56 | BOOST_ASIO_ASSERT(lock.locked()); |
57 | (void)lock; |
58 | state_ |= 1; |
59 | ::pthread_cond_broadcast(cond: &cond_); // Ignore EINVAL. |
60 | } |
61 | |
62 | // Unlock the mutex and signal one waiter. |
63 | template <typename Lock> |
64 | void unlock_and_signal_one(Lock& lock) |
65 | { |
66 | BOOST_ASIO_ASSERT(lock.locked()); |
67 | state_ |= 1; |
68 | bool have_waiters = (state_ > 1); |
69 | lock.unlock(); |
70 | if (have_waiters) |
71 | ::pthread_cond_signal(cond: &cond_); // Ignore EINVAL. |
72 | } |
73 | |
74 | // If there's a waiter, unlock the mutex and signal it. |
75 | template <typename Lock> |
76 | bool maybe_unlock_and_signal_one(Lock& lock) |
77 | { |
78 | BOOST_ASIO_ASSERT(lock.locked()); |
79 | state_ |= 1; |
80 | if (state_ > 1) |
81 | { |
82 | lock.unlock(); |
83 | ::pthread_cond_signal(cond: &cond_); // Ignore EINVAL. |
84 | return true; |
85 | } |
86 | return false; |
87 | } |
88 | |
89 | // Reset the event. |
90 | template <typename Lock> |
91 | void clear(Lock& lock) |
92 | { |
93 | BOOST_ASIO_ASSERT(lock.locked()); |
94 | (void)lock; |
95 | state_ &= ~std::size_t(1); |
96 | } |
97 | |
98 | // Wait for the event to become signalled. |
99 | template <typename Lock> |
100 | void wait(Lock& lock) |
101 | { |
102 | BOOST_ASIO_ASSERT(lock.locked()); |
103 | while ((state_ & 1) == 0) |
104 | { |
105 | state_ += 2; |
106 | ::pthread_cond_wait(cond: &cond_, mutex: &lock.mutex().mutex_); // Ignore EINVAL. |
107 | state_ -= 2; |
108 | } |
109 | } |
110 | |
111 | private: |
112 | ::pthread_cond_t cond_; |
113 | std::size_t state_; |
114 | }; |
115 | |
116 | } // namespace detail |
117 | } // namespace asio |
118 | } // namespace boost |
119 | |
120 | #include <boost/asio/detail/pop_options.hpp> |
121 | |
122 | #if defined(BOOST_ASIO_HEADER_ONLY) |
123 | # include <boost/asio/detail/impl/posix_event.ipp> |
124 | #endif // defined(BOOST_ASIO_HEADER_ONLY) |
125 | |
126 | #endif // defined(BOOST_ASIO_HAS_PTHREADS) |
127 | |
128 | #endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP |
129 |