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