BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmt_mutexassert.h
Go to the documentation of this file.
1/// @file bslmt_mutexassert.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_mutexassert.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_MUTEXASSERT
9#define INCLUDED_BSLMT_MUTEXASSERT
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_mutexassert bslmt_mutexassert
15/// @brief Provide an assert macro for verifying that a mutex is locked.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_mutexassert
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_mutexassert-purpose"> Purpose</a>
25/// * <a href="#bslmt_mutexassert-classes"> Classes </a>
26/// * <a href="#bslmt_mutexassert-macros"> Macros </a>
27/// * <a href="#bslmt_mutexassert-description"> Description </a>
28/// * <a href="#bslmt_mutexassert-usage"> Usage </a>
29/// * <a href="#bslmt_mutexassert-example-1-checking-consistency-within-a-private-method"> Example 1: Checking Consistency Within a Private Method </a>
30///
31/// # Purpose {#bslmt_mutexassert-purpose}
32/// Provide an assert macro for verifying that a mutex is locked.
33///
34/// # Classes {#bslmt_mutexassert-classes}
35///
36///
37/// # Macros {#bslmt_mutexassert-macros}
38///
39/// - BSLMT_MUTEXASSERT_IS_LOCKED: verify a mutex is locked in non-opt modes
40/// - BSLMT_MUTEXASSERT_IS_LOCKED_SAFE: verify a mutex is locked in safe mode
41/// - BSLMT_MUTEXASSERT_IS_LOCKED_OPT: verify a mutex is locked in all modes
42///
43/// @see bslmt_mutex
44///
45/// # Description {#bslmt_mutexassert-description}
46/// This component provides macros for asserting that a mutex is
47/// locked. It does not distinguish between locks held by the current thread or
48/// other threads. If the macro is active in the current build mode, when the
49/// macro is called, if the supplied mutex is unlocked, the assert handler
50/// installed for `BSLS_ASSERT` will be called. The assert handler installed by
51/// default will report an error and abort the task.
52///
53/// The three macros defined by the component are analogous to the macros
54/// defined by `BSLS_ASSERT`:
55///
56/// * `BSLMT_MUTEXASSERT_IS_LOCKED`: active when `BSLS_ASSERT` is active
57/// * `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`: active when `BSLS_ASSERT_SAFE` is
58/// active
59/// * `BSLMT_MUTEXASSERT_IS_LOCKED_OPT`: active when `BSLS_ASSERT_OPT` is
60/// active
61///
62/// In build modes where any one of these macros is not active, calling it will
63/// have no effect.
64///
65/// If any of these asserts are in effect and fail (because the mutex in
66/// question was unlocked), the behavior parallels the behavior of the assertion
67/// macros defined in `bsls_assert.h` -- `bsls::Assert::invokeHandler` is
68/// called, with a source code expression, the name of the source file, and the
69/// line number in the source file where the macro was called. If the default
70/// handler is installed, this will result in an error message and an abort.
71///
72/// ## Usage {#bslmt_mutexassert-usage}
73///
74///
75/// This section illustrates intended use of this component.
76///
77/// ### Example 1: Checking Consistency Within a Private Method {#bslmt_mutexassert-example-1-checking-consistency-within-a-private-method}
78///
79///
80/// Sometimes multithreaded code is written such that the author of a function
81/// requires that a caller has already acquired a mutex. The
82/// `BSLMT_MUTEXASSERT_IS_LOCKED*` family of assertions allows the programmers
83/// to verify, using defensive programming techniques, that the mutex in
84/// question is indeed locked.
85///
86/// Suppose we have a fully thread-safe queue that contains `int` values, and is
87/// guarded by an internal mutex. We can use `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`
88/// to ensure (in appropriate build modes) that proper internal locking of the
89/// mutex is taking place.
90///
91/// First, we define the container:
92/// @code
93/// /// This `class` provides a fully *thread-safe* unidirectional queue of
94/// /// `int` values. See {`bsls_glossary`|Fully Thread-Safe}. All public
95/// /// manipulators operate as single, atomic actions.
96/// class MyThreadSafeQueue {
97///
98/// // DATA
99/// bsl::deque<int> d_deque; // underlying non-*thread-safe*
100/// // standard container
101///
102/// mutable bslmt::Mutex d_mutex; // mutex to provide thread safety
103///
104/// // PRIVATE MANIPULATOR
105///
106/// /// Assign the value at the front of the queue to the specified
107/// /// `*result`, and remove the value at the front of the queue;
108/// /// return 0 if the queue was not initially empty, and a non-zero
109/// /// value (with no effect) otherwise. The behavior is undefined
110/// /// unless `d_mutex` is locked.
111/// int popImp(int *result);
112///
113/// public:
114/// // ...
115///
116/// // MANIPULATORS
117///
118/// /// Assign the value at the front of the queue to the specified
119/// /// `*result`, and remove the value at the front of the queue;
120/// /// return 0 if the queue was not initially empty, and a non-zero
121/// /// value (with no effect) otherwise.
122/// int pop(int *result);
123///
124/// /// Assign the values of all the elements from this queue, in order,
125/// /// to the specified `*result`, and remove them from this queue.
126/// /// Any previous contents of `*result` are discarded. Note that, as
127/// /// with the other public manipulators, this entire operation occurs
128/// /// as a single, atomic action.
129/// void popAll(bsl::vector<int> *result);
130///
131/// /// ...
132/// void push(int value);
133///
134/// /// ...
135/// template <class INPUT_ITER>
136/// void pushRange(const INPUT_ITER& first, const INPUT_ITER& last);
137/// };
138/// @endcode
139/// Notice that our public manipulators have two forms: push/pop a single
140/// element, and push/pop a collection of elements. Popping even a single
141/// element is non-trivial, so we factor this operation into a non-*thread-safe*
142/// private manipulator that performs the pop, and is used in both public `pop`
143/// methods. This private manipulator requires that the mutex be locked, but
144/// cannot lock the mutex itself, since the correctness of `popAll` demands that
145/// all of the pops be collectively performed using a single mutex lock/unlock.
146///
147/// Then, we define the private manipulator:
148/// @code
149/// // PRIVATE MANIPULATOR
150/// int MyThreadSafeQueue::popImp(int *result)
151/// {
152/// BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex);
153///
154/// if (d_deque.empty()) {
155/// return -1; // RETURN
156/// }
157/// else {
158/// *result = d_deque.front();
159/// d_deque.pop_front();
160/// return 0; // RETURN
161/// }
162/// }
163/// @endcode
164/// Notice that, on the very first line, the private manipulator verifies, as a
165/// precondition check, that the mutex has been acquired, using one of the
166/// `BSLMT_MUTEXASSERT_IS_LOCKED*` macros. We use the `...IS_LOCKED_SAFE...`
167/// version of the macro so that the check, which on some platforms is as
168/// expensive as locking the mutex, is performed in only the safe build mode.
169///
170/// Next, we define the public manipulators; each of which must acquire a lock
171/// on the mutex (note that there is a bug in `popAll`):
172/// @code
173/// // MANIPULATORS
174/// int MyThreadSafeQueue::pop(int *result)
175/// {
176/// BSLS_ASSERT(result);
177///
178/// d_mutex.lock();
179/// int rc = popImp(result);
180/// d_mutex.unlock();
181/// return rc;
182/// }
183///
184/// void MyThreadSafeQueue::popAll(bsl::vector<int> *result)
185/// {
186/// BSLS_ASSERT(result);
187///
188/// const int size = static_cast<int>(d_deque.size());
189/// result->resize(size);
190/// int *begin = result->begin();
191/// for (int index = 0; index < size; ++index) {
192/// int rc = popImp(&begin[index]);
193/// BSLS_ASSERT(0 == rc);
194/// }
195/// }
196///
197/// void MyThreadSafeQueue::push(int value)
198/// {
199/// d_mutex.lock();
200/// d_deque.push_back(value);
201/// d_mutex.unlock();
202/// }
203///
204/// template <class INPUT_ITER>
205/// void MyThreadSafeQueue::pushRange(const INPUT_ITER& first,
206/// const INPUT_ITER& last)
207/// {
208/// d_mutex.lock();
209/// d_deque.insert(d_deque.begin(), first, last);
210/// d_mutex.unlock();
211/// }
212/// @endcode
213/// Notice that, in `popAll`, we forgot to lock/unlock the mutex!
214///
215/// Then, in our function `example2Function`, we make use of our class to create
216/// and exercise a `MyThreadSafeQueue` object:
217/// @code
218/// void testThreadSafeQueue(bsl::ostream& stream)
219/// {
220/// MyThreadSafeQueue queue;
221/// @endcode
222/// Next, we populate the queue using `pushRange`:
223/// @code
224/// const int rawData[] = { 17, 3, 21, -19, 4, 87, 29, 3, 101, 31, 36 };
225/// enum { k_RAW_DATA_LENGTH = sizeof rawData / sizeof *rawData };
226///
227/// queue.pushRange(rawData + 0, rawData + k_RAW_DATA_LENGTH);
228/// @endcode
229/// Then, we pop a few items off the front of the queue and verify their values:
230/// @code
231/// int value = -1;
232///
233/// assert(0 == queue.pop(&value)); assert(17 == value);
234/// assert(0 == queue.pop(&value)); assert( 3 == value);
235/// assert(0 == queue.pop(&value)); assert(21 == value);
236/// @endcode
237/// Next, we attempt to empty the queue with `popAll`, which, if built in safe
238/// mode, would fail because it neglects to lock the mutex:
239/// @code
240/// bsl::vector<int> v;
241/// queue.popAll(&v);
242///
243/// stream << "Remaining raw numbers: ";
244/// for (bsl::size_t ti = 0; ti < v.size(); ++ti) {
245/// stream << (ti ? ", " : "") << v[ti];
246/// }
247/// stream << bsl::endl;
248/// }
249/// @endcode
250/// Then, we build in non-safe mode and run:
251/// @code
252/// Remaining raw numbers: -19, 4, 87, 29, 3, 101, 31, 36
253/// @endcode
254/// Notice that, since the test case is being run in a single thread and our
255/// check is disabled, the bug where the mutex was not acquired does not
256/// manifest itself in a visible error, and we observe the seemingly correct
257/// output.
258///
259/// Now, we build in safe mode (which enables our check), run the program (which
260/// calls `example2Function`), and observe that, when we call `popAll`, the
261/// `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex)` macro issues an error message
262/// and aborts:
263/// @code
264/// Assertion failed: BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex),
265/// file bslmt_mutexassertislocked.t.cpp, line 137 Aborted (core dumped)
266/// @endcode
267/// Finally, note that the message printed above and the subsequent aborting of
268/// the program were the result of a call to `bsls::Assert::invokeHandler`,
269/// which in this case was configured (by default) to call
270/// `bsls::Assert::failAbort`. Other handlers may be installed that produce
271/// different results, but in all cases should prevent the program from
272/// proceeding normally.
273/// @}
274/** @} */
275/** @} */
276
277/** @addtogroup bsl
278 * @{
279 */
280/** @addtogroup bslmt
281 * @{
282 */
283/** @addtogroup bslmt_mutexassert
284 * @{
285 */
286
287#include <bslscm_version.h>
288
289#include <bsls_assert.h>
290
291#if defined(BSLS_ASSERT_IS_ACTIVE)
292 #define BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p) do { \
293 BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl( \
294 (mutex_p), \
295 "BSLMT_MUTEXASSERT_IS_LOCKED(" #mutex_p ")", \
296 __FILE__, \
297 __LINE__); } while (false)
298#else
299 #define BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p) ((void) 0)
300#endif
301
302#if defined(BSLS_ASSERT_SAFE_IS_ACTIVE)
303 #define BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(mutex_p) do { \
304 BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl( \
305 (mutex_p), \
306 "BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(" #mutex_p ")", \
307 __FILE__, \
308 __LINE__); } while (false)
309#else
310 #define BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(mutex_p) ((void) 0)
311#endif
312
313#if defined(BSLS_ASSERT_OPT_IS_ACTIVE)
314 #define BSLMT_MUTEXASSERT_IS_LOCKED_OPT(mutex_p) do { \
315 BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl( \
316 (mutex_p), \
317 "BSLMT_MUTEXASSERT_IS_LOCKED_OPT(" #mutex_p ")", \
318 __FILE__, \
319 __LINE__); } while (false)
320#else
321 #define BSLMT_MUTEXASSERT_IS_LOCKED_OPT(mutex_p) ((void) 0)
322#endif
323
324
325namespace bslmt {
326
327class Mutex;
328
329 // =====================
330 // class MutexAssert_Imp
331 // =====================
332
333/// This `struct` provides a (component private) namespace for
334/// implementation functions of the assert macros defined in this component.
335/// This class should *not* be used directly in client code.
337
338 // CLASS METHODS
339
340 /// If the specified `mutex` is not locked, call
341 /// `bsls::Assert::invokeHandler` with the specified `text`, `file`, and
342 /// `line`, where `text` is text describing the assertion being
343 /// performed, `file` is the name of the source file that called the
344 /// macro, and `line` is the line number in the file where the macro was
345 /// called. This function is intended to implement
346 /// `BSLMT_MUTEXASSERT_IS_LOCKED`, `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`,
347 /// and `BSLMT_MUTEXASSERT_IS_LOCKED_OPT` and should not otherwise be
348 /// called directly.
349 static void assertIsLockedImpl(Mutex *mutex,
350 const char *text,
351 const char *file,
352 int line);
353};
354
355} // close package namespace
356
357
358#endif
359
360// ----------------------------------------------------------------------------
361// Copyright 2015 Bloomberg Finance L.P.
362//
363// Licensed under the Apache License, Version 2.0 (the "License");
364// you may not use this file except in compliance with the License.
365// You may obtain a copy of the License at
366//
367// http://www.apache.org/licenses/LICENSE-2.0
368//
369// Unless required by applicable law or agreed to in writing, software
370// distributed under the License is distributed on an "AS IS" BASIS,
371// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
372// See the License for the specific language governing permissions and
373// limitations under the License.
374// ----------------------------- END-OF-FILE ----------------------------------
375
376/** @} */
377/** @} */
378/** @} */
Definition bslmt_mutex.h:315
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslmt_barrier.h:344
Definition bslmt_mutexassert.h:336
static void assertIsLockedImpl(Mutex *mutex, const char *text, const char *file, int line)