00001
00145
00146
00147
00148
00149
00150 #if COMPILE_THREADS
00151 #ifndef BASE_THREAD_LOCK_HH
00152 #define BASE_THREAD_LOCK_HH 1
00153
00154 #include "base_thread_common.hh"
00155
00156 namespace base {
00157
00158
00159
00160 #define THREAD_AUTO_FAST_LOCK {{ PERSISTENT FastLock lock; FastLock::Auto autolock(&lock); }}
00161 #define THREAD_AUTO_SLOW_LOCK {{ PERSISTENT SlowLock lock; SlowLock::Auto autolock(&lock); }}
00162
00163 #if CPU_X86
00164 #define PAUSE_CPU() asm volatile ("rep;nop": : :"memory"); // Linux kernel 2.6
00165 #else
00166 #define PAUSE_CPU()
00167 #endif
00168
00178 template<typename LOCK>
00179 class AutoLock
00180 {
00181
00182 public:
00183 AutoLock( LOCK* lock )
00184 : mLock(lock)
00185 {
00186 ASSERT_STACK_OBJECT( this );
00187 ASSERT_PERSISTENT_OBJECT( mLock );
00188
00189 mLock->Lock();
00190 }
00191
00192 ~AutoLock()
00193 {
00194 mLock->Unlock();
00195 }
00196
00197 private:
00198 LOCK* mLock;
00199 };
00200
00206 class RushLock : private Atomic
00207 {
00208
00209 public:
00210 RushLock( void )
00211 : mLock(false)
00212 {
00213 ASSERT_PERSISTENT_OBJECT( this );
00214 }
00215
00216 ~RushLock()
00217 {
00218
00219 }
00220
00221 inline void Lock( void )
00222 {
00223
00224
00225 Spin: if ( UX(Atomic::Xchg(&mLock,true)) ) { PAUSE_CPU(); goto Spin; }
00226 }
00227
00228 inline void Unlock( void )
00229 {
00230 Atomic::Set( &mLock, false );
00231 }
00232
00233
00234
00236 class Auto : public AutoLock<RushLock>
00237 {
00238 public:
00239 Auto( RushLock* lock ) : AutoLock<RushLock>(lock) { }
00240 };
00241
00242 private:
00243 volatile Atomic::Bool mLock;
00244 };
00245
00255 class FastLock : private Atomic
00256 {
00257
00258 private:
00259 enum { UNLOCKED, LOCKED, BUSY };
00260
00261 public:
00262 FastLock( void )
00263 : mLock(UNLOCKED),
00264 mDepth(0),
00265 mOwner(0)
00266 {
00267 ASSERT_PERSISTENT_OBJECT( this );
00268 }
00269
00270 ~FastLock() { }
00271
00272
00273 #define FAST_LOCK_YIELD( i ) \
00274 { \
00275 PAUSE_CPU(); \
00276 ++i; \
00277 if ( UX( i > base::defs::FAST_LOCK_LOOP_YIELD ) ) \
00278 { \
00279 \
00280 i = 0; \
00281 THREAD_YIELD(); \
00282 } \
00283 }
00284
00285
00287 void Lock( void )
00288 {
00289 uint i = 0;
00290 while ( true )
00291 {
00292 FAST_LOCK_YIELD(i);
00293
00294
00295 const int lock = Atomic::Xchg( &mLock, BUSY );
00296 if ( EX( lock == UNLOCKED ) )
00297 {
00298
00299 ASSERT( mDepth == 0 );
00300 Atomic::Set( &mDepth, 1 );
00301 Atomic::Set( &mOwner, THREAD_ATOMIC_TID() );
00302 Atomic::Set( &mLock, LOCKED );
00303 break;
00304 }
00305 else if ( UX( lock == LOCKED ) )
00306 {
00307
00308 if ( THREAD_ATOMIC_TID_EQUAL( mOwner ) )
00309 {
00310
00311 Atomic::Add( &mDepth, +1 );
00312 Atomic::Set( &mLock, LOCKED );
00313 break;
00314 }
00315 else
00316 {
00317
00318 Atomic::Set( &mLock, LOCKED );
00319 continue;
00320 }
00321 }
00322 else
00323 {
00324 PAUSE_CPU();
00325 continue;
00326 }
00327 }
00328 }
00329
00331 void Unlock( void )
00332 {
00333 ASSERT( mLock != UNLOCKED );
00334 ASSERT( mDepth > 0 );
00335 ASSERT( THREAD_ATOMIC_TID_EQUAL( mOwner ) );
00336
00337
00338
00339
00340
00341 uint i = 0;
00342 while ( true )
00343 {
00344 if ( EX( Atomic::Xchg(&mLock,BUSY) != BUSY ) )
00345 {
00346
00347 const int depth = Atomic::Add( &mDepth, -1 );
00348 Atomic::Set( &mLock, (depth ? LOCKED : UNLOCKED) );
00349 break;
00350 }
00351 else
00352 {
00353
00354 FAST_LOCK_YIELD(i);
00355 continue;
00356 }
00357 }
00358 }
00359
00362 bool IfLocked( void )
00363 {
00364
00365
00366 return mLock && not THREAD_ATOMIC_TID_EQUAL(mOwner);
00367 }
00368
00370 class Auto : public AutoLock<FastLock>
00371 {
00372 public:
00373 Auto( FastLock* lock ) : AutoLock<FastLock>(lock) { }
00374 };
00375
00376 private:
00377
00378
00379
00380 volatile Atomic::Int mLock;
00381 volatile Atomic::Int mDepth;
00382 volatile Thread::AtomicTid mOwner;
00383 };
00384
00394 class SlowLock
00395 {
00396
00397 public:
00398 SlowLock( void );
00399 ~SlowLock();
00400 void Lock( void );
00401 void Unlock( void );
00402 bool IfLocked( void );
00403 bool TryLock( void );
00404
00406 class Auto : public AutoLock<SlowLock>
00407 {
00408 public:
00409 Auto( SlowLock* lock ) : AutoLock<SlowLock>(lock) { }
00410 };
00411
00412 private:
00413 pthread_mutex_t mMutex;
00414 };
00415
00419 class NoLock
00420 {
00421
00422 public:
00423
00424
00425 NoLock( void ) { }
00426 ~NoLock() { }
00427 void Lock( void ) { }
00428 void Unlock( void ) { }
00429
00431 class Auto
00432 {
00433 public:
00434 Auto( UNUSED NoLock* ) { }
00435 ~Auto() { }
00436 };
00437 };
00438
00439 }
00440
00441 #endif // BASE_THREAD_LOCK_HH
00442 #endif // COMPILE_THREADS