/*
 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */

#ifndef BU_DEBUG_MUTEX_H
#define BU_DEBUG_MUTEX_H

#include "bu/mutex.h"
#include "bu/list.h"
#include "bu/string.h"

namespace Bu
{
    /**
     * Simple mutex wrapper.  Currently this doesn't do anything extra for you
     * except keep all of the functionality together in an OO sorta' way and
     * keep you from having to worry about cleaning up your mutexes properly,
     * or initing them.
     *@ingroup Threading
     */
    class DebugMutex : public Mutex
    {
    public:
        /**
         * Create an unlocked mutex.
         */
        DebugMutex();
        
        /**
         * Destroy a mutex.  This can only be done when a mutex is unlocked.
         * Failure to unlock before destroying a mutex object could cause it to
         * wait for the mutex to unlock, the odds of which are usually farily
         * low at deconstruction time.
         */
        virtual ~DebugMutex();

        /**
         * Lock the mutex.  This causes all future calls to lock on this
         * instance of mutex to block until the first thread that called mutex
         * unlocks it.  At that point the next thread that called lock will get
         * a chance to go to work.  Because of the nature of a mutex lock it is
         * a very bad idea to do any kind of serious or rather time consuming
         * computation within a locked section.  This can cause thread-deadlock
         * and your program may hang.
         */
        virtual int lock();

        /**
         * Unlock the mutex.  This allows the next thread that asked for a lock
         * to lock the mutex and continue with execution.
         */
        virtual int unlock();

        /**
         * Try to lock the mutex.  This is the option to go with if you cannot
         * avoid putting lengthy operations within a locked section.  trylock
         * will attempt to lock the mutex, if the mutex is already locked this
         * function returns immediately with an error code.
         */
        virtual int trylock();

    private:
        Bu::Mutex mState;

        class ThreadInfo
        {
        public:
            ThreadInfo( bool bLocked=false ) :
                idThread( pthread_self() ),
                bLocked( bLocked )
            {
                char buf[64];
                if( pthread_getname_np( idThread, buf, 64 ) == 0 )
                    sName = buf;
            }
            ~ThreadInfo() {}

            bool operator==( const ThreadInfo &rhs )
            {
                return pthread_equal( idThread, rhs.idThread );
            }

            bool operator==( const pthread_t &rhs )
            {
                return pthread_equal( idThread, rhs );
            }

            pthread_t idThread;
            Bu::String sName;
            bool bLocked;
        };
        typedef Bu::List<ThreadInfo> ThreadList;
        ThreadList lThreads;
    };
}

#endif


