Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phMutex.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  --------------------------------------------------------------------------- */
00026 #ifdef HAVE_CONFIG_H
00027     #include <phissionconfig.h>
00028 #endif
00029 
00030 #include <phStandard.h>
00031 
00032 #include <phObject.h>
00033 
00034 #include <phMutex.h>
00035 
00036 #define phERROR_CHECK_OWNER() 1
00037 #define phERROR_PRINT_OWNER() 0
00038 
00039 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00040     #include <pthread.h>
00041 #endif
00042 
00043 #if defined(WIN32)
00044     #include <windows.h>
00045 #endif
00046 
00047 #if defined(__ADSPBLACKFIN__)
00048     #include <PhissionVDK.h>
00049 #endif
00050 
00051 #ifdef HAVE_ERRNO_H
00052     #include <errno.h> /* EDEADLK, EBUSY */
00053 #endif
00054 
00055 #include <phError.h>
00056 #include <phMemory.h>
00057 #include <phPrint.h>
00058 
00059 #if defined(__ADSPBLACKFIN__)
00060     /* pick one and only one */
00061     #define USE_VDK_RMUTEX()    1
00062     #define USE_VDK_SPINLOCK()  0
00063     #define USE_VDK_SEMAPHORE() 0
00064     #define USE_ADI_SPINLOCK()  0
00065     
00066     #if USE_VDK_RMUTEX()
00067         /* This is the interface to an unsupported VDK feature.
00068          * Analog has no gaurantees on this interface and it is subject to
00069          * change. */
00070         namespace VDK
00071         {
00072             typedef struct RMutex
00073             {
00074                 unsigned int vDummy[5];
00075             } RMutex;
00076 
00077             void    RMutexInit   (RMutex *pMutex, unsigned size);
00078             void    RMutexDeInit (RMutex *pMutex);
00079             RMutex *RMutexCreate ();
00080             void    RMutexDestroy(RMutex *pMutex);
00081             void    RMutexAcquire(RMutex *pMutex);
00082             void    RMutexRelease(RMutex *pMutex);
00083         }; // namespace VDK
00084     #elif USE_VDK_SPINLOCK()
00085         /* Got the main outline/code for vdk*lock from ccblkfn.h and inserted a
00086          * VDK::Yield() in the acquire spin loop */
00087         typedef volatile uint32_t ph_lock_type;
00088         static __inline__ void vdk_acquire_lock(ph_lock_type *lock)
00089         {
00090             //printf("(%d) vdk_acquire_lock : %d\n", VDK::GetThreadID(),*lock);
00091             VDK::PushUnscheduledRegion();
00092             
00093             while (*lock)
00094             {
00095                 VDK::PopUnscheduledRegion();
00096                 //printf("(%d) vdk_acquire_lock : %d\n", VDK::GetThreadID(), *lock);
00097                 //VDK::Yield();
00098                 VDK::Sleep(7);
00099                 VDK::PushUnscheduledRegion();
00100             }
00101 
00102             *lock = VDK::GetThreadID();
00103             //phMemset((void *)lock,0xFF,sizeof(ph_lock_type));
00104             
00105             VDK::PopUnscheduledRegion();
00106             //printf("(%d) vdk_acquire_lock - got lock\n", VDK::GetThreadID());
00107         }
00108         static __inline__ int vdk_try_lock( ph_lock_type *lock )
00109         {
00110             int gotlock = 1;
00111             //printf("(%d) vdk_try_lock\n", VDK::GetThreadID());
00112             VDK::PushUnscheduledRegion();
00113             if (!*lock) 
00114             {
00115                 *lock = VDK::GetThreadID();
00116                 //phMemset((void*)lock,0xFF,sizeof(ph_lock_type));
00117                 gotlock = phSUCCESS;
00118             }
00119             VDK::PopUnscheduledRegion();
00120             //printf("(%d) vdk_try_lock (%d)\n", VDK::GetThreadID(),gotlock);
00121             return gotlock;
00122         }
00123         static __inline__ void vdk_release_lock( ph_lock_type *lock )
00124         {
00125             //printf("(%d) vdk_release_lock\n", VDK::GetThreadID());
00126             VDK::PushUnscheduledRegion();
00127             *lock = 0;
00128             //phMemset((void*)lock,0x00,sizeof(ph_lock_type));
00129             VDK::PopUnscheduledRegion();
00130             //printf("(%d) vdk_release_lock - released\n", VDK::GetThreadID());
00131         }
00132     #elif USE_ADI_SPINLOCK()
00133         #include <ccblkfn.h>
00134         #define testset_t ph_lock_type
00135     #endif
00136 #endif /* #if defined(__ADSP_BLACKFIN__) */
00137 
00138 /* ------------------------------------------------------------------------- */
00139 struct ph_mutex_info_t
00140 {
00141 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00142     /* pthreads mutex variables */
00143     /* The m_mutex is a lock used around most objects to permit
00144      * proper threaded access to objects */
00145     pthread_mutex_t     m_mutex;
00146     pthread_mutexattr_t m_mutex_attr;
00147 #elif defined(WIN32)
00148     HANDLE              m_mutex;
00149 #elif defined(__ADSPBLACKFIN__)
00150     #if USE_VDK_RMUTEX()
00151     VDK::RMutex         m_mutex;
00152     #endif
00153     #if USE_ADI_SPINLOCK() || USE_VDK_SPINLOCK()
00154     ph_lock_type        m_mutex;
00155     #endif
00156     #if USE_VDK_SEMAPHORE()
00157     VDK::SemaphoreID    m_mutex;
00158     #endif
00159 #endif
00160 };
00161 
00162 #define phMutex_INVALIDOWNER ((uintmax_t)-1)
00163 
00164 /* ------------------------------------------------------------------------- */
00165 phMutex::phMutex( ) : phObject("phMutex")
00166 {
00167     phFUNCTION("phMutex::phMutex")
00168 
00169     this->m_owner           = phMutex_INVALIDOWNER;
00170     this->m_locked_count    = 0;
00171 
00172     this->m_mutex_info = (struct ph_mutex_info_t *)phCalloc(1,
00173                                     sizeof(struct ph_mutex_info_t));
00174     phPRINT_NULLPTR(this->m_mutex_info,"phCalloc","phCalloc failed.");
00175     
00176     this->m_private_mutex = (void *)&this->m_mutex_info->m_mutex;
00177     
00178 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00179     /* initialize the lock */
00180     rc = pthread_mutexattr_init(&(this->m_mutex_info->m_mutex_attr));
00181     phPRINT_RC(rc,"pthread_mutexattr_init",
00182                "this->m_mutex_info->m_mutex_attr init failed");
00183  
00184     /* we want a recursive mutex so the lock can be called
00185      * multiple times by the same thread. Obviously
00186      * this means it takes more than one unlock call to unlock it too.
00187      * This is just a better way to do things since deadlocking is
00188      * a dangerous thing. There won't be deadlock within a thread 
00189      * if things are done right. */
00190     /*pthread_mutex_t initmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;*/
00191     rc = pthread_mutexattr_settype(&(this->m_mutex_info->m_mutex_attr), 
00192                                    PTHREAD_MUTEX_RECURSIVE);
00193     phPRINT_RC(rc,"pthread_mutexattr_settype",
00194                "this->m_mutex_info->m_mutex set type failed");
00195     
00196     rc = pthread_mutex_init(&(this->m_mutex_info->m_mutex),
00197                             &(this->m_mutex_info->m_mutex_attr));
00198     phPRINT_RC(rc,"pthread_mutex_init",
00199                "this->m_mutex_info->m_mutex init failed");
00200 
00201 #endif
00202 
00203 #if defined(WIN32)
00204     this->m_mutex_info->m_mutex = CreateMutex(NULL,FALSE,NULL);
00205     phPRINT_NULLPTR(this->m_mutex_info->m_mutex,
00206                     "CreateMutex","CreateMutex failed");
00207 #endif
00208     
00209 #if defined(__ADSPBLACKFIN__) 
00210     #if USE_VDK_SEMAPHORE()
00211     this->m_mutex_info->m_mutex = VDK::CreateSemaphore(1,1,0,0);
00212     if (this->m_mutex_info->m_mutex == UINT_MAX)
00213     {
00214         phPRINT_RC(-1,NULL,"VDK::CreateSemaphore failed");
00215     }
00216     #elif USE_VDK_RMUTEX()
00217     //this->m_mutex_info->m_mutex = VDK::RMutexCreate();
00218     VDK::RMutexInit(&(this->m_mutex_info->m_mutex),sizeof(VDK::RMutex));
00219     #else
00220     this->m_mutex_info->m_mutex = 0;
00221     #endif
00222 #endif
00223 }
00224 
00225 /* ------------------------------------------------------------------------- */
00226 phMutex::~phMutex( )
00227 {
00228     phFUNCTION("phMutex::~phMutex")
00229     int locked = 0;
00230    
00231 #if defined(WIN32)
00232     BOOL bResult;
00233 #endif
00234 
00235     phTHIS_LOOSE_LOCK(locked);
00236 
00237     /* Free the phObject stuff before freeing the object's mutex */
00238     this->setName(NULL);
00239 
00240     for ( ; this->m_locked_count > 0; )
00241     {
00242         rc = this->unlock();
00243         phPRINT_RC(rc,NULL,"this->unlock");
00244     }
00245     
00246 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00247     /* destroy the lock */
00248     rc = pthread_mutex_destroy(&(this->m_mutex_info->m_mutex));
00249     phPRINT_RC(rc,"pthread_mutex_destroy","destroying mutex failed");
00250     
00251     /* destroy the attributes */
00252     rc = pthread_mutexattr_destroy(&(this->m_mutex_info->m_mutex_attr));
00253     phPRINT_RC(rc,"pthread_mutexattr_destroy","destroying mutex failed");
00254 #endif
00255 
00256 #if defined(WIN32)
00257     bResult = CloseHandle(this->m_mutex_info->m_mutex);
00258     if (!bResult) rc = phFAIL; else rc = phSUCCESS;
00259     phPRINT_RC(rc,"CloseHandle","CloseHandle when closing mutex\n");
00260 #endif
00261 
00262 #if defined(__ADSPBLACKFIN__)
00263     #if USE_VDK_SEMAPHORE()
00264     VDK::DestroySemaphore(this->m_mutex_info->m_mutex);
00265     #elif USE_VDK_RMUTEX()
00266     //VDK::RMutexDestroy(this->m_mutex_info->m_mutex);
00267     VDK::RMutexDeInit(&(this->m_mutex_info->m_mutex));
00268     #endif
00269 #endif
00270 
00271     this->m_private_mutex = (void *)0x0;
00272     phFree(this->m_mutex_info);
00273 }
00274 
00275 /* ------------------------------------------------------------------------- */
00276 int phMutex::incLockCount()
00277 {
00278     phFUNCTION("phMutex::incLockCount()")
00279     
00280     if (this->m_owner == phMutex_INVALIDOWNER)
00281     {
00282         this->m_owner = phGetCurrentThreadId();
00283         this->m_locked_count++;
00284     }
00285     else if (this->m_owner == phGetCurrentThreadId())
00286     {
00287         this->m_locked_count++;
00288     }
00289     else
00290     {
00291     #if phERROR_CHECK_OWNER()
00292         phCHECK_RC( 
00293             -1,NULL,
00294             "(%p) Thread:%lu locked mutex owned by other thread:%lu count:%u",
00295             this,
00296             phGetCurrentThreadId(),
00297             this->m_owner,
00298             this->m_locked_count );
00299     #endif
00300     }
00301     /*
00302     phPROGRESS( "(this:%p) current:%u owner:%u locked_count:%u\n",
00303                this,phGetCurrentThreadId(),this->m_owner,this->m_locked_count);
00304     */
00305     
00306     return phSUCCESS;
00307 error:
00308     return phFAIL;
00309 }
00310 
00311 /* ------------------------------------------------------------------------- */
00312 int phMutex::decLockCount()
00313 {
00314     phFUNCTION("phMutex::decLockCount()")
00315 
00316     /*
00317     phPROGRESS( "(this:%p) current:%u owner:%u locked_count:%u\n",
00318                this,phGetCurrentThreadId(),this->m_owner,this->m_locked_count);
00319      */
00320     if (this->m_owner == phGetCurrentThreadId())
00321     {
00322         /* decrement the lock count */
00323         this->m_locked_count--;
00324 
00325         /* reset the owner */
00326         if (this->m_locked_count == 0)
00327         {
00328             this->m_owner = phMutex_INVALIDOWNER;
00329         }
00330     }
00331     else
00332     {
00333     #if phERROR_CHECK_OWNER()
00334         phCHECK_RC(
00335         /* this->m_owner isn't guaranteed to be the same as the 
00336          * one we tried to unlock */
00337             -1,NULL,
00338             "(%p) Thread:%lu unlocking mutex owned by thread:%lu count:%u",
00339             this,
00340             phGetCurrentThreadId(),
00341             this->m_owner,
00342             this->m_locked_count );
00343     #endif
00344     }
00345 
00346     return phSUCCESS;
00347 error:
00348     return phFAIL;
00349 }
00350 
00351 /* ------------------------------------------------------------------------- */
00352 uint32_t phMutex::getLockCount()
00353 {
00354     return this->m_locked_count;
00355 }
00356 
00357 /* ------------------------------------------------------------------------- */
00358 int phMutex::lock( )
00359 {
00360     phFUNCTION("phMutex::lock")
00361     int dlck        = 0;
00362     
00363 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00364     /* call the pthread mutex lock function on the mutex */
00365     rc = pthread_mutex_lock(&(this->m_mutex_info->m_mutex));
00366     if (rc == EDEADLK) { rc = 0; dlck = 1;}
00367     phCHECK_RC(rc, "pthread_mutex_lock", 
00368                "locking this->m_mutex_info->m_mutex failed");
00369 #endif
00370 
00371 #if defined(WIN32)
00372     DWORD dwResult = WaitForSingleObject( this->m_mutex_info->m_mutex, 
00373                                           INFINITE );
00374     if ((dwResult == WAIT_OBJECT_0) || (dwResult == WAIT_ABANDONED))
00375         rc = phSUCCESS; 
00376     else 
00377         rc = phFAIL;
00378     phCHECK_RC(rc,"WaitForSingleObject",
00379                "WaitForSingleObject failed - HANDLE: 0x%08x\n",
00380                (unsigned long)this->m_mutex_info->m_mutex);
00381 #endif
00382 
00383 #if defined(__ADSPBLACKFIN__) 
00384     /* With adi_acquire_lock, we can only call it once in a thread, so we
00385      * must check whether we own the lock already and don't try to lock
00386      * again if we do */
00387     if (this->m_owner != phGetCurrentThreadId())
00388     {
00389         #if USE_VDK_RMUTEX()
00390         VDK::RMutexAcquire(&(this->m_mutex_info->m_mutex));
00391         #endif
00392         #if USE_ADI_SPINLOCK()
00393         adi_acquire_lock(&(this->m_mutex_info->m_mutex));
00394         #endif
00395         #if USE_VDK_SPINLOCK()
00396         vdk_acquire_lock(&(this->m_mutex_info->m_mutex));
00397         #endif
00398         #if USE_VDK_SEMAPHORE()
00399         if (!VDK::PendSemaphore(this->m_mutex_info->m_mutex,0))
00400             phCHECK_RC(-1,NULL,"VDK::PendSemaphore failed.");
00401         #endif
00402     }
00403 #endif
00404     /* increment the lock count, only if we didn't
00405      * get a deadlock condition(ie we didn't really get the lock )*/
00406     /* Also, we'll only end up here if we succeeded in getting the lock
00407      * because CHECK_RC will jump over this statement */
00408     if (dlck == 0)
00409     {
00410         rc = this->incLockCount();
00411         phCHECK_RC(rc,NULL,"this->incLockCount()");
00412     }
00413     return phSUCCESS;
00414 error:
00415     return phFAIL;
00416 }
00417 
00418 /* ------------------------------------------------------------------------- */
00419 /* 0: successful, 1: unsuccessful, -1: error */
00420 int phMutex::trylock( )
00421 {
00422     phFUNCTION("phMutex::trylock")
00423     int retrc       = phSUCCESS;
00424     int dlck        = 0;
00425 
00426     /* Try to get the lock */
00427 
00428 #if defined(HAVE_PTHREAD) && !defined(WIN32)    
00429     rc = pthread_mutex_trylock(&(this->m_mutex_info->m_mutex));
00430     /* we don't want to fail on deadlock, just return 1 */
00431     if (rc == EDEADLK) { rc = 0; retrc = 1; }
00432     /* This means we can't get the lock, so return -1 */
00433     if (rc == EBUSY)   { rc = 0; retrc = 1; }
00434     //if (rc != 0)       { rc = 0; retrc = 1; }
00435     phPRINT_RC(rc,"pthread_mutex_trylock","trylock failed");
00436 #endif
00437 
00438 #if defined(WIN32)
00439     DWORD dwResult      = WaitForSingleObject( this->m_mutex_info->m_mutex, 0L );
00440     if ((dwResult == WAIT_OBJECT_0) || (dwResult == WAIT_ABANDONED))
00441         rc = phSUCCESS; 
00442     else if (dwResult == WAIT_TIMEOUT)
00443     {
00444         retrc = 1;
00445         rc = phSUCCESS;
00446     }
00447     else 
00448         rc = phFAIL;
00449     phCHECK_RC(rc,"WaitForSingleObject",
00450                "WaitForSingleObject failed - HANDLE: 0x%08x\n",
00451                (unsigned long)this->m_mutex_info->m_mutex);
00452 #endif
00453 
00454 #if defined(__ADSPBLACKFIN__)
00455     /* UGH! No try lock/try acquire in the VDK */
00456     if (this->m_owner != phGetCurrentThreadId())
00457     {
00458         #if USE_VDK_RMUTEX()
00459         VDK::RMutexAcquire(&(this->m_mutex_info->m_mutex));
00460         retrc = phSUCCESS;
00461         #endif
00462         #if USE_ADI_SPINLOCK()
00463         rc = adi_try_lock(&(this->m_mutex_info->m_mutex));
00464         if (!rc) 
00465             retrc = 0;
00466         else
00467             retrc = 1;
00468         #endif
00469         #if USE_VDK_SPINLOCK()
00470         rc = vdk_try_lock(&(this->m_mutex_info->m_mutex));
00471         if (!rc) 
00472             retrc = 0;
00473         else
00474             retrc = 1;
00475         #endif
00476         #if USE_VDK_SEMAPHORE()
00477         if (VDK::PendSemaphore(this->m_mutex_info->m_mutex,
00478                                1 | VDK::kNoTimeoutError))
00479             retrc = 0;
00480         else
00481             retrc = 1;
00482         #endif
00483     }
00484 #endif
00485 
00486     /* only increment if we actually got the lock */
00487     if (retrc != 1)
00488     {
00489         rc = this->incLockCount();
00490         phCHECK_RC(rc,NULL,"this->incLockCount()");
00491     }
00492     
00493     return retrc;
00494 error:
00495     return phFAIL;
00496 }
00497 
00498 /* ------------------------------------------------------------------------- */
00499 int phMutex::unlock( )
00500 {
00501     phFUNCTION("phMutex::unlock")
00502 #if defined(WIN32)
00503     BOOL bResult;
00504 #endif
00505 
00506     rc = this->decLockCount();
00507     phCHECK_RC(rc,NULL,"this->decLockCount()");
00508     
00509     /* decLockCount will prevent any thread that doesn't own the lock
00510      * from getting to here */
00511 
00512     /* NOW unlock the mutex */
00513     
00514 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00515     rc = pthread_mutex_unlock(&(this->m_mutex_info->m_mutex));
00516     phCHECK_RC(rc, "pthread_mutex_unlock", "unlocking this->m_mutex_info->m_mutex failed");
00517 #endif
00518 
00519 #if defined(WIN32)
00520     bResult        = ReleaseMutex(this->m_mutex_info->m_mutex);
00521     if (!bResult) rc = phFAIL; else rc = phSUCCESS;
00522     phCHECK_RC(rc,"ReleaseMutex",
00523              "ReleaseMutex - HANDLE: 0x%08x\n",
00524              (unsigned long)this->m_mutex_info->m_mutex);    
00525 #endif
00526 
00527 #if defined(__ADSPBLACKFIN__)
00528     //phPROGRESS("(this:%p) owner:%u locked:%u\n",this,this->m_owner,this->m_locked_count);
00529     if (this->m_locked_count == 0)
00530     {
00531         #if USE_VDK_RMUTEX()    
00532         VDK::RMutexRelease(&(this->m_mutex_info->m_mutex));
00533         #endif
00534         #if USE_ADI_SPINLOCK()
00535             adi_release_lock(&(this->m_mutex_info->m_mutex));
00536         #endif
00537         #if USE_VDK_SPINLOCK()  
00538             vdk_release_lock(&(this->m_mutex_info->m_mutex));
00539         #endif
00540         #if USE_VDK_SEMAPHORE()
00541             VDK::PostSemaphore(this->m_mutex_info->m_mutex);
00542         #endif
00543     }
00544 #endif
00545 
00546     /* Return with SUCCESS */
00547     
00548     return phSUCCESS;
00549 error:
00550     return phFAIL;
00551 }
00552 
00553 /* These methods could make the system more stable, however, there's 
00554  * greater potential for slowing the system down due to excessive locking
00555  * when calling isNamed. This is going to be a trade-off for now, at
00556  * least until someone proves that this is absolutely necessary given
00557  * that all objects (1) call set name in their constructor when they have
00558  * the lock and (2) if the object is being destroyed, the object has the lock
00559  * and will destroy the lock, causing most of the code to bomb out anyway */
00560 
00561 #if 0
00562 /* ------------------------------------------------------------------------- */
00563 void phMutex::setName(const char *n)
00564 {
00565     phFUNCTION("phMutex::")
00566     
00567     rc = this->lock();
00568     phPRINT_RC(rc,NULL,"this->lock()");
00569     
00570     this->phObject::setName(n);
00571 
00572     rc = this->unlock();
00573     phPRINT_RC(rc,NULL,"this->unlock()");
00574 }
00575 
00576 /* ------------------------------------------------------------------------- */
00577 int phMutex::isNamed(const char *n)
00578 {
00579     phFUNCTION("phMutex::isNamed")
00580     int retrc = phSUCCESS;
00581 
00582     rc = this->lock();
00583     phPRINT_RC(rc,NULL,"this->lock()");
00584 
00585     retrc = this->phObject::isNamed(n);
00586     
00587     rc = this->unlock();
00588     phPRINT_RC(rc,NULL,"this->unlock()");
00589 
00590     return retrc;
00591 }
00592 #endif




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:02 2007 for phission by  doxygen 1.4.4