// bslmt_mutexassert.h                                                -*-C++-*-
#ifndef INCLUDED_BSLMT_MUTEXASSERT
#define INCLUDED_BSLMT_MUTEXASSERT

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an assert macro for verifying that a mutex is locked.
//
//@CLASSES:
//
//@MACROS:
//  BSLMT_MUTEXASSERT_IS_LOCKED: verify a mutex is locked in non-opt modes
//  BSLMT_MUTEXASSERT_IS_LOCKED_SAFE: verify a mutex is locked in safe mode
//  BSLMT_MUTEXASSERT_IS_LOCKED_OPT: verify a mutex is locked in all modes
//
//@SEE_ALSO: bslmt_mutex
//
//@DESCRIPTION: This component provides macros for asserting that a mutex is
// locked.  It does not distinguish between locks held by the current thread or
// other threads.  If the macro is active in the current build mode, when the
// macro is called, if the supplied mutex is unlocked, the assert handler
// installed for `BSLS_ASSERT` will be called.  The assert handler installed by
// default will report an error and abort the task.
//
// The three macros defined by the component are analogous to the macros
// defined by `BSLS_ASSERT`:
//
// * `BSLMT_MUTEXASSERT_IS_LOCKED`: active when `BSLS_ASSERT` is active
// * `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`: active when `BSLS_ASSERT_SAFE` is
//   active
// * `BSLMT_MUTEXASSERT_IS_LOCKED_OPT`: active when `BSLS_ASSERT_OPT` is
//   active
//
// In build modes where any one of these macros is not active, calling it will
// have no effect.
//
// If any of these asserts are in effect and fail (because the mutex in
// question was unlocked), the behavior parallels the behavior of the assertion
// macros defined in `bsls_assert.h` -- `bsls::Assert::invokeHandler` is
// called, with a source code expression, the name of the source file, and the
// line number in the source file where the macro was called.  If the default
// handler is installed, this will result in an error message and an abort.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Checking Consistency Within a Private Method
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Sometimes multithreaded code is written such that the author of a function
// requires that a caller has already acquired a mutex.  The
// `BSLMT_MUTEXASSERT_IS_LOCKED*` family of assertions allows the programmers
// to verify, using defensive programming techniques, that the mutex in
// question is indeed locked.
//
// Suppose we have a fully thread-safe queue that contains `int` values, and is
// guarded by an internal mutex.  We can use `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`
// to ensure (in appropriate build modes) that proper internal locking of the
// mutex is taking place.
//
// First, we define the container:
// ```
// /// This `class` provides a fully *thread-safe* unidirectional queue of
// /// `int` values.  See {`bsls_glossary`|Fully Thread-Safe}.  All public
// /// manipulators operate as single, atomic actions.
// class MyThreadSafeQueue {
//
//     // DATA
//     bsl::deque<int>      d_deque;    // underlying non-*thread-safe*
//                                      // standard container
//
//     mutable bslmt::Mutex  d_mutex;    // mutex to provide thread safety
//
//     // PRIVATE MANIPULATOR
//
//     /// Assign the value at the front of the queue to the specified
//     /// `*result`, and remove the value at the front of the queue;
//     /// return 0 if the queue was not initially empty, and a non-zero
//     /// value (with no effect) otherwise.  The behavior is undefined
//     /// unless `d_mutex` is locked.
//     int popImp(int *result);
//
//   public:
//     // ...
//
//     // MANIPULATORS
//
//     /// Assign the value at the front of the queue to the specified
//     /// `*result`, and remove the value at the front of the queue;
//     /// return 0 if the queue was not initially empty, and a non-zero
//     /// value (with no effect) otherwise.
//     int pop(int *result);
//
//     /// Assign the values of all the elements from this queue, in order,
//     /// to the specified `*result`, and remove them from this queue.
//     /// Any previous contents of `*result` are discarded.  Note that, as
//     /// with the other public manipulators, this entire operation occurs
//     /// as a single, atomic action.
//     void popAll(bsl::vector<int> *result);
//
//     /// ...
//     void push(int value);
//
//     /// ...
//     template <class INPUT_ITER>
//     void pushRange(const INPUT_ITER& first, const INPUT_ITER& last);
// };
// ```
// Notice that our public manipulators have two forms: push/pop a single
// element, and push/pop a collection of elements.  Popping even a single
// element is non-trivial, so we factor this operation into a non-*thread-safe*
// private manipulator that performs the pop, and is used in both public `pop`
// methods.  This private manipulator requires that the mutex be locked, but
// cannot lock the mutex itself, since the correctness of `popAll` demands that
// all of the pops be collectively performed using a single mutex lock/unlock.
//
// Then, we define the private manipulator:
// ```
// // PRIVATE MANIPULATOR
// int MyThreadSafeQueue::popImp(int *result)
// {
//     BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex);
//
//     if (d_deque.empty()) {
//         return -1;                                                // RETURN
//     }
//     else {
//         *result = d_deque.front();
//         d_deque.pop_front();
//         return 0;                                                 // RETURN
//     }
// }
// ```
// Notice that, on the very first line, the private manipulator verifies, as a
// precondition check, that the mutex has been acquired, using one of the
// `BSLMT_MUTEXASSERT_IS_LOCKED*` macros.  We use the `...IS_LOCKED_SAFE...`
// version of the macro so that the check, which on some platforms is as
// expensive as locking the mutex, is performed in only the safe build mode.
//
// Next, we define the public manipulators; each of which must acquire a lock
// on the mutex (note that there is a bug in `popAll`):
// ```
// // MANIPULATORS
// int MyThreadSafeQueue::pop(int *result)
// {
//     BSLS_ASSERT(result);
//
//     d_mutex.lock();
//     int rc = popImp(result);
//     d_mutex.unlock();
//     return rc;
// }
//
// void MyThreadSafeQueue::popAll(bsl::vector<int> *result)
// {
//     BSLS_ASSERT(result);
//
//     const int size = static_cast<int>(d_deque.size());
//     result->resize(size);
//     int *begin = result->begin();
//     for (int index = 0; index < size; ++index) {
//         int rc = popImp(&begin[index]);
//         BSLS_ASSERT(0 == rc);
//     }
// }
//
// void MyThreadSafeQueue::push(int value)
// {
//     d_mutex.lock();
//     d_deque.push_back(value);
//     d_mutex.unlock();
// }
//
// template <class INPUT_ITER>
// void MyThreadSafeQueue::pushRange(const INPUT_ITER& first,
//                                   const INPUT_ITER& last)
// {
//     d_mutex.lock();
//     d_deque.insert(d_deque.begin(), first, last);
//     d_mutex.unlock();
// }
// ```
// Notice that, in `popAll`, we forgot to lock/unlock the mutex!
//
// Then, in our function `example2Function`, we make use of our class to create
// and exercise a `MyThreadSafeQueue` object:
// ```
// void testThreadSafeQueue(bsl::ostream& stream)
// {
//     MyThreadSafeQueue queue;
// ```
// Next, we populate the queue using `pushRange`:
// ```
//     const int rawData[] = { 17, 3, 21, -19, 4, 87, 29, 3, 101, 31, 36 };
//     enum { k_RAW_DATA_LENGTH = sizeof rawData / sizeof *rawData };
//
//     queue.pushRange(rawData + 0, rawData + k_RAW_DATA_LENGTH);
// ```
// Then, we pop a few items off the front of the queue and verify their values:
// ```
//     int value = -1;
//
//     assert(0 == queue.pop(&value));    assert(17 == value);
//     assert(0 == queue.pop(&value));    assert( 3 == value);
//     assert(0 == queue.pop(&value));    assert(21 == value);
// ```
// Next, we attempt to empty the queue with `popAll`, which, if built in safe
// mode, would fail because it neglects to lock the mutex:
// ```
//     bsl::vector<int> v;
//     queue.popAll(&v);
//
//     stream << "Remaining raw numbers: ";
//     for (bsl::size_t ti = 0; ti < v.size(); ++ti) {
//         stream << (ti ? ", " : "") << v[ti];
//     }
//     stream << bsl::endl;
// }
// ```
// Then, we build in non-safe mode and run:
// ```
// Remaining raw numbers: -19, 4, 87, 29, 3, 101, 31, 36
// ```
// Notice that, since the test case is being run in a single thread and our
// check is disabled, the bug where the mutex was not acquired does not
// manifest itself in a visible error, and we observe the seemingly correct
// output.
//
// Now, we build in safe mode (which enables our check), run the program (which
// calls `example2Function`), and observe that, when we call `popAll`, the
// `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex)` macro issues an error message
// and aborts:
// ```
// Assertion failed: BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(&d_mutex),
// file bslmt_mutexassertislocked.t.cpp, line 137 Aborted (core dumped)
// ```
// Finally, note that the message printed above and the subsequent aborting of
// the program were the result of a call to `bsls::Assert::invokeHandler`,
// which in this case was configured (by default) to call
// `bsls::Assert::failAbort`.  Other handlers may be installed that produce
// different results, but in all cases should prevent the program from
// proceeding normally.

#include <bslscm_version.h>

#include <bsls_assert.h>

#if defined(BSLS_ASSERT_IS_ACTIVE)
    #define BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p) do {                         \
        BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl(              \
                           (mutex_p),                                         \
                           "BSLMT_MUTEXASSERT_IS_LOCKED(" #mutex_p ")",       \
                           __FILE__,                                          \
                           __LINE__); } while (false)
#else
    #define BSLMT_MUTEXASSERT_IS_LOCKED(mutex_p) ((void) 0)
#endif

#if defined(BSLS_ASSERT_SAFE_IS_ACTIVE)
    #define BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(mutex_p) do {                    \
        BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl(              \
                           (mutex_p),                                         \
                           "BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(" #mutex_p ")",  \
                           __FILE__,                                          \
                           __LINE__); } while (false)
#else
    #define BSLMT_MUTEXASSERT_IS_LOCKED_SAFE(mutex_p) ((void) 0)
#endif

#if defined(BSLS_ASSERT_OPT_IS_ACTIVE)
    #define BSLMT_MUTEXASSERT_IS_LOCKED_OPT(mutex_p) do {                     \
        BloombergLP::bslmt::MutexAssert_Imp::assertIsLockedImpl(              \
                           (mutex_p),                                         \
                           "BSLMT_MUTEXASSERT_IS_LOCKED_OPT(" #mutex_p ")",   \
                           __FILE__,                                          \
                           __LINE__); } while (false)
#else
    #define BSLMT_MUTEXASSERT_IS_LOCKED_OPT(mutex_p) ((void) 0)
#endif

namespace BloombergLP {
namespace bslmt {

class Mutex;

                          // =====================
                          // class MutexAssert_Imp
                          // =====================

/// This `struct` provides a (component private) namespace for
/// implementation functions of the assert macros defined in this component.
/// This class should *not* be used directly in client code.
struct MutexAssert_Imp {

    // CLASS METHODS

    /// If the specified `mutex` is not locked, call
    /// `bsls::Assert::invokeHandler` with the specified `text`, `file`, and
    /// `line`, where `text` is text describing the assertion being
    /// performed, `file` is the name of the source file that called the
    /// macro, and `line` is the line number in the file where the macro was
    /// called.  This function is intended to implement
    /// `BSLMT_MUTEXASSERT_IS_LOCKED`, `BSLMT_MUTEXASSERT_IS_LOCKED_SAFE`,
    /// and `BSLMT_MUTEXASSERT_IS_LOCKED_OPT` and should not otherwise be
    /// called directly.
    static void assertIsLockedImpl(Mutex      *mutex,
                                   const char *text,
                                   const char *file,
                                   int         line);
};

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
