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
36namespace boost {
37
38BOOST_LOG_OPEN_NAMESPACE
39
40namespace ipc {
41
42namespace aux {
43
44#if defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
45
46#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
47struct BOOST_SYMBOL_VISIBLE lock_owner_dead {};
48#endif
49
50//! Pthread mutex attributes
51struct pthread_mutex_attributes
52{
53 pthread_mutexattr_t attrs;
54
55 pthread_mutex_attributes()
56 {
57 int err = pthread_mutexattr_init(attr: &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
62 ~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
72struct pthread_condition_variable_attributes
73{
74 pthread_condattr_t attrs;
75
76 pthread_condition_variable_attributes()
77 {
78 int err = pthread_condattr_init(attr: &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
83 ~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
93struct interprocess_mutex
94{
95 struct auto_unlock
96 {
97 explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
98 ~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
109 interprocess_mutex()
110 {
111 pthread_mutex_attributes attrs;
112 int err = pthread_mutexattr_settype(attr: &attrs.attrs, kind: 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(attr: &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(mutex: &this->mutex, mutexattr: &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
129 ~interprocess_mutex()
130 {
131 BOOST_VERIFY(pthread_mutex_destroy(&this->mutex) == 0);
132 }
133
134 void lock()
135 {
136 int err = pthread_mutex_lock(mutex: &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
145 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)
151 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
164struct interprocess_condition_variable
165{
166 pthread_cond_t cond;
167
168 interprocess_condition_variable()
169 {
170 pthread_condition_variable_attributes attrs;
171 int err = pthread_condattr_setpshared(attr: &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(cond: &this->cond, cond_attr: &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
180 ~interprocess_condition_variable()
181 {
182 BOOST_VERIFY(pthread_cond_destroy(&this->cond) == 0);
183 }
184
185 void notify_one()
186 {
187 int err = pthread_cond_signal(cond: &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
192 void notify_all()
193 {
194 int err = pthread_cond_broadcast(cond: &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
199 void wait(interprocess_mutex& mutex)
200 {
201 int err = pthread_cond_wait(cond: &this->cond, mutex: &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
213struct 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
253typedef 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
261BOOST_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

source code of boost/libs/log/src/posix/ipc_sync_wrappers.hpp