LogCabin
|
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