• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *              Copyright Andrey Semashev 2016.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   posix/ipc_sync_wrappers.hpp
9  * \author Andrey Semashev
10  * \date   05.01.2016
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #ifndef BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
17 #define BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
18 
19 #include <boost/log/detail/config.hpp>
20 #include <pthread.h>
21 #include <cerrno>
22 #include <cstddef>
23 #include <boost/assert.hpp>
24 #include <boost/throw_exception.hpp>
25 // Use Boost.Interprocess to detect if process-shared pthread primitives are supported
26 #include <boost/interprocess/detail/workaround.hpp>
27 #if !defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
28 #include <boost/core/explicit_operator_bool.hpp>
29 #include <boost/interprocess/sync/interprocess_mutex.hpp>
30 #include <boost/interprocess/sync/interprocess_condition.hpp>
31 #undef BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST
32 #endif
33 #include <boost/log/exceptions.hpp>
34 #include <boost/log/detail/header.hpp>
35 
36 namespace boost {
37 
38 BOOST_LOG_OPEN_NAMESPACE
39 
40 namespace ipc {
41 
42 namespace aux {
43 
44 #if defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
45 
46 #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
47 struct BOOST_SYMBOL_VISIBLE lock_owner_dead {};
48 #endif
49 
50 //! Pthread mutex attributes
51 struct pthread_mutex_attributes
52 {
53     pthread_mutexattr_t attrs;
54 
pthread_mutex_attributesboost::ipc::aux::pthread_mutex_attributes55     pthread_mutex_attributes()
56     {
57         int err = pthread_mutexattr_init(&this->attrs);
58         if (BOOST_UNLIKELY(err != 0))
59             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex attributes", (err));
60     }
61 
~pthread_mutex_attributesboost::ipc::aux::pthread_mutex_attributes62     ~pthread_mutex_attributes()
63     {
64         BOOST_VERIFY(pthread_mutexattr_destroy(&this->attrs) == 0);
65     }
66 
67     BOOST_DELETED_FUNCTION(pthread_mutex_attributes(pthread_mutex_attributes const&))
68     BOOST_DELETED_FUNCTION(pthread_mutex_attributes& operator=(pthread_mutex_attributes const&))
69 };
70 
71 //! Pthread condifion variable attributes
72 struct pthread_condition_variable_attributes
73 {
74     pthread_condattr_t attrs;
75 
pthread_condition_variable_attributesboost::ipc::aux::pthread_condition_variable_attributes76     pthread_condition_variable_attributes()
77     {
78         int err = pthread_condattr_init(&this->attrs);
79         if (BOOST_UNLIKELY(err != 0))
80             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable attributes", (err));
81     }
82 
~pthread_condition_variable_attributesboost::ipc::aux::pthread_condition_variable_attributes83     ~pthread_condition_variable_attributes()
84     {
85         BOOST_VERIFY(pthread_condattr_destroy(&this->attrs) == 0);
86     }
87 
88     BOOST_DELETED_FUNCTION(pthread_condition_variable_attributes(pthread_condition_variable_attributes const&))
89     BOOST_DELETED_FUNCTION(pthread_condition_variable_attributes& operator=(pthread_condition_variable_attributes const&))
90 };
91 
92 //! Interprocess mutex wrapper
93 struct interprocess_mutex
94 {
95     struct auto_unlock
96     {
auto_unlockboost::ipc::aux::interprocess_mutex::auto_unlock97         explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
~auto_unlockboost::ipc::aux::interprocess_mutex::auto_unlock98         ~auto_unlock() { m_mutex.unlock(); }
99 
100         BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
101         BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
102 
103     private:
104         interprocess_mutex& m_mutex;
105     };
106 
107     pthread_mutex_t mutex;
108 
interprocess_mutexboost::ipc::aux::interprocess_mutex109     interprocess_mutex()
110     {
111         pthread_mutex_attributes attrs;
112         int err = pthread_mutexattr_settype(&attrs.attrs, PTHREAD_MUTEX_NORMAL);
113         if (BOOST_UNLIKELY(err != 0))
114             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to set pthread mutex type", (err));
115         err = pthread_mutexattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED);
116         if (BOOST_UNLIKELY(err != 0))
117             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex process-shared", (err));
118 #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
119         err = pthread_mutexattr_setrobust(&attrs.attrs, PTHREAD_MUTEX_ROBUST);
120         if (BOOST_UNLIKELY(err != 0))
121             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex robust", (err));
122 #endif
123 
124         err = pthread_mutex_init(&this->mutex, &attrs.attrs);
125         if (BOOST_UNLIKELY(err != 0))
126             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex", (err));
127     }
128 
~interprocess_mutexboost::ipc::aux::interprocess_mutex129     ~interprocess_mutex()
130     {
131         BOOST_VERIFY(pthread_mutex_destroy(&this->mutex) == 0);
132     }
133 
lockboost::ipc::aux::interprocess_mutex134     void lock()
135     {
136         int err = pthread_mutex_lock(&this->mutex);
137 #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
138         if (BOOST_UNLIKELY(err == EOWNERDEAD))
139             throw lock_owner_dead();
140 #endif
141         if (BOOST_UNLIKELY(err != 0))
142             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to lock pthread mutex", (err));
143     }
144 
unlockboost::ipc::aux::interprocess_mutex145     void unlock() BOOST_NOEXCEPT
146     {
147         BOOST_VERIFY(pthread_mutex_unlock(&this->mutex) == 0);
148     }
149 
150 #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
recoverboost::ipc::aux::interprocess_mutex151     void recover()
152     {
153         int err = pthread_mutex_consistent(&this->mutex);
154         if (BOOST_UNLIKELY(err != 0))
155             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to recover pthread mutex from a crashed thread", (err));
156     }
157 #endif
158 
159     BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
160     BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
161 };
162 
163 //! Interprocess condition variable wrapper
164 struct interprocess_condition_variable
165 {
166     pthread_cond_t cond;
167 
interprocess_condition_variableboost::ipc::aux::interprocess_condition_variable168     interprocess_condition_variable()
169     {
170         pthread_condition_variable_attributes attrs;
171         int err = pthread_condattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED);
172         if (BOOST_UNLIKELY(err != 0))
173             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread condition variable process-shared", (err));
174 
175         err = pthread_cond_init(&this->cond, &attrs.attrs);
176         if (BOOST_UNLIKELY(err != 0))
177             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable", (err));
178     }
179 
~interprocess_condition_variableboost::ipc::aux::interprocess_condition_variable180     ~interprocess_condition_variable()
181     {
182         BOOST_VERIFY(pthread_cond_destroy(&this->cond) == 0);
183     }
184 
notify_oneboost::ipc::aux::interprocess_condition_variable185     void notify_one()
186     {
187         int err = pthread_cond_signal(&this->cond);
188         if (BOOST_UNLIKELY(err != 0))
189             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify one thread on a pthread condition variable", (err));
190     }
191 
notify_allboost::ipc::aux::interprocess_condition_variable192     void notify_all()
193     {
194         int err = pthread_cond_broadcast(&this->cond);
195         if (BOOST_UNLIKELY(err != 0))
196             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify all threads on a pthread condition variable", (err));
197     }
198 
waitboost::ipc::aux::interprocess_condition_variable199     void wait(interprocess_mutex& mutex)
200     {
201         int err = pthread_cond_wait(&this->cond, &mutex.mutex);
202         if (BOOST_UNLIKELY(err != 0))
203             BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to wait on a pthread condition variable", (err));
204     }
205 
206     BOOST_DELETED_FUNCTION(interprocess_condition_variable(interprocess_condition_variable const&))
207     BOOST_DELETED_FUNCTION(interprocess_condition_variable& operator=(interprocess_condition_variable const&))
208 };
209 
210 #else // defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
211 
212 // If there are no process-shared pthread primitives, use whatever emulation Boost.Interprocess implements
213 struct interprocess_mutex
214 {
215     struct auto_unlock
216     {
217         explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
218         ~auto_unlock() { m_mutex.unlock(); }
219 
220         BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
221         BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
222 
223     private:
224         interprocess_mutex& m_mutex;
225     };
226 
227     BOOST_DEFAULTED_FUNCTION(interprocess_mutex(), {})
228 
229     // Members to emulate a lock interface
230     typedef boost::interprocess::interprocess_mutex mutex_type;
231 
232     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
233     bool operator! () const BOOST_NOEXCEPT { return false; }
234     mutex_type* mutex() BOOST_NOEXCEPT { return &m_mutex; }
235 
236     void lock()
237     {
238         m_mutex.lock();
239     }
240 
241     void unlock() BOOST_NOEXCEPT
242     {
243         m_mutex.unlock();
244     }
245 
246     mutex_type m_mutex;
247 
248     BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
249     BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
250 };
251 
252 
253 typedef boost::interprocess::interprocess_condition interprocess_condition_variable;
254 
255 #endif // defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
256 
257 } // namespace aux
258 
259 } // namespace ipc
260 
261 BOOST_LOG_CLOSE_NAMESPACE // namespace log
262 
263 } // namespace boost
264 
265 #include <boost/log/detail/footer.hpp>
266 
267 #endif // BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
268