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

phCondition.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2004 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 #include <phObject.h>
00032 #include <phMutex.h>
00033 
00034 #include <phCondition.h>
00035 
00036 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00037     #include <pthread.h>
00038 #endif
00039 #if defined(WIN32)
00040     #include <windows.h>
00041 #endif
00042 #if defined(__ADSPBLACKFIN__)
00043     #include <PhissionVDK.h>
00044 #endif
00045 #if defined(HAVE_ERRNO_H) && defined(HAVE_PTHREAD) && !defined(WIN32)
00046     #include <errno.h>
00047 #endif
00048 #if defined(HAVE_TIME_H)
00049     #include <time.h>
00050 #endif
00051 
00052 #include <phError.h>
00053 #include <phMemory.h>
00054 #include <phPrint.h>
00055 
00056 /* ---------------------------------------------------------------------- */
00057 #if defined(__ADSPBLACKFIN__)
00058 typedef struct ph_cond_node_t
00059 {
00060     struct ph_cond_node_t *next;
00061     struct ph_cond_node_t *prev;
00062 
00063     VDK::SemaphoreID                sem;
00064 
00065     uint32_t                        id;
00066     
00067     uint8_t                         broadcast_last_waiter;
00068 } ph_cond_node_type;
00069 #endif
00070 /* ---------------------------------------------------------------------- */
00071 struct ph_condition_info_t 
00072 {
00073 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00074     /* pthreads condition variables */
00075     pthread_cond_t m_cond;
00076 #endif
00077 #if defined(WIN32)
00078     int         m_nwaiters;
00079     int         m_was_broadcast;
00080     HANDLE      m_sem;
00081     HANDLE      m_wdone;
00082 #endif
00083 #if defined(__ADSPBLACKFIN__)
00084     phMutex                    *m_semlock;
00085 //    VDK::SemaphoreID            m_semtaken;
00086     VDK::SemaphoreID            m_wdone;
00087     ph_cond_node_type          *m_head;
00088     ph_cond_node_type          *m_tail;
00089     uint32_t                    m_nwaiters;
00090 #endif
00091 };
00092 
00093 /* ---------------------------------------------------------------------- */
00094 phCondition::phCondition( ) : phMutex()
00095 {
00096     phFUNCTION("phCondition::phCondition")
00097     int prc     = 0;
00098     int locked  = 0;
00099 
00100     phTHIS_LOOSE_LOCK(locked);
00101 
00102     this->setName("phCondition");
00103     
00104     this->m_info = (struct ph_condition_info_t *)phCalloc(1,
00105                             sizeof(struct ph_condition_info_t));
00106     phPRINT_PTR(this->m_info,"phCalloc","phCalloc failed.");
00107     /*
00108      * int    pthread_cond_init(pthread_cond_t    *cond,
00109      *                          pthread_condattr_t *cond_attr);
00110      */                          
00111 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00112     prc = pthread_cond_init(&this->m_info->m_cond, NULL);
00113     if (prc != 0) rc = phFAIL; else rc = phSUCCESS;
00114     phPRINT_RC(rc,NULL,
00115         "pthread_cond_init - initializing the condition variable failed. This is impossible.");
00116 #endif
00117 
00118 #if defined(WIN32)
00119     rc = this->m_info_lock.lock();
00120     phPRINT_RC(rc,NULL,"m_info_lock.lock()");
00121 
00122     this->m_info->m_sem = CreateSemaphore (NULL,0,
00123                                 0x7fffffff,NULL);
00124     phPRINT_NULLPTR(this->m_info->m_sem,"new","new semaphore failed.");
00125 
00126     this->m_info->m_wdone = CreateEvent(NULL,FALSE,FALSE,NULL);
00127     phPRINT_NULLPTR(this->m_info->m_wdone,"CreateEvent",
00128         "CreateEvent failed for waiters done event.");
00129     
00130     this->m_info->m_nwaiters = 0;
00131     this->m_info->m_was_broadcast = 0;
00132     
00133     rc = this->m_info_lock.unlock();
00134     phPRINT_RC(rc,NULL,"m_info_lock.unlock()");
00135 
00136 #endif
00137 
00138 #if defined(__ADSPBLACKFIN__)
00139     this->m_info->m_semlock = new phMutex();
00140     this->m_info->m_wdone   = VDK::CreateSemaphore(0,1,0,0);
00141     this->m_info->m_head    = this->m_info->m_tail = NULL;
00142     this->m_info->m_nwaiters= 0;
00143 #endif
00144     
00145     phTHIS_LOOSE_UNLOCK(locked);
00146 }
00147 
00148 /* ---------------------------------------------------------------------- */
00149 /* ---------------------------------------------------------------------- */
00150 phCondition::~phCondition( )
00151 {
00152     phFUNCTION("phCondition::~phCondition")
00153     int prc = 0;
00154     int locked = 0;
00155   
00156 #if defined(WIN32)
00157     BOOL bResult = FALSE;
00158 #endif
00159 #if defined(__ADSPBLACKFIN__)
00160     ph_cond_node_type   *node       = NULL;
00161     ph_cond_node_type   *temp_node  = NULL;
00162     VDK::SemaphoreID    sem         = (VDK::SemaphoreID)UINT_MAX;
00163 #endif
00164 
00165     phTHIS_LOOSE_LOCK(locked);
00166     
00167 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00168     /*
00169      * int pthread_cond_destroy(pthread_cond_t *cond);
00170      */
00171     /* destroy the lock */
00172     prc = pthread_cond_destroy(&(this->m_info->m_cond));
00173     if (prc != 0) rc = phFAIL; else rc = phSUCCESS;
00174     phPRINT_RC(rc,NULL,"pthread_cond_destroy - destroying cond failed : %s",
00175              ((prc == EBUSY) ? "EBUSY" : "Unknown"));
00176 #endif
00177 #if defined(WIN32)
00178     bResult = CloseHandle(this->m_info->m_wdone);
00179     if (!bResult) rc = phFAIL; else rc = phSUCCESS;
00180     phPRINT_RC(rc,"CloseHandle","CloseHandle when closing signal\n");
00181 
00182     bResult = CloseHandle(this->m_info->m_sem);
00183     if (!bResult) rc = phFAIL; else rc = phSUCCESS;
00184     phPRINT_RC(rc,"CloseHandle","CloseHandle when closing broadcast\n");
00185 
00186     this->m_info->m_nwaiters = 0;
00187     this->m_info->m_was_broadcast = 0;
00188 #endif
00189 #if defined(__ADSPBLACKFIN__)
00190     rc = this->m_info->m_semlock->lock();
00191     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00192     
00193     node = this->m_info->m_head;
00194     /* let everyone go */
00195     while (node != NULL)
00196     {
00197         /* Post the semaphore to let the first go */
00198         VDK::PostSemaphore(node->sem);
00199         
00200         /* save the a temporary pointer to the next node */    
00201         temp_node = node->next;
00202 
00203         node->prev = node->next = NULL;
00204         
00205         sem = node->sem;
00206         
00207         /* Set the node to the next node */
00208         node = temp_node;
00209     }
00210     
00211     phDelete(this->m_info->m_semlock);
00212     VDK::DestroySemaphore(this->m_info->m_wdone);
00213 #endif
00214 
00215     phFree(this->m_info);
00216 }
00217 
00218 /* ---------------------------------------------------------------------- */
00219 /* ---------------------------------------------------------------------- */
00220 int phCondition::broadcast( )
00221 {
00222     phFUNCTION("phCondition::broadcast")
00223     int prc = 0;
00224     int retrc = 0;
00225 #if defined(WIN32)
00226     int have_waiters = 0;
00227     BOOL bResult = TRUE;
00228     DWORD dwResult = 0;
00229 #endif
00230 #if defined(__ADSPBLACKFIN__)
00231     ph_cond_node_type  *node        = NULL;
00232     ph_cond_node_type  *temp_node   = NULL;
00233     VDK::SemaphoreID    sem         = (VDK::SemaphoreID)UINT_MAX;
00234 #endif
00235 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00236     /* 
00237      * pthread_cond_broadcast
00238      * 
00239      * int pthread_cond_broadcast(pthread_cond_t *cond);
00240      * 
00241      * This shouldn't return an error code, but I'm checking anyway!
00242      */
00243     prc = pthread_cond_broadcast(&(this->m_info->m_cond));
00244     if (prc != 0) rc = phFAIL; else rc = phSUCCESS;
00245     phCHECK_RC(rc,NULL,
00246        "pthread_cond_broadcast - broadcast on m_info->m_cond failed; This is impossible");
00247 #endif
00248 #if defined(WIN32)
00249     rc = this->m_info_lock.lock();
00250     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00251     
00252     if (this->m_info->m_nwaiters > 0)
00253     {
00254         have_waiters = 1;
00255         this->m_info->m_was_broadcast = 1;
00256     }
00257     
00258     if (have_waiters)
00259     {
00260         bResult = ReleaseSemaphore(this->m_info->m_sem,
00261                                    this->m_info->m_nwaiters,
00262                                    NULL);
00263         if (!bResult)
00264             rc = phFAIL;
00265         else
00266             rc = phSUCCESS;
00267         phPRINT_RC(rc,"ReleaseSemaphore","ReleaseSemaphore failed.");
00268     
00269         rc = this->m_info_lock.unlock();
00270         phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00271     
00272         dwResult = WaitForSingleObject(this->m_info->m_wdone,INFINITE);
00273         /* There was an error waiting on the thread */
00274         if (dwResult == WAIT_FAILED) 
00275         {
00276             rc = phFAIL; 
00277             retrc = phFAIL;
00278         }
00279         else
00280         {
00281             rc = phSUCCESS;
00282             retrc = phSUCCESS;
00283         }
00284         phPRINT_RC(rc,"WaitForSingleObject","Wait on failed: m_info->m_wdone.");    
00285     
00286         this->m_info->m_was_broadcast = 0;
00287     }
00288     else
00289     {
00290         rc = this->m_info_lock.unlock();
00291         phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00292     }
00293 #endif
00294 
00295 #if defined(__ADSPBLACKFIN__)
00296     rc = this->m_info->m_semlock->lock();
00297     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00298     
00299     if (this->m_info->m_head != NULL)
00300     {
00301         node = this->m_info->m_head;
00302 
00303         /* release everyone and wait for each to take the semaphore */
00304         while ((node != NULL) && (this->m_info->m_nwaiters > 0))
00305         {
00306             /* get the semaphore id */
00307             sem = node->sem;
00308             
00309             /* get a pointer to the next node */
00310             temp_node = node->next;
00311 
00312             node->prev = node->next = NULL;
00313 
00314             /* if this is the last node, then tell it that it's the last
00315              * one so we can synchronize with it */
00316             //phPROGRESS("%p %d\n",temp_node,this->m_info->m_nwaiters);
00317             if ((temp_node == NULL) || (this->m_info->m_nwaiters == 1))
00318             {
00319                 //phPROGRESS("broadcast_last_waiter=1\n");
00320                 node->broadcast_last_waiter = 1;
00321             }
00322            
00323             //phPROGRESS("Releasing %d\n",node->id);
00324            
00325             /* Post a sempahore to the thread */
00326             VDK::PostSemaphore(sem);
00327             
00328             node = temp_node;
00329 
00330             this->m_info->m_nwaiters--;
00331         }
00332         
00333         /* node should be NULL, but just in case... */
00334         if (node != NULL)
00335         {
00336             phERROR_PRINT(NULL,"We should never get here. Trying to handle impossible situation\n");
00337             this->m_info->m_head = node;
00338         }
00339         else
00340             this->m_info->m_head = this->m_info->m_tail = NULL;
00341         
00342         VDK::PendSemaphore(this->m_info->m_wdone,0L);
00343         /* TODO: Check return code */
00344         
00345         rc = this->m_info->m_semlock->unlock();
00346         phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00347     }
00348     else
00349     {
00350         rc = this->m_info->m_semlock->unlock();
00351         phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00352     }
00353 #endif
00354     
00355     return retrc;
00356 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00357 error:
00358     return phFAIL;
00359 #endif
00360 }
00361 
00362 /* ---------------------------------------------------------------------- */
00363 /* ---------------------------------------------------------------------- */
00364 int phCondition::signal( )
00365 {
00366     phFUNCTION("phCondition::signal")
00367     int                 prc         = 0;
00368     int                 retrc       = phSUCCESS;
00369 #if defined(WIN32)
00370     int                 have_waiters= 0;
00371     BOOL                bResult     = TRUE;
00372 #endif
00373 #if defined(__ADSPBLACKFIN__)
00374     VDK::SemaphoreID    sem         = (VDK::SemaphoreID)UINT_MAX;
00375     ph_cond_node_type  *node        = NULL;
00376     ph_cond_node_type  *temp_node   = NULL;
00377 #endif
00378 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00379     /* 
00380      * pthread_cond_signal
00381      * int pthread_cond_signal(pthread_cond_t *cond);
00382      * 
00383      * This shouldn't return an error code, but I'm checking anyway!
00384      */
00385     prc = pthread_cond_signal(&(this->m_info->m_cond));
00386     if (prc != 0) rc = phFAIL; else rc = phSUCCESS;
00387     phCHECK_RC(rc,NULL,
00388         "pthread_cond_signal - signal on cond failed; This is impossible");
00389 #endif
00390 #if defined(WIN32)
00391     rc = this->m_info_lock.lock();
00392     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00393     if (this->m_info->m_nwaiters > 0)
00394     {
00395         have_waiters = 1;
00396     }
00397     rc = this->m_info_lock.unlock();
00398     phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00399     
00400     if (have_waiters)
00401     {
00402         bResult = ReleaseSemaphore(this->m_info->m_sem,1,NULL);
00403         if (!bResult)
00404         {
00405             rc = phFAIL;
00406             retrc = phFAIL;
00407         }
00408         else
00409         {
00410             rc = phSUCCESS;
00411             retrc = phSUCCESS;
00412         }
00413         phPRINT_RC(rc,"ReleaseSemaphore","ReleaseSemaphore failed.");
00414     }
00415 #endif
00416 #if defined(__ADSPBLACKFIN__)
00417     rc = this->m_info->m_semlock->lock();
00418     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00419     
00420     if (this->m_info->m_head != NULL)
00421     {
00422         node = this->m_info->m_head;
00423         
00424         /* get the semaphore id */
00425         sem = node->sem;
00426         
00427         /* get a pointer to the next node */
00428         temp_node = node->next;
00429 
00430         /* Post a sempahore to the thread */
00431         //phPROGRESS("Post - %d owned by %d\n",(int32_t)sem,node->id)
00432         VDK::PostSemaphore(sem);
00433         
00434         /* we're responsible for decrementing the waiters */
00435         this->m_info->m_nwaiters--;
00436 
00437         /* Set the head pointer to the next node; if the next node 
00438          * is NULL, then m_head will be NULL */
00439         this->m_info->m_head = temp_node;
00440 
00441         node->prev = node->next = NULL;
00442         
00443         /* Set the tail pointer to NULL if it points to the current node
00444          * that we're signaling */
00445         if (this->m_info->m_tail == node)
00446             this->m_info->m_tail = NULL;
00447     }
00448     
00449     rc = this->m_info->m_semlock->unlock();
00450     phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00451 #endif
00452     
00453     return retrc;
00454 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00455 error:
00456     return phFAIL;
00457 #endif
00458 }
00459 
00460 /* ---------------------------------------------------------------------- */
00461 /* ---------------------------------------------------------------------- */
00462 int phCondition::timedWait(const int sec, const int nsec )
00463 {
00464     phFUNCTION("phCondition::timedWait")
00465     int             prc     = 0;
00466     int             retrc   = phSUCCESS;
00467 //#ifdef HAVE_CLOCK_GETTIME
00468 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00469     struct timespec t;
00470     /* struct timeval  now; */
00471 #endif
00472 #if defined(WIN32)
00473     int             locked      = 0;
00474     DWORD           dwResult    = 0;
00475     int             last_waiter = 0;
00476 #endif
00477 #if defined(__ADSPBLACKFIN__)
00478     /* We should be locked when we get in here */
00479     int                 locked      = 1;
00480     VDK::Ticks          ticks       = 0;
00481     VDK::Ticks          timepassed  = 0;
00482     VDK::SemaphoreID    my_sem      = (VDK::SemaphoreID)UINT_MAX;
00483     ph_cond_node_type  *node        = NULL;
00484 #endif
00485 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00486     /* 
00487      * pthread_cond_timedwait
00488         * 0: successful, 1: unsuccessful, -1: error *
00489      * 
00490      * int   pthread_cond_timedwait(pthread_cond_t   *cond,    
00491      *                              pthread_mutex_t  *mutex, 
00492      *                              const struct timespec *abstime);
00493      *
00494      */
00495 
00496 #if 0
00497     gettimeofday(&now,NULL);
00498     t.tv_sec = now.tv_sec + sec;
00499     t.tv_nsec = now.tv_usec * 1000 + nsec;
00500 #endif
00501     clock_gettime(CLOCK_REALTIME, &t);
00502     t.tv_sec    += sec;
00503     t.tv_nsec   += nsec;
00504 
00505     rc = this->decLockCount();
00506     phCHECK_RC(rc,NULL,"this->decLockCount()");
00507 
00508     if (this->getLockCount() > 0)
00509     {
00510         phWARN("phCondition(this:%p) still owns the lock and might cause a deadlock\n",
00511                this );
00512     }
00513 
00514     prc = pthread_cond_timedwait(&(this->m_info->m_cond),
00515                                  (pthread_mutex_t*)(this->m_private_mutex),
00516                                  &t);
00517     rc = this->incLockCount();
00518     phCHECK_RC(rc,NULL,"this->incLockCount()");
00519 
00520     if (prc != 0) 
00521     {
00522         if (errno == ETIMEDOUT)
00523         {
00524             retrc = phCondition_NOTRECEIVED;
00525         }
00526         else
00527         {
00528             rc = phFAIL; 
00529         }
00530     }
00531     else 
00532         rc = phSUCCESS;
00533     phCHECK_RC(rc,NULL, "pthread_cond_timedwait - timedwait on cond failed");
00534 #endif
00535     
00536 #if defined(WIN32)
00537     rc = this->m_info_lock.lock();
00538     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00539     this->m_info->m_nwaiters++;
00540     rc = this->m_info_lock.unlock();
00541     phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00542     
00543     rc = this->decLockCount();
00544     phCHECK_RC(rc,NULL,"this->decLockCount()");
00545 
00546     if (this->getLockCount() > 0)
00547     {
00548         phWARN("phCondition(this:%p) still owns the lock and might cause a deadlock\n",
00549                this );
00550     }
00551 
00552     /* TODO: check to see if we get the Mutex back even on a timeout */
00553     dwResult = SignalObjectAndWait(
00554                         *((HANDLE*)this->m_private_mutex),
00555                         this->m_info->m_sem,
00556                         sec * 1000 + ((int)(nsec / 6)),
00557                         FALSE);
00558     if ((dwResult == WAIT_ABANDONED) ||
00559         (dwResult == WAIT_FAILED) ||
00560         (dwResult == WAIT_IO_COMPLETION))
00561     {
00562         rc      = phFAIL;
00563         retrc   = phFAIL;
00564     }
00565     else if (dwResult == WAIT_OBJECT_0)
00566     {
00567         rc      = phSUCCESS;
00568         retrc   = phSUCCESS;
00569     }
00570     else if (dwResult == WAIT_TIMEOUT)
00571     {
00572         rc = phSUCCESS;
00573         /* We won't do anything special,
00574            We'll just try to get the mutex back later */
00575         retrc = phCondition_RECEIVED;
00576     }
00577     phPRINT_RC(rc,"SignalObjectAndWait","SignalObjectAndWait");
00578     
00579     rc = this->m_info_lock.lock();
00580     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00581     
00582     this->m_info->m_nwaiters--;
00583     
00584     if ((this->m_info->m_was_broadcast) && 
00585         (this->m_info->m_nwaiters == 0) && 
00586         (retrc == phSUCCESS))
00587     {
00588         last_waiter = 1;
00589     }
00590         
00591     rc = this->m_info_lock.unlock();
00592     phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00593     
00594     if (last_waiter)
00595     {
00596         dwResult = SignalObjectAndWait(this->m_info->m_sem,
00597                             *((HANDLE*)this->m_private_mutex),
00598                             INFINITE,
00599                             FALSE);
00600         if ((dwResult == WAIT_ABANDONED) ||
00601             (dwResult == WAIT_FAILED) ||
00602             (dwResult == WAIT_IO_COMPLETION))
00603         {
00604             rc      = phFAIL;
00605             retrc   = phFAIL;
00606         }
00607         else if (dwResult == WAIT_OBJECT_0)
00608         {
00609             rc = this->incLockCount();
00610             phCHECK_RC(rc,NULL,"this->incLockCount()");
00611 
00612             rc      = phSUCCESS;
00613             retrc   = phSUCCESS;
00614         }
00615         phPRINT_RC(rc,"SignalObjectAndWait","SignalObjectAndWait");
00616     }
00617     else if (retrc == phSUCCESS)
00618     {
00619         phTHIS_LOOSE_LOCK(locked);
00620     }
00621 #endif
00622 
00623 #if defined(__ADSPBLACKFIN__)
00624     ticks = (sec * (/* ticks per second */ 1000 / VDK::GetTickPeriod() /* ms */)) + 
00625             ((((double)nsec) / 1000000.0 /* ms */) * VDK::GetTickPeriod() /* ms */);
00626             
00627     timepassed = VDK::GetUptime();
00628 
00629     /* allocate a node on to add to the list */
00630     node = (ph_cond_node_type *)phCalloc(1,sizeof(ph_cond_node_type));
00631     phCHECK_PTR(node,"phCalloc","phCalloc fail to allocate condition node");
00632 
00633     node->broadcast_last_waiter = 0;
00634     /* Create a semaphore to wait on */
00635     my_sem = node->sem = VDK::CreateSemaphore(0,1,0,0);
00636     node->id = phGetCurrentThreadId();
00637 
00638     rc = this->m_info->m_semlock->lock();
00639     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00640     
00641     if (this->m_info->m_head == NULL)
00642         this->m_info->m_head = this->m_info->m_tail = node;
00643     else
00644     {
00645         node->prev                 = this->m_info->m_tail;
00646         this->m_info->m_tail->next = node;
00647         this->m_info->m_tail       = node;
00648     }
00649     rc = this->m_info->m_semlock->unlock();
00650     phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00651     
00652     phTHIS_LOOSE_UNLOCK(locked);
00653     
00654     /* adjust ticks to be the total time we've been in this method */
00655     timepassed = VDK::GetUptime() - timepassed; // TODO: Check for loop around
00656     if (timepassed > ticks) ticks = 0;
00657     else                    ticks -= timepassed;
00658     
00659     if (VDK::PendSemaphore(my_sem,
00660                            ticks | VDK::kNoTimeoutError))
00661         retrc = phSUCCESS;
00662     else
00663         retrc = phCondition_NOTRECEIVED;
00664 
00665     rc = this->m_info->m_semlock->lock();
00666     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00667 
00668     phTHIS_LOOSE_LOCK(locked);
00669 
00670     /* if the semaphore was posted between timeout and getting the lock,
00671      * then we got the semaphore */
00672     if (VDK::GetSemaphoreValue(my_sem) > 0)
00673     {
00674         VDK::PendSemaphore(my_sem,0L);
00675         retrc = phSUCCESS;
00676 //        VDK::PostSemaphore(this->m_info->m_semtaken);
00677         VDK::DestroySemaphore(my_sem);
00678     }
00679     /* Otherwise we didn't get the semaphore, so we need to remove
00680      * ourselves from the queue */
00681     else
00682     {
00683         if (this->m_info->m_tail == node)
00684             this->m_info->m_tail = node->prev;
00685             
00686         if (this->m_info->m_head == node)
00687             this->m_info->m_head = node->next;
00688             
00689         if (node->prev != NULL)
00690             node->prev->next = node->next;
00691             
00692         if (node->next != NULL)
00693             node->next->prev = node->prev;
00694     }
00695 
00696     rc = this->m_info->m_semlock->unlock();
00697     phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00698 
00699     phFree(node);
00700     
00701 #endif
00702 
00703     return retrc;
00704 error:
00705     return phFAIL;
00706 }
00707 
00708 /* ---------------------------------------------------------------------- */
00709 /* ---------------------------------------------------------------------- */
00710 int phCondition::signalWait( )
00711 {
00712     phFUNCTION("phCondition::signalWait")
00713     int     prc         = 0;
00714     int     retrc       = phSUCCESS;
00715     int     locked      = 1;
00716 #if defined(WIN32)
00717     int     last_waiter = 0;
00718     DWORD   dwResult    = 0;
00719 #endif
00720 #if defined(__ADSPBLACKFIN__)
00721     VDK::SemaphoreID    my_sem  = (VDK::SemaphoreID)UINT_MAX;
00722     ph_cond_node_type  *node    = NULL;
00723 #endif
00724     
00725 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00726     /* 
00727      * pthread_cond_wait
00728      * int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
00729      *
00730      * This shouldn't return an error code, but I'm checking anyway!
00731      */
00732     rc = this->decLockCount();
00733     phCHECK_RC(rc,NULL,"this->decLockCount()");
00734 
00735     if (this->getLockCount() > 0)
00736     {
00737         phWARN("phCondition(this:%p) still owns the lock and might cause a deadlock\n",
00738                this );
00739     }
00740     
00741     prc = pthread_cond_wait(&(this->m_info->m_cond),
00742                             (pthread_mutex_t*)(this->m_private_mutex));
00743     if (prc != 0) rc = phFAIL; else rc = phSUCCESS;
00744     phCHECK_RC(rc,NULL,
00745         "pthread_cond_wait - signalWait on cond failed; This is impossible");
00746 
00747     rc = this->incLockCount();
00748     phCHECK_RC(rc,NULL,"this->incLockCount()");
00749 #endif
00750 #if defined(WIN32)
00751     /* increment the number of waiters */
00752     rc = this->m_info_lock.lock();
00753     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00754     this->m_info->m_nwaiters++;
00755     rc = this->m_info_lock.unlock();
00756     phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00757     
00758     rc = this->decLockCount();
00759     phCHECK_RC(rc,NULL,"this->decLockCount()");
00760 
00761     if (this->getLockCount() > 0)
00762     {
00763         phWARN("phCondition(this:%p) still owns the lock and might cause a deadlock\n",
00764                this );
00765     }
00766 
00767     /* release the object lock and wait to be signaled */
00768     dwResult = SignalObjectAndWait(
00769                         *((HANDLE*)this->m_private_mutex),
00770                         this->m_info->m_sem,
00771                         INFINITE,
00772                         FALSE);
00773     /* Check to make sure we didn't get an error */
00774     if ((dwResult == WAIT_ABANDONED) ||
00775         (dwResult == WAIT_FAILED) ||
00776         (dwResult == WAIT_IO_COMPLETION))
00777     {
00778         rc      = phFAIL;
00779         retrc   = phFAIL;
00780     }
00781     /* if we succeeded, then we have the object lock (and we took a
00782      * semaphore) */
00783     else if (dwResult == WAIT_OBJECT_0)
00784     {
00785         rc      = phSUCCESS;
00786         retrc   = phSUCCESS;
00787     }
00788     phPRINT_RC(rc,"SignalObjectAndWait","SignalObjectAndWait");
00789     
00790     /* reacquire the info lock to decrement the number of waiters */
00791     rc = this->m_info_lock.lock();
00792     phPRINT_RC(rc,NULL,"this->m_info_lock.lock()");
00793     
00794     this->m_info->m_nwaiters--;
00795     
00796     /* if it was a broadcast that released us and we're the last waiter,
00797      * then remember this */
00798     if ((this->m_info->m_was_broadcast) && 
00799         (this->m_info->m_nwaiters == 0) &&
00800         (retrc == phSUCCESS))
00801     {
00802         last_waiter = 1;
00803     }
00804         
00805     /* unlock the info lock to let other waiters through */
00806     rc = this->m_info_lock.unlock();
00807     phPRINT_RC(rc,NULL,"this->m_info_lock.unlock()");
00808     
00809     /* if we were the last waiter, then we need to let the
00810      * signalling/broadcasting thread know that we're done.
00811      * The signalling thread will reset the m_wdone event as soon as it
00812      * gets it */
00813     if (last_waiter) /* can't get set w/o retrc == phSUCCESS */
00814     {
00815         /* set the m_wdone event and wait for the object lock */
00816         dwResult = SignalObjectAndWait(this->m_info->m_wdone,
00817                             *((HANDLE*)this->m_private_mutex),
00818                             INFINITE,
00819                             FALSE);
00820         /* Check to see if we had an error */
00821         if ((dwResult == WAIT_ABANDONED) ||
00822             (dwResult == WAIT_FAILED) ||
00823             (dwResult == WAIT_IO_COMPLETION))
00824         {
00825             rc = phFAIL;
00826         }
00827         /* The signalling thread has let the object lock go and the event
00828          * has been received by the signalling thread */
00829         else if (dwResult == WAIT_OBJECT_0)
00830         {
00831             rc = this->incLockCount();
00832             phCHECK_RC(rc,NULL,"this->incLockCount()");
00833 
00834             rc = phSUCCESS;
00835         }
00836         phCHECK_RC(rc,"SignalObjectAndWait","SignalObjectAndWait");
00837     }
00838     else if (retrc == phSUCCESS)
00839     {
00840         phTHIS_LOOSE_LOCK(locked);
00841     }
00842 #endif
00843 
00844 #if defined(__ADSPBLACKFIN__)
00845     //phPROGRESS("new node\n");
00846     /* Create a new node to add to the list */
00847     node = (ph_cond_node_type *)phCalloc(1,sizeof(ph_cond_node_type));
00848     phCHECK_PTR(node,"phCalloc","phCalloc fail to allocate condition node");
00849 
00850     node->broadcast_last_waiter = 0;
00851 
00852     my_sem = node->sem = VDK::CreateSemaphore(0,1,0,0);
00853     /* TODO: Check return code */
00854 
00855     node->id = phGetCurrentThreadId();
00856         
00857     rc = this->m_info->m_semlock->lock();
00858     phPRINT_RC(rc,NULL,"m_semlock->lock() failed.");
00859     
00860     /* TODO: Check return code */
00861     
00862     /* increment the number of waiters */
00863     this->m_info->m_nwaiters++;
00864 
00865     //phPROGRESS("Adding:%p\n",this->m_info);
00866     //phPROGRESS("%p\n",this->m_info->m_tail);
00867     /* Add myself to the list : FIFO */
00868     if (this->m_info->m_tail != NULL)
00869     {
00870         node->prev                  = this->m_info->m_tail;
00871         this->m_info->m_tail->next  = node;
00872         this->m_info->m_tail        = node;
00873     }
00874     else
00875     {
00876         //phPROGRESS("head-tail\n");
00877         this->m_info->m_head = this->m_info->m_tail = node;
00878     }
00879 
00880     rc = this->m_info->m_semlock->unlock();
00881     phPRINT_RC(rc,NULL,"m_semlock->unlock() failed.");
00882    
00883     /* There is no race condition between letting this unlock and the
00884      * PendSemphore because the signaling thread will wait until the 
00885      * first thread in the queue has received the semaphore before 
00886      * posting another one */
00887     //phPROGRESS("this unlock\n");
00888     phTHIS_LOOSE_UNLOCK(locked);
00889     
00890     //phPROGRESS("Pend - %d owned by %d\n",(int32_t)node->sem,node->id)
00891     if (VDK::PendSemaphore(my_sem,0))
00892         retrc = phSUCCESS;
00893     else
00894         retrc = phFAIL;
00895     //phPROGRESS("Pended - %d owned by %d\n",(int32_t)node->sem,node->id)
00896 
00897     /* Release the signaller */
00898 //    VDK::PostSemaphore(this->m_info->m_semtaken);
00899     VDK::DestroySemaphore(my_sem);
00900     /* let the broadcasting thread go if we're the last waiter */
00901     //phPROGRESS("broadcast_last_waiter=%d\n", node->broadcast_last_waiter );
00902     if (node->broadcast_last_waiter) VDK::PostSemaphore(this->m_info->m_wdone);
00903 
00904     /* Lock the object */
00905     //phPROGRESS("this->lock\n");
00906     phTHIS_LOOSE_LOCK(locked);
00907     //phPROGRESS("this got lock\n");
00908         
00909     /* Free the list node memory */
00910     phFree(node);
00911     
00912 #endif
00913     
00914     return retrc;
00915 error:
00916     return phFAIL;
00917 }
00918 




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