aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2024-11-06 16:01:36 -0800
committerMike Buland <mike@xagasoft.com>2024-11-06 16:01:36 -0800
commit700d4bbcbf59c4447becbab21a6aa7204a8da2f4 (patch)
treeae68c40a5af2d5bc84ac4bbb192fbbda893d64cc /src
parent6403224b6fe50dfc28d3c25725b6d0910b7eb6c3 (diff)
downloadlibbu++-myriad.tar.gz
libbu++-myriad.tar.bz2
libbu++-myriad.tar.xz
libbu++-myriad.zip
I believe MyriadFs is now threadsafe.myriad
It could probably be more optimized, but it does work.
Diffstat (limited to 'src')
-rw-r--r--src/experimental/debugmutex.cpp78
-rw-r--r--src/experimental/debugmutex.h102
-rw-r--r--src/stable/mutex.h8
-rw-r--r--src/unstable/myriadfs.cpp11
-rw-r--r--src/unstable/myriadfs.h12
5 files changed, 204 insertions, 7 deletions
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 @@
1#include "bu/debugmutex.h"
2
3#include "bu/exceptionbase.h"
4
5Bu::DebugMutex::DebugMutex()
6{
7}
8
9Bu::DebugMutex::~DebugMutex()
10{
11}
12
13int Bu::DebugMutex::lock()
14{
15 pthread_t self = pthread_self();
16 mState.lock();
17 bool bFound = false;
18 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
19 {
20 if( (*i) == self )
21 {
22 bFound = true;
23 if( (*i).bLocked == true )
24 {
25 throw Bu::ExceptionBase( Bu::String("Double lock in thread: %1").arg( (*i).sName ).end().getStr() );
26
27 }
28 else
29 {
30 (*i).bLocked = true;
31 }
32 break;
33 }
34 }
35 if( bFound == false )
36 {
37 lThreads.append( ThreadInfo( true ) );
38 }
39 mState.unlock();
40 return Bu::Mutex::lock();
41}
42
43int Bu::DebugMutex::unlock()
44{
45 pthread_t self = pthread_self();
46 mState.lock();
47 bool bFound = false;
48 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
49 {
50 if( (*i) == self )
51 {
52 bFound = true;
53 if( (*i).bLocked == false )
54 {
55 throw Bu::ExceptionBase( Bu::String("Unlock in thread that did not lock: %1").arg( (*i).sName ).end().getStr() );
56
57 }
58 else
59 {
60 (*i).bLocked = false;
61 }
62 break;
63 }
64 }
65 if( bFound == false )
66 {
67 ThreadInfo info( false );
68 throw Bu::ExceptionBase( Bu::String("Unlock in thread that never locked mutex: %1").arg( info.sName ).end().getStr() );
69 }
70 mState.unlock();
71 return Bu::Mutex::unlock();
72}
73
74int Bu::DebugMutex::trylock()
75{
76 return Bu::Mutex::trylock();
77}
78
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 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_DEBUG_MUTEX_H
9#define BU_DEBUG_MUTEX_H
10
11#include "bu/mutex.h"
12#include "bu/list.h"
13#include "bu/string.h"
14
15namespace Bu
16{
17 /**
18 * Simple mutex wrapper. Currently this doesn't do anything extra for you
19 * except keep all of the functionality together in an OO sorta' way and
20 * keep you from having to worry about cleaning up your mutexes properly,
21 * or initing them.
22 *@ingroup Threading
23 */
24 class DebugMutex : public Mutex
25 {
26 public:
27 /**
28 * Create an unlocked mutex.
29 */
30 DebugMutex();
31
32 /**
33 * Destroy a mutex. This can only be done when a mutex is unlocked.
34 * Failure to unlock before destroying a mutex object could cause it to
35 * wait for the mutex to unlock, the odds of which are usually farily
36 * low at deconstruction time.
37 */
38 virtual ~DebugMutex();
39
40 /**
41 * Lock the mutex. This causes all future calls to lock on this
42 * instance of mutex to block until the first thread that called mutex
43 * unlocks it. At that point the next thread that called lock will get
44 * a chance to go to work. Because of the nature of a mutex lock it is
45 * a very bad idea to do any kind of serious or rather time consuming
46 * computation within a locked section. This can cause thread-deadlock
47 * and your program may hang.
48 */
49 virtual int lock();
50
51 /**
52 * Unlock the mutex. This allows the next thread that asked for a lock
53 * to lock the mutex and continue with execution.
54 */
55 virtual int unlock();
56
57 /**
58 * Try to lock the mutex. This is the option to go with if you cannot
59 * avoid putting lengthy operations within a locked section. trylock
60 * will attempt to lock the mutex, if the mutex is already locked this
61 * function returns immediately with an error code.
62 */
63 virtual int trylock();
64
65 private:
66 Bu::Mutex mState;
67
68 class ThreadInfo
69 {
70 public:
71 ThreadInfo( bool bLocked=false ) :
72 idThread( pthread_self() ),
73 bLocked( bLocked )
74 {
75 char buf[64];
76 if( pthread_getname_np( idThread, buf, 64 ) == 0 )
77 sName = buf;
78 }
79 ~ThreadInfo() {}
80
81 bool operator==( const ThreadInfo &rhs )
82 {
83 return pthread_equal( idThread, rhs.idThread );
84 }
85
86 bool operator==( const pthread_t &rhs )
87 {
88 return pthread_equal( idThread, rhs );
89 }
90
91 pthread_t idThread;
92 Bu::String sName;
93 bool bLocked;
94 };
95 typedef Bu::List<ThreadInfo> ThreadList;
96 ThreadList lThreads;
97 };
98}
99
100#endif
101
102
diff --git a/src/stable/mutex.h b/src/stable/mutex.h
index d9e8910..8034974 100644
--- a/src/stable/mutex.h
+++ b/src/stable/mutex.h
@@ -33,7 +33,7 @@ namespace Bu
33 * wait for the mutex to unlock, the odds of which are usually farily 33 * wait for the mutex to unlock, the odds of which are usually farily
34 * low at deconstruction time. 34 * low at deconstruction time.
35 */ 35 */
36 ~Mutex(); 36 virtual ~Mutex();
37 37
38 /** 38 /**
39 * Lock the mutex. This causes all future calls to lock on this 39 * Lock the mutex. This causes all future calls to lock on this
@@ -44,13 +44,13 @@ namespace Bu
44 * computation within a locked section. This can cause thread-deadlock 44 * computation within a locked section. This can cause thread-deadlock
45 * and your program may hang. 45 * and your program may hang.
46 */ 46 */
47 int lock(); 47 virtual int lock();
48 48
49 /** 49 /**
50 * Unlock the mutex. This allows the next thread that asked for a lock 50 * Unlock the mutex. This allows the next thread that asked for a lock
51 * to lock the mutex and continue with execution. 51 * to lock the mutex and continue with execution.
52 */ 52 */
53 int unlock(); 53 virtual int unlock();
54 54
55 /** 55 /**
56 * Try to lock the mutex. This is the option to go with if you cannot 56 * Try to lock the mutex. This is the option to go with if you cannot
@@ -58,7 +58,7 @@ namespace Bu
58 * will attempt to lock the mutex, if the mutex is already locked this 58 * will attempt to lock the mutex, if the mutex is already locked this
59 * function returns immediately with an error code. 59 * function returns immediately with an error code.
60 */ 60 */
61 int trylock(); 61 virtual int trylock();
62 62
63 protected: 63 protected:
64 pthread_mutex_t mutex; /**< The internal mutex reference. */ 64 pthread_mutex_t mutex; /**< The internal mutex reference. */
diff --git a/src/unstable/myriadfs.cpp b/src/unstable/myriadfs.cpp
index a2386c2..f748a53 100644
--- a/src/unstable/myriadfs.cpp
+++ b/src/unstable/myriadfs.cpp
@@ -108,6 +108,7 @@ Bu::MyriadFs::~MyriadFs()
108 108
109void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf ) 109void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
110{ 110{
111 Bu::MutexLocker lLock( mAccess );
111 int32_t iParent; 112 int32_t iParent;
112 int32_t iNode = lookupInode( sPath, iParent ); 113 int32_t iNode = lookupInode( sPath, iParent );
113 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read ); 114 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
@@ -117,6 +118,7 @@ void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
117Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode, 118Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode,
118 uint16_t uPerms ) 119 uint16_t uPerms )
119{ 120{
121 Bu::MutexLocker lLock( mAccess );
120 int32_t iParent = -1; 122 int32_t iParent = -1;
121 int32_t iNode; 123 int32_t iNode;
122 try 124 try
@@ -165,6 +167,7 @@ void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
165void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms, 167void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
166 uint32_t uSpecial ) 168 uint32_t uSpecial )
167{ 169{
170 Bu::MutexLocker lLock( mAccess );
168 int32_t iParent = -1; 171 int32_t iParent = -1;
169// int32_t iNode; 172// int32_t iNode;
170 try 173 try
@@ -201,6 +204,7 @@ void Bu::MyriadFs::mkDir( const Bu::String &sPath, uint16_t iPerms )
201void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget, 204void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
202 const Bu::String &sPath ) 205 const Bu::String &sPath )
203{ 206{
207 Bu::MutexLocker lLock( mAccess );
204 int32_t iParent = -1; 208 int32_t iParent = -1;
205 int32_t iNode; 209 int32_t iNode;
206 try 210 try
@@ -233,6 +237,7 @@ void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
233void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget, 237void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
234 const Bu::String &sPath ) 238 const Bu::String &sPath )
235{ 239{
240 Bu::MutexLocker lLock( mAccess );
236 int32_t iParent = -1; 241 int32_t iParent = -1;
237 int32_t iNode; 242 int32_t iNode;
238 243
@@ -268,6 +273,7 @@ void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
268 273
269Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath ) 274Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
270{ 275{
276 Bu::MutexLocker lLock( mAccess );
271 int32_t iParent = -1; 277 int32_t iParent = -1;
272 int32_t iNode; 278 int32_t iNode;
273 iNode = lookupInode( sPath, iParent ); 279 iNode = lookupInode( sPath, iParent );
@@ -280,6 +286,7 @@ Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
280 286
281Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath ) 287Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
282{ 288{
289 Bu::MutexLocker lLock( mAccess );
283 int32_t iParent = -1; 290 int32_t iParent = -1;
284 int32_t iNode = lookupInode( sPath, iParent ); 291 int32_t iNode = lookupInode( sPath, iParent );
285 return readDir( iNode ); 292 return readDir( iNode );
@@ -288,6 +295,7 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
288void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime, 295void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
289 int64_t iMTime ) 296 int64_t iMTime )
290{ 297{
298 Bu::MutexLocker lLock( mAccess );
291 int32_t iParent = -1; 299 int32_t iParent = -1;
292 int32_t iNode; 300 int32_t iNode;
293 301
@@ -298,6 +306,7 @@ void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
298 306
299void Bu::MyriadFs::unlink( const Bu::String &sPath ) 307void Bu::MyriadFs::unlink( const Bu::String &sPath )
300{ 308{
309 Bu::MutexLocker lLock( mAccess );
301 int32_t iParent = -1; 310 int32_t iParent = -1;
302// int32_t iNode; 311// int32_t iNode;
303 312
@@ -353,6 +362,7 @@ void Bu::MyriadFs::unlink( const Bu::String &sPath )
353 362
354void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize ) 363void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
355{ 364{
365 Bu::MutexLocker lLock( mAccess );
356 int32_t iParent = -1; 366 int32_t iParent = -1;
357 int32_t iNode; 367 int32_t iNode;
358 iNode = lookupInode( sPath, iParent ); 368 iNode = lookupInode( sPath, iParent );
@@ -362,6 +372,7 @@ void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
362 372
363void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo ) 373void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo )
364{ 374{
375 Bu::MutexLocker lLock( mAccess );
365 mkHardLink( sFrom, sTo ); 376 mkHardLink( sFrom, sTo );
366 unlink( sFrom ); 377 unlink( sFrom );
367} 378}
diff --git a/src/unstable/myriadfs.h b/src/unstable/myriadfs.h
index 4e1749e..e3008bc 100644
--- a/src/unstable/myriadfs.h
+++ b/src/unstable/myriadfs.h
@@ -11,7 +11,7 @@
11#include <sys/types.h> 11#include <sys/types.h>
12 12
13#include "bu/myriad.h" 13#include "bu/myriad.h"
14#include "bu/mutex.h" 14#include "bu/debugmutex.h"
15 15
16namespace Bu 16namespace Bu
17{ 17{
@@ -172,7 +172,13 @@ namespace Bu
172 typedef Bu::Hash<int32_t, int32_t> NodeIndex; 172 typedef Bu::Hash<int32_t, int32_t> NodeIndex;
173 173
174 private: 174 private:
175 /**
176 * Lookup inode.
177 */
175 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent ); 178 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent );
179 /**
180 * Lookup inode.
181 */
176 int32_t lookupInode( Bu::String::const_iterator iStart, 182 int32_t lookupInode( Bu::String::const_iterator iStart,
177 int32_t iNode, int32_t &iParent ); 183 int32_t iNode, int32_t &iParent );
178 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs ); 184 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs );
@@ -190,12 +196,12 @@ namespace Bu
190 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime ); 196 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime );
191 void destroyNode( int32_t iNode ); 197 void destroyNode( int32_t iNode );
192 198
193 Bu::String filePart( const Bu::String &sPath ); 199 static Bu::String filePart( const Bu::String &sPath );
194 200
195 private: 201 private:
196 Bu::Stream &rStore; 202 Bu::Stream &rStore;
197 Bu::Myriad mStore; 203 Bu::Myriad mStore;
198 Bu::Mutex mAccess; 204 Bu::DebugMutex mAccess;
199 NodeIndex hNodeIndex; 205 NodeIndex hNodeIndex;
200 int32_t iUser; 206 int32_t iUser;
201 int32_t iGroup; 207 int32_t iGroup;