diff options
author | Mike Buland <mike@xagasoft.com> | 2024-11-06 16:01:36 -0800 |
---|---|---|
committer | Mike Buland <mike@xagasoft.com> | 2024-11-06 16:01:36 -0800 |
commit | 700d4bbcbf59c4447becbab21a6aa7204a8da2f4 (patch) | |
tree | ae68c40a5af2d5bc84ac4bbb192fbbda893d64cc /src | |
parent | 6403224b6fe50dfc28d3c25725b6d0910b7eb6c3 (diff) | |
download | libbu++-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 '')
-rw-r--r-- | src/experimental/debugmutex.cpp | 78 | ||||
-rw-r--r-- | src/experimental/debugmutex.h | 102 | ||||
-rw-r--r-- | src/stable/mutex.h | 8 | ||||
-rw-r--r-- | src/unstable/myriadfs.cpp | 11 | ||||
-rw-r--r-- | src/unstable/myriadfs.h | 12 |
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 | |||
5 | Bu::DebugMutex::DebugMutex() | ||
6 | { | ||
7 | } | ||
8 | |||
9 | Bu::DebugMutex::~DebugMutex() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | int 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 | |||
43 | int 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 | |||
74 | int 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 | |||
15 | namespace 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 | ||
109 | void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf ) | 109 | void 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 ) | |||
117 | Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode, | 118 | Bu::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, | |||
165 | void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms, | 167 | void 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 ) | |||
201 | void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget, | 204 | void 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, | |||
233 | void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget, | 237 | void 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 | ||
269 | Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath ) | 274 | Bu::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 | ||
281 | Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath ) | 287 | Bu::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 ) | |||
288 | void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime, | 295 | void 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 | ||
299 | void Bu::MyriadFs::unlink( const Bu::String &sPath ) | 307 | void 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 | ||
354 | void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize ) | 363 | void 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 | ||
363 | void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo ) | 373 | void 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 | ||
16 | namespace Bu | 16 | namespace 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; |