From 700d4bbcbf59c4447becbab21a6aa7204a8da2f4 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 6 Nov 2024 16:01:36 -0800 Subject: I believe MyriadFs is now threadsafe. It could probably be more optimized, but it does work. --- src/experimental/debugmutex.cpp | 78 ++++++++++++++++++++++++++++++ src/experimental/debugmutex.h | 102 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 src/experimental/debugmutex.cpp create mode 100644 src/experimental/debugmutex.h (limited to 'src/experimental') diff --git a/src/experimental/debugmutex.cpp b/src/experimental/debugmutex.cpp new file mode 100644 index 0000000..2b61ae2 --- /dev/null +++ b/src/experimental/debugmutex.cpp @@ -0,0 +1,78 @@ +#include "bu/debugmutex.h" + +#include "bu/exceptionbase.h" + +Bu::DebugMutex::DebugMutex() +{ +} + +Bu::DebugMutex::~DebugMutex() +{ +} + +int Bu::DebugMutex::lock() +{ + pthread_t self = pthread_self(); + mState.lock(); + bool bFound = false; + for( ThreadList::iterator i = lThreads.begin(); i; i++ ) + { + if( (*i) == self ) + { + bFound = true; + if( (*i).bLocked == true ) + { + throw Bu::ExceptionBase( Bu::String("Double lock in thread: %1").arg( (*i).sName ).end().getStr() ); + + } + else + { + (*i).bLocked = true; + } + break; + } + } + if( bFound == false ) + { + lThreads.append( ThreadInfo( true ) ); + } + mState.unlock(); + return Bu::Mutex::lock(); +} + +int Bu::DebugMutex::unlock() +{ + pthread_t self = pthread_self(); + mState.lock(); + bool bFound = false; + for( ThreadList::iterator i = lThreads.begin(); i; i++ ) + { + if( (*i) == self ) + { + bFound = true; + if( (*i).bLocked == false ) + { + throw Bu::ExceptionBase( Bu::String("Unlock in thread that did not lock: %1").arg( (*i).sName ).end().getStr() ); + + } + else + { + (*i).bLocked = false; + } + break; + } + } + if( bFound == false ) + { + ThreadInfo info( false ); + throw Bu::ExceptionBase( Bu::String("Unlock in thread that never locked mutex: %1").arg( info.sName ).end().getStr() ); + } + mState.unlock(); + return Bu::Mutex::unlock(); +} + +int Bu::DebugMutex::trylock() +{ + return Bu::Mutex::trylock(); +} + diff --git a/src/experimental/debugmutex.h b/src/experimental/debugmutex.h new file mode 100644 index 0000000..ca8ef9f --- /dev/null +++ b/src/experimental/debugmutex.h @@ -0,0 +1,102 @@ +/* + * 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 ThreadList; + ThreadList lThreads; + }; +} + +#endif + + -- cgit v1.2.3