Skip to content
Snippets Groups Projects
llmutex.h 3.43 KiB
Newer Older
  • Learn to ignore specific revisions
  • /** 
     * @file llmutex.h
     * @brief Base classes for mutex and condition handling.
     *
     * $LicenseInfo:firstyear=2004&license=viewerlgpl$
     * Second Life Viewer Source Code
     * Copyright (C) 2012, Linden Research, Inc.
     * 
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation;
     * version 2.1 of the License only.
     * 
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
     * 
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     * 
     * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
     * $/LicenseInfo$
     */
    
    #ifndef LL_LLMUTEX_H
    #define LL_LLMUTEX_H
    
    
    
    //============================================================================
    
    #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
    
    
    #if MUTEX_DEBUG
    #include <map>
    #endif
    
    
    struct apr_thread_mutex_t;
    struct apr_pool_t;
    struct apr_thread_cond_t;
    
    
    class LL_COMMON_API LLMutex
    {
    public:
    	typedef enum
    	{
    		NO_THREAD = 0xFFFFFFFF
    	} e_locking_thread;
    
    	LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex
    	virtual ~LLMutex();
    	
    
    Richard Linden's avatar
    Richard Linden committed
    	void lock();		// blocks
    	bool trylock();		// non-blocking, returns true if lock held.
    	void unlock();		// undefined behavior when called on mutex not being held
    	bool isLocked(); 	// non-blocking, but does do a lock/unlock so not free
    	bool isSelfLocked(); //return true if locked in a same thread
    
    	U32 lockingThread() const; //get ID of locking thread
    	
    protected:
    
    Richard Linden's avatar
    Richard Linden committed
    	apr_thread_mutex_t *mAPRMutexp;
    
    	mutable U32			mCount;
    	mutable U32			mLockingThread;
    	
    
    Richard Linden's avatar
    Richard Linden committed
    	apr_pool_t			*mAPRPoolp;
    
    	BOOL				mIsLocalPool;
    	
    #if MUTEX_DEBUG
    	std::map<U32, BOOL> mIsLocked;
    #endif
    };
    
    // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
    class LL_COMMON_API LLCondition : public LLMutex
    {
    public:
    
    	LLCondition(apr_pool_t* apr_poolp); // Defaults to global pool, could use the thread pool as well.
    
    	~LLCondition();
    	
    	void wait();		// blocks
    	void signal();
    	void broadcast();
    	
    protected:
    
    };
    
    class LLMutexLock
    {
    public:
    	LLMutexLock(LLMutex* mutex)
    	{
    		mMutex = mutex;
    		
    		if(mMutex)
    			mMutex->lock();
    	}
    	~LLMutexLock()
    	{
    		if(mMutex)
    			mMutex->unlock();
    	}
    private:
    	LLMutex* mMutex;
    };
    
    
    Richard Linden's avatar
    Richard Linden committed
    //============================================================================
    
    // Scoped locking class similar in function to LLMutexLock but uses
    // the trylock() method to conditionally acquire lock without
    // blocking.  Caller resolves the resulting condition by calling
    // the isLocked() method and either punts or continues as indicated.
    //
    // Mostly of interest to callers needing to avoid stalls who can
    // guarantee another attempt at a later time.
    
    class LLMutexTrylock
    {
    public:
    	LLMutexTrylock(LLMutex* mutex)
    		: mMutex(mutex),
    		  mLocked(false)
    	{
    		if (mMutex)
    			mLocked = mMutex->trylock();
    	}
    
    	~LLMutexTrylock()
    	{
    		if (mMutex && mLocked)
    			mMutex->unlock();
    	}
    
    	bool isLocked() const
    	{
    		return mLocked;
    	}
    	
    private:
    	LLMutex*	mMutex;
    	bool		mLocked;
    };