# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

mutex.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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  * Windows code *
00052  ****************/
00053 
00054 #ifdef NL_OS_WINDOWS
00055 
00056 // these defines are for IsDebuggerPresent(). It'll not compile on windows 95
00057 // just comment this and the IsDebuggerPresent to compile on windows 95
00058 #define _WIN32_WINDOWS  0x0410
00059 #define WINVER                  0x0400
00060 #include <windows.h>
00061 
00062 
00063 namespace NLMISC {
00064 
00065 
00066 /*
00067  * Windows version
00068  */
00069 
00070 CUnfairMutex::CUnfairMutex()
00071 {
00072         // Create a mutex with no initial owner.
00073         Mutex = (void *) CreateMutex (NULL, FALSE, NULL);
00074         nlassert (Mutex != NULL);
00075 }
00076 
00077 
00078 CUnfairMutex::CUnfairMutex(const std::string &name)
00079 {
00080         // Create a mutex with no initial owner.
00081         Mutex = (void *) CreateMutex (NULL, FALSE, NULL);
00082         nlassert (Mutex != NULL);
00083 }
00084 
00085 
00086 /*
00087  * Windows version
00088  */
00089 CUnfairMutex::~CUnfairMutex()
00090 {
00091         CloseHandle( Mutex );
00092 }
00093 
00094 
00095 /*
00096  * Windows version
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     // Request ownership of mutex
00108         DWORD dwWaitResult = WaitForSingleObject (Mutex, timeout);
00109 #else
00110     // Request ownership of mutex during 10s
00111         DWORD dwWaitResult = WaitForSingleObject (Mutex, 10000);
00112 #endif // NL_DEBUG
00113         switch (dwWaitResult)
00114         {
00115         // The thread got mutex ownership.
00116         case WAIT_OBJECT_0:             break;
00117         // Cannot get mutex ownership due to time-out.
00118         case WAIT_TIMEOUT:              nlerror ("Dead lock in a mutex (or more that 10s for the critical section");
00119         // Got ownership of the abandoned mutex object.
00120         case WAIT_ABANDONED:    nlerror ("A thread forgot to release the mutex");
00121     }
00122 }
00123 
00124 
00125 /*
00126  * Windows version
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  * Windows version
00139  */
00140 CFairMutex::CFairMutex()
00141 {
00142         Name = "unset mutex name";
00143 
00144         debugCreateMutex();
00145 
00146         // Check that the CRITICAL_SECTION structure has not changed
00147         nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
00148 
00149 #if (_WIN32_WINNT >= 0x0500)
00150         DWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation
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         // Check that the CRITICAL_SECTION structure has not changed
00170         nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
00171 
00172 #if (_WIN32_WINNT >= 0x0500)
00173         DWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation
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  * Windows version
00187  */
00188 CFairMutex::~CFairMutex()
00189 {
00190         DeleteCriticalSection( (CRITICAL_SECTION*)&_Cs );
00191 
00192         debugDeleteMutex();
00193 }
00194 
00195 
00196 /*
00197  * Windows version
00198  */
00199 void CFairMutex::enter()
00200 {
00201         debugBeginEnter();
00202 
00203         EnterCriticalSection( (CRITICAL_SECTION*)&_Cs );
00204 
00205         debugEndEnter();
00206 }
00207 
00208 
00209 /*
00210  * Windows version
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  * Unix code *
00228  *************/
00229 
00230 #elif defined NL_OS_UNIX
00231 
00232 #include <pthread.h>
00233 #include <errno.h>
00234 
00235 
00236 /*
00237  * Clanlib authors say: "We need to do this because the posix threads library
00238  * under linux obviously suck:"
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  * Unix version
00251  */
00252 CUnfairMutex::CUnfairMutex(const std::string &name)
00253 {
00254         pthread_mutexattr_t attr;
00255         pthread_mutexattr_init( &attr );
00256         // Fast mutex. Note: on Windows all mutexes are recursive
00257         pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ADAPTIVE_NP ); //PTHREAD_MUTEX_ERRORCHECK_NP );//PTHREAD_MUTEX_ADAPTIVE_NP );//PTHREAD_MUTEX_RECURSIVE_NP );
00258         pthread_mutex_init( &mutex, &attr );
00259         pthread_mutexattr_destroy( &attr );
00260 }
00261 
00262 
00263 /*
00264  * Unix version
00265  */
00266 CUnfairMutex::~CUnfairMutex()
00267 {
00268         pthread_mutex_destroy( &mutex );
00269 }
00270 
00271 
00272 /*
00273  * Unix version
00274  */
00275 void CUnfairMutex::enter()
00276 {
00277         //cout << getpid() << ": Locking " << &mutex << endl;
00278         if ( pthread_mutex_lock( &mutex ) != 0 )
00279         {
00280           //cout << "Error locking a mutex " << endl;
00281                 nlerror( "Error locking a mutex" );
00282         }
00283         /*else
00284         {
00285           cout << getpid() << ": Owning " << &mutex << endl;
00286         }*/
00287 }
00288 
00289 
00290 /*
00291  * Unix version
00292  */
00293 void CUnfairMutex::leave()
00294 {
00295         //int errcode;
00296         //cout << getpid() << ": Unlocking " << &mutex << endl;
00297         if ( (/*errcode=*/pthread_mutex_unlock( &mutex )) != 0 )
00298         {
00299          /* switch ( errcode )
00300             {
00301             case EINVAL: cout << "INVAL" << endl; break;
00302             case EPERM: cout << "PERM" << endl; break;
00303             default: cout << "OTHER" << endl;
00304             }
00305           */
00306           //cout << "Error unlocking a mutex " /*<< &mutex*/ << endl;
00307                 nlerror( "Error unlocking a mutex" );
00308         }
00309         /*else
00310         {
00311           cout << getpid() << ": Released " << &mutex << endl;
00312         }*/
00313 }
00314 
00315 
00316 /*
00317  * Unix version
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  * Unix version
00333  */
00334 CFairMutex::~CFairMutex()
00335 {
00336         sem_destroy( const_cast<sem_t*>(&_Sem) ); // needs that no thread is waiting on the semaphore
00337 }
00338 
00339 
00340 /*
00341  * Unix version
00342  */
00343 void CFairMutex::enter()
00344 {
00345         sem_wait( const_cast<sem_t*>(&_Sem) );
00346 }
00347 
00348 
00349 /*
00350  * Unix version
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  * Debugging code *
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         // Copy map
00397         m = *AcquireTime;
00398 
00399         // Reset map
00400 /*      map<CMutex*,TMutexLocks>::iterator im;
00401         for ( im=AcquireTime->begin(); im!=AcquireTime->end(); ++im )
00402         {
00403                 (*im).second.Time = 0;
00404                 (*im).second.Nb = 0;
00405                 (*im).second.Locked = false;
00406         }
00407 */
00408         ATMutex->leave();
00409         return m;
00410 }
00411 
00412 
00415 
00416 void CFairMutex::debugCreateMutex()
00417 {
00418 /*      if ( ! InitAT )
00419         {
00420                 ATMutex->enter();
00421                 AcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes) ) );
00422                 NbMutexes++;
00423                 ATMutex->leave();
00424                 char dbgstr [256];
00425                 smprintf( dbgstr, 256, "MUTEX: Creating mutex %p %s (number %u)\n", this, Name.c_str(), NbMutexes-1 );
00426 #ifdef NL_OS_WINDOWS
00427                 if ( IsDebuggerPresent() )
00428                         OutputDebugString( dbgstr );
00429 #endif
00430                 cout << dbgstr << endl;
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 //      printf("1");
00475 /*      char str[1024];
00476         sprintf(str, "enter %8p %8p %8p\n", this, Mutex, getThreadId ());
00477         if (Mutex == (void*)0x88)
00478         {
00479                 OutputDebugString (str);
00480                 if (entered) __asm int 3;
00481                 entered = true;
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 //      printf( "0" );
00502 /*      char str[1024];
00503         sprintf(str, "leave %8p %8p %8p\n", this, Mutex, getThreadId ());
00504         if (Mutex == (void*)0x88)
00505         {
00506                 OutputDebugString (str);
00507                 if (!entered) __asm int 3;
00508                 entered = false;
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 } // NLMISC