LogCabin
Core/Mutex.h
Go to the documentation of this file.
00001 /* Copyright (c) 2012 Stanford University
00002  *
00003  * Permission to use, copy, modify, and distribute this software for any
00004  * purpose with or without fee is hereby granted, provided that the above
00005  * copyright notice and this permission notice appear in all copies.
00006  *
00007  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00008  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00009  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00010  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00011  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00012  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00013  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00014  */
00015 
00016 #include <cassert>
00017 #include <functional>
00018 #include <mutex>
00019 
00020 #include "Core/Debug.h"
00021 
00022 #ifndef LOGCABIN_CORE_MUTEX_H
00023 #define LOGCABIN_CORE_MUTEX_H
00024 
00025 namespace LogCabin {
00026 namespace Core {
00027 
00028 /**
00029  * A wrapper around std::mutex that is useful for testing purposes. You can set
00030  * a callback to be called when the mutex is locked and before it is unlocked.
00031  * This callback can, for example, check the invariants on the protected state.
00032  *
00033  * The interface to this class is the same as std::mutex.
00034  */
00035 class Mutex {
00036   public:
00037     typedef std::mutex::native_handle_type native_handle_type;
00038 
00039     Mutex()
00040         : m()
00041         , callback()
00042     {
00043     }
00044 
00045     void
00046     lock() {
00047         m.lock();
00048         if (callback)
00049             callback();
00050     }
00051 
00052     bool
00053     try_lock() {
00054         bool l = m.try_lock();
00055         if (l) {
00056             if (callback)
00057                 callback();
00058         }
00059         return l;
00060     }
00061 
00062     void
00063     unlock() {
00064         // TODO(ongardie): apparently try_lock->false...unlock is allowed, but
00065         // this will then call the callback without the lock, which is unsafe.
00066         if (callback)
00067             callback();
00068         m.unlock();
00069     }
00070 
00071     native_handle_type
00072     native_handle() {
00073         return m.native_handle();
00074     }
00075 
00076   private:
00077     /// Underlying mutex.
00078     std::mutex m;
00079   public:
00080     /**
00081      * This function will be called with the lock held after the lock is
00082      * acquired and before it is released.
00083      */
00084     std::function<void()> callback;
00085 
00086     friend class ConditionVariable;
00087 };
00088 
00089 /**
00090  * Release a mutex upon construction, reacquires it upon destruction.
00091  * \tparam Mutex
00092  *      Type of mutex (either std::mutex or Core::Mutex).
00093  */
00094 template<typename Mutex>
00095 class MutexUnlock {
00096   public:
00097     explicit MutexUnlock(std::unique_lock<Mutex>& guard)
00098         : guard(guard)
00099     {
00100         assert(guard.owns_lock());
00101         guard.unlock();
00102     }
00103     ~MutexUnlock()
00104     {
00105         guard.lock();
00106     }
00107   private:
00108     std::unique_lock<Mutex>& guard;
00109 };
00110 
00111 /**
00112  * Proof that the caller is holding some mutex.
00113  * Useful as an additional (unused) argument for some private methods that want
00114  * to ensure the caller is holding a lock.
00115  */
00116 class HoldingMutex {
00117   public:
00118     /**
00119      * Constructor from std::lock_guard.
00120      */
00121     template<typename Mutex>
00122     explicit HoldingMutex(const std::lock_guard<Mutex>& lockGuard) {
00123     }
00124 
00125     /**
00126      * Constructor from std::unique_lock. Since unique_lock might not, in fact,
00127      * hold the lock, this uses a dynamic check in the form of an assert().
00128      */
00129     template<typename Mutex>
00130     explicit HoldingMutex(const std::unique_lock<Mutex>& lockGuard) {
00131         assert(lockGuard.owns_lock());
00132     }
00133 };
00134 
00135 } // namespace LogCabin::Core
00136 } // namespace LogCabin
00137 
00138 #endif // LOGCABIN_CORE_MUTEX_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines