Vault  4.1
vmutex.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00003 This file is part of the Code Vault version 4.1
00004 http://www.bombaydigital.com/
00005 License: MIT. See LICENSE.md in the Vault top level directory.
00006 */
00007 
00010 #include "vmutex.h"
00011 
00012 #include "vexception.h"
00013 #include "vthread.h"
00014 #include "vlogger.h"
00015 
00016 VDuration VMutex::gVMutexLockDelayLoggingThreshold(100 * VDuration::MILLISECOND());
00017 int VMutex::gVMutexLockDelayLoggingLevel(VLoggerLevel::DEBUG);
00018 
00019 VMutex::VMutex(const VString& name, bool suppressLogging)
00020     : mMutex()
00021     , mName(name)
00022     , mSuppressLogging(suppressLogging)
00023     , mLastLockThread((VThreadID_Type) - 1)
00024     , mLastLockerName()
00025     , mLastLockTime(VInstant::NEVER_OCCURRED())
00026     , mIsLocked(false)
00027     {
00028 
00029     if (! VMutex::mutexInit(&mMutex))
00030         throw VStackTraceException(VSTRING_FORMAT("VMutex::VMutex unable to initialize mutex '%s'.", name.chars()));
00031 }
00032 
00033 VMutex::~VMutex() {
00034     VMutex::mutexDestroy(&mMutex);
00035 }
00036 
00037 void VMutex::setName(const VString& name) {
00038     mName = name;
00039 }
00040 
00041 VMutex_Type* VMutex::getMutex() {
00042     return &mMutex;
00043 }
00044 
00045 bool VMutex::isLockedByCurrentThread() const {
00046     return mIsLocked && (mLastLockThread == VThread::threadSelf());
00047 }
00048 
00049 void VMutex::_lock(const VString& lockerName) {
00050 #ifdef VAULT_MUTEX_LOCK_DELAY_CHECK
00051     VInstant start;
00052 #endif
00053     if (VMutex::mutexLock(&mMutex)) {
00054         mLastLockTime.setNow();
00055 
00056 #ifdef VAULT_MUTEX_LOCK_DELAY_CHECK
00057         if ((gVMutexLockDelayLoggingThreshold >= VDuration::ZERO()) && ! mSuppressLogging) {
00058             VInstant end;
00059             VDuration waitTime = end - start;
00060 
00061             if (waitTime >= gVMutexLockDelayLoggingThreshold) {
00062                 VLOGGER_LEVEL(gVMutexLockDelayLoggingLevel, VSTRING_FORMAT("Delay: '%s' was blocked " VSTRING_FORMATTER_S64 "ms on mutex '%s' released by '%s'.",
00063                                                                            lockerName.chars(), waitTime.getDurationMilliseconds(), mName.chars(), mLastLockerName.chars()));
00064             }
00065         }
00066 #endif
00067 
00068         // Note: These properties are only valid with the understanding that they are not set atomically during lock/unlock.
00069         // The only guarantee is that they end up set to their new values after the lock is acquired above, and before we return.
00070         // They may only be used for mutex diagnostics (e.g. isLockedByCurrentThread() and lock delay reporting), not for concurrency control.
00071         mLastLockThread = VThread::threadSelf();
00072         mLastLockerName = lockerName;
00073         mIsLocked = true;
00074     } else {
00075         if (mName.isEmpty()) {
00076             throw VStackTraceException("VMutex::lock unable to lock mutex.");
00077         } else {
00078             throw VStackTraceException(VSTRING_FORMAT("VMutex::lock unable to lock mutex '%s'.", mName.chars()));
00079         }
00080     }
00081 }
00082 
00083 void VMutex::_unlock() {
00084 #ifdef VAULT_MUTEX_LOCK_DELAY_CHECK
00085     if ((gVMutexLockDelayLoggingThreshold >= VDuration::ZERO()) && ! mSuppressLogging) {
00086         VInstant now;
00087         VDuration delay = now - mLastLockTime;
00088         if (delay >= gVMutexLockDelayLoggingThreshold) {
00089             VLOGGER_LEVEL(gVMutexLockDelayLoggingLevel, VSTRING_FORMAT("Delay: '%s' is unlocking mutex '%s' after holding it for " VSTRING_FORMATTER_S64 "ms.",
00090                                                                        mLastLockerName.chars(), mName.chars(), delay.getDurationMilliseconds()));
00091         }
00092     }
00093 #endif
00094 
00095     mIsLocked = false; // Note: Must set false *before* unlocking, otherwise we may set it false after another thread jumps in, locks, sets it true, confusing isLockedByCurrentThread(). Part of non-atomicity warning above.
00096     if (! VMutex::mutexUnlock(&mMutex)) {
00097         mIsLocked = true; // Restore value since we failed to unlock.
00098         if (mName.isEmpty()) {
00099             throw VStackTraceException("VMutex::unlock unable to unlock mutex.");
00100         } else {
00101             throw VStackTraceException(VSTRING_FORMAT("VMutex::unlock unable to unlock mutex '%s'.", mName.chars()));
00102         }
00103     }
00104 }
00105 

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.