00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdmisc.h"
00027
00028 #ifndef _GNU_SOURCE
00029 #define _GNU_SOURCE
00030 #endif // _GNU_SOURCE
00031
00032 #include "nel/misc/mutex.h"
00033 #include "nel/misc/time_nl.h"
00034
00035 #ifdef MUTEX_DEBUG
00036 #include <iostream>
00037 #endif
00038
00039 using namespace std;
00040
00041 #ifndef MUTEX_DEBUG
00042 #define debugCreateMutex() ;
00043 #define debugBeginEnter() ;
00044 #define debugEndEnter() ;
00045 #define debugLeave() ;
00046 #define debugDeleteMutex() ;
00047 #endif
00048
00049
00050
00051
00052
00053
00054 #ifdef NL_OS_WINDOWS
00055
00056
00057
00058 #define _WIN32_WINDOWS 0x0410
00059 #define WINVER 0x0400
00060 #include <windows.h>
00061
00062
00063 namespace NLMISC {
00064
00065
00066
00067
00068
00069
00070 CUnfairMutex::CUnfairMutex()
00071 {
00072
00073 Mutex = (void *) CreateMutex (NULL, FALSE, NULL);
00074 nlassert (Mutex != NULL);
00075 }
00076
00077
00078 CUnfairMutex::CUnfairMutex(const std::string &name)
00079 {
00080
00081 Mutex = (void *) CreateMutex (NULL, FALSE, NULL);
00082 nlassert (Mutex != NULL);
00083 }
00084
00085
00086
00087
00088
00089 CUnfairMutex::~CUnfairMutex()
00090 {
00091 CloseHandle( Mutex );
00092 }
00093
00094
00095
00096
00097
00098 void CUnfairMutex::enter()
00099 {
00100 #ifdef NL_DEBUG
00101 DWORD timeout;
00102 if ( IsDebuggerPresent() )
00103 timeout = INFINITE;
00104 else
00105 timeout = 10000;
00106
00107
00108 DWORD dwWaitResult = WaitForSingleObject (Mutex, timeout);
00109 #else
00110
00111 DWORD dwWaitResult = WaitForSingleObject (Mutex, 10000);
00112 #endif // NL_DEBUG
00113 switch (dwWaitResult)
00114 {
00115
00116 case WAIT_OBJECT_0: break;
00117
00118 case WAIT_TIMEOUT: nlerror ("Dead lock in a mutex (or more that 10s for the critical section");
00119
00120 case WAIT_ABANDONED: nlerror ("A thread forgot to release the mutex");
00121 }
00122 }
00123
00124
00125
00126
00127
00128 void CUnfairMutex::leave()
00129 {
00130 if (ReleaseMutex(Mutex) == 0)
00131 {
00132 nlerror ("error while releasing the mutex (0x%x %d), %p", GetLastError(), GetLastError(), Mutex);
00133 }
00134 }
00135
00136
00137
00138
00139
00140 CFairMutex::CFairMutex()
00141 {
00142 Name = "unset mutex name";
00143
00144 debugCreateMutex();
00145
00146
00147 nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
00148
00149 #if (_WIN32_WINNT >= 0x0500)
00150 DWORD dwSpinCount = 0x80000000;
00151 if ( ! InitializeCriticalSectionAndSpinCount( &_Cs, dwSpinCount ) )
00152 {
00153 nlerror( "Error entering critical section" );
00154 }
00155 #else
00156 InitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );
00157 #endif
00158 }
00159
00160
00161 CFairMutex::CFairMutex(const string &name)
00162 {
00163 Name = name;
00164
00165 #ifdef MUTEX_DEBUG
00166 debugCreateMutex();
00167 #endif
00168
00169
00170 nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
00171
00172 #if (_WIN32_WINNT >= 0x0500)
00173 DWORD dwSpinCount = 0x80000000;
00174 if ( ! InitializeCriticalSectionAndSpinCount( &_Cs, dwSpinCount ) )
00175 {
00176 nlerror( "Error entering critical section" );
00177 }
00178 #else
00179 InitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );
00180 #endif
00181 }
00182
00183
00184
00185
00186
00187
00188 CFairMutex::~CFairMutex()
00189 {
00190 DeleteCriticalSection( (CRITICAL_SECTION*)&_Cs );
00191
00192 debugDeleteMutex();
00193 }
00194
00195
00196
00197
00198
00199 void CFairMutex::enter()
00200 {
00201 debugBeginEnter();
00202
00203 EnterCriticalSection( (CRITICAL_SECTION*)&_Cs );
00204
00205 debugEndEnter();
00206 }
00207
00208
00209
00210
00211
00212 void CFairMutex::leave()
00213 {
00214 LeaveCriticalSection( (CRITICAL_SECTION*)&_Cs );
00215
00216 debugLeave();
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 #elif defined NL_OS_UNIX
00231
00232 #include <pthread.h>
00233 #include <errno.h>
00234
00235
00236
00237
00238
00239
00240 extern "C"
00241 {
00242 int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
00243 }
00244
00245
00246 namespace NLMISC {
00247
00248
00249
00250
00251
00252 CUnfairMutex::CUnfairMutex(const std::string &name)
00253 {
00254 pthread_mutexattr_t attr;
00255 pthread_mutexattr_init( &attr );
00256
00257 pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ADAPTIVE_NP );
00258 pthread_mutex_init( &mutex, &attr );
00259 pthread_mutexattr_destroy( &attr );
00260 }
00261
00262
00263
00264
00265
00266 CUnfairMutex::~CUnfairMutex()
00267 {
00268 pthread_mutex_destroy( &mutex );
00269 }
00270
00271
00272
00273
00274
00275 void CUnfairMutex::enter()
00276 {
00277
00278 if ( pthread_mutex_lock( &mutex ) != 0 )
00279 {
00280
00281 nlerror( "Error locking a mutex" );
00282 }
00283
00284
00285
00286
00287 }
00288
00289
00290
00291
00292
00293 void CUnfairMutex::leave()
00294 {
00295
00296
00297 if ( (pthread_mutex_unlock( &mutex )) != 0 )
00298 {
00299
00300
00301
00302
00303
00304
00305
00306
00307 nlerror( "Error unlocking a mutex" );
00308 }
00309
00310
00311
00312
00313 }
00314
00315
00316
00317
00318
00319 CFairMutex::CFairMutex()
00320 {
00321 sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
00322 }
00323
00324
00325 CFairMutex::CFairMutex( const std::string &name )
00326 {
00327 sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
00328 }
00329
00330
00331
00332
00333
00334 CFairMutex::~CFairMutex()
00335 {
00336 sem_destroy( const_cast<sem_t*>(&_Sem) );
00337 }
00338
00339
00340
00341
00342
00343 void CFairMutex::enter()
00344 {
00345 sem_wait( const_cast<sem_t*>(&_Sem) );
00346 }
00347
00348
00349
00350
00351
00352 void CFairMutex::leave()
00353 {
00354 sem_post( const_cast<sem_t*>(&_Sem) );
00355 }
00356
00357
00358 #endif // NL_OS_WINDOWS/NL_OS_LINUX
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 #ifdef MUTEX_DEBUG
00371
00372 map<CFairMutex*,TMutexLocks> *AcquireTime = NULL;
00373 uint32 NbMutexes = 0;
00374 CFairMutex *ATMutex = NULL;
00375 bool InitAT = true;
00376
00377
00379 void initAcquireTimeMap()
00380 {
00381 if ( InitAT )
00382 {
00383 ATMutex = new CFairMutex("ATMutex");
00384 AcquireTime = new map<CFairMutex*,TMutexLocks>;
00385 InitAT = false;
00386 }
00387 }
00388
00389
00391 map<CFairMutex*,TMutexLocks> getNewAcquireTimes()
00392 {
00393 map<CMutex*,TMutexLocks> m;
00394 ATMutex->enter();
00395
00396
00397 m = *AcquireTime;
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 ATMutex->leave();
00409 return m;
00410 }
00411
00412
00415
00416 void CFairMutex::debugCreateMutex()
00417 {
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 }
00433
00434 void CFairMutex::debugDeleteMutex()
00435 {
00436 if ( (this!=ATMutex ) && (ATMutex!=NULL) )
00437 {
00438 ATMutex->enter();
00439 (*AcquireTime)[this].Dead = true;
00440 ATMutex->leave();
00441 }
00442 }
00443
00444 void CFairMutex::debugBeginEnter()
00445 {
00446 if ( (this!=ATMutex ) && (ATMutex!=NULL) )
00447 {
00448 TTicks t = CTime::getPerformanceTime();
00449
00450 ATMutex->enter();
00451 std::map<CMutex*,TMutexLocks>::iterator it = (*AcquireTime).find (this);
00452 if (it == (*AcquireTime).end())
00453 {
00454 AcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes++) ) );
00455 char dbgstr [256];
00456 smprintf( dbgstr, 256, "MUTEX: Creating mutex %p %s (number %u)\n", this, Name.c_str(), NbMutexes-1 );
00457 #ifdef NL_OS_WINDOWS
00458 if ( IsDebuggerPresent() ) OutputDebugString( dbgstr );
00459 #endif
00460 cout << dbgstr << endl;
00461
00462 it = (*AcquireTime).find (this);
00463 (*it).second.MutexName = Name;
00464 }
00465 (*it).second.WaitingMutex++;
00466 (*it).second.BeginEnter = t;
00467 ATMutex->leave();
00468 }
00469 }
00470
00471
00472 void CFairMutex::debugEndEnter()
00473 {
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 if ( ( this != ATMutex ) && ( ATMutex != NULL ) )
00485 {
00486 TTicks t = CTime::getPerformanceTime();
00487 ATMutex->enter();
00488 if ((uint32)(t-(*AcquireTime)[this].BeginEnter) > (*AcquireTime)[this].TimeToEnter)
00489 (*AcquireTime)[this].TimeToEnter = (uint32)(t-(*AcquireTime)[this].BeginEnter);
00490 (*AcquireTime)[this].Nb += 1;
00491 (*AcquireTime)[this].WaitingMutex--;
00492 (*AcquireTime)[this].ThreadHavingTheMutex = getThreadId();
00493 (*AcquireTime)[this].EndEnter = t;
00494 ATMutex->leave();
00495 }
00496 }
00497
00498
00499 void CFairMutex::debugLeave()
00500 {
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 if ( ( this != ATMutex ) && ( ATMutex != NULL ) )
00513 {
00514 TTicks Leave = CTime::getPerformanceTime();
00515 ATMutex->enter();
00516 if ((uint32)(Leave-(*AcquireTime)[this].EndEnter) > (*AcquireTime)[this].TimeInMutex)
00517 (*AcquireTime)[this].TimeInMutex = (uint32)(Leave-(*AcquireTime)[this].EndEnter);
00518 (*AcquireTime)[this].Nb += 1;
00519 (*AcquireTime)[this].WaitingMutex = false;
00520 (*AcquireTime)[this].ThreadHavingTheMutex = 0xFFFFFFFF;
00521 ATMutex->leave();
00522 }
00523
00524 }
00525
00526 #endif // MUTEX_DEBUG
00527
00528 }