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

phLiveObject.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 #include <phMutex.h>
00034 #include <phSemaphore.h>
00035 #include <phCondition.h>
00036 #include <phRWLock.h>
00037 #include <phList.h>
00038 #include <phTimeStamp.h>
00039 #include <phTimeInterval.h>
00040 
00041 #include <phLiveObject.h>
00042 
00043 #ifdef HAVE_ERRNO_H
00044 //    #include <errno.h>
00045 #endif
00046 #ifdef HAVE_TIME_H
00047     #include <time.h>
00048 #endif
00049 
00050 #include <phError.h>
00051 #include <phMemory.h>
00052 #include <phPrint.h>
00053 
00054 /* ---------------------------------------------------------------------- */
00055 #define USE_SCHEDULING() 0
00056 
00057 /* ---------------------------------------------------------------------- */
00058 phLiveCookie::phLiveCookie() : phSemaphore(0,1)
00059 {
00060     phFUNCTION("phLiveCookie::phLiveCookie")
00061     int locked = 0;
00062 
00063     phTHIS_LOOSE_LOCK(locked);
00064     
00065     setName("phLiveCookie");
00066     
00067     this->m_cookie_key  = 0;
00068     this->m_cookie_next = NULL;
00069     this->m_cookie_prev = NULL;
00070     this->m_owner       = NULL;
00071     
00072     this->m_jitter_us   = -1;
00073 
00074     phTHIS_LOOSE_UNLOCK(locked);
00075 }
00076 
00077 /* ---------------------------------------------------------------------- */
00078 phLiveCookie::~phLiveCookie()
00079 {
00080     phFUNCTION("phLiveCookie::~phLiveCookie")
00081     int locked = 0;
00082     
00083     phTHIS_LOOSE_LOCK(locked);
00084     
00085     this->m_cookie_key = 0;
00086     this->m_cookie_next = this->m_cookie_prev = NULL;
00087 
00088     /* no need to unlock, when the object is finally destroyed the 
00089      * OS should signal that the mutex is dead */
00090 }
00091 
00092 /* ---------------------------------------------------------------------- */
00093 int phLiveCookie::setNext(phLiveCookie *n)
00094 {
00095     phFUNCTION("phLiveCookie::setNext")
00096     int locked = 0;
00097 
00098     phTHIS_LOOSE_LOCK(locked);
00099     
00100     this->m_cookie_next = n;
00101 
00102     phTHIS_LOOSE_UNLOCK(locked);
00103     
00104     return phSUCCESS;
00105 }
00106 
00107 /* ---------------------------------------------------------------------- */
00108 int phLiveCookie::setPrev(phLiveCookie *p)
00109 {
00110     phFUNCTION("phLiveCookie::setPrev")
00111     int locked = 0;
00112 
00113     phTHIS_LOOSE_LOCK(locked);
00114     
00115     this->m_cookie_prev = p;
00116     
00117     phTHIS_LOOSE_UNLOCK(locked);
00118     
00119     return phSUCCESS;
00120 }
00121 
00122 /* ---------------------------------------------------------------------- */
00123 phLiveCookie *phLiveCookie::getNext()
00124 {
00125     phFUNCTION("phLiveCookie::getNext")
00126     int          locked = 0;
00127     phLiveCookie *n     = NULL;
00128     
00129     phTHIS_LOOSE_LOCK(locked);
00130     
00131     n = this->m_cookie_next;
00132     
00133     phTHIS_LOOSE_UNLOCK(locked);
00134     
00135     return n;
00136 }
00137 
00138 /* ---------------------------------------------------------------------- */
00139 phLiveCookie *phLiveCookie::getPrev()
00140 {
00141     phFUNCTION("phLiveCookie::getPrev")
00142     int          locked = 0;
00143     phLiveCookie *p     = NULL;
00144     
00145     phTHIS_LOOSE_LOCK(locked);
00146     
00147     p = this->m_cookie_prev;
00148     
00149     phTHIS_LOOSE_UNLOCK(locked);
00150     
00151     return p;
00152 }
00153 
00154 /* ---------------------------------------------------------------------- */
00155 /* Could also be refered to as setSelf; this method stores the pointer to
00156  * the owner of the cookie */
00157 int phLiveCookie::setOwner(phLiveObject *object)
00158 {
00159     phFUNCTION("phLiveCookie::setOwner")
00160     int locked = 0;
00161 
00162     phTHIS_LOCK(locked);
00163     
00164     this->m_owner = object;
00165     
00166     phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL);
00167 }
00168 
00169 /* ---------------------------------------------------------------------- */
00170 phLiveObject *phLiveCookie::getOwner()
00171 {
00172     phFUNCTION("phLiveCookie::getOwner")
00173     int             locked = 0;
00174     phLiveObject    *owner = NULL;
00175 
00176     phTHIS_LOCK(locked);
00177     
00178     owner = this->m_owner;
00179     
00180     phTHIS_UNLOCK(locked);
00181     
00182     return owner;
00183 error:
00184     return NULL;
00185 }
00186 
00187 /* ---------------------------------------------------------------------- */
00188 int phLiveCookie::setKey(uint32_t k)
00189 {
00190     phFUNCTION("phLiveCookie::setKey")
00191     int locked = 0;
00192 
00193     phTHIS_LOOSE_LOCK(locked);
00194     
00195     this->m_cookie_key = k;
00196 
00197     phTHIS_LOOSE_UNLOCK(locked);
00198     
00199     return phSUCCESS;
00200 }
00201 
00202 /* ---------------------------------------------------------------------- */
00203 uint32_t phLiveCookie::getKey() 
00204 { 
00205     return this->m_cookie_key; 
00206 }
00207 
00208 /* ---------------------------------------------------------------------- */
00209 int phLiveCookie::postCookie( )
00210 {
00211     phFUNCTION("phLiveCookie::postCookie")
00212     int locked = 0;
00213     int retrc = 0;
00214    
00215     phTHIS_LOCK(locked);
00216 
00217     retrc = this->postMax();
00218     
00219     /* Start the time interval for the jitter calculation */
00220     this->m_jitter.start();
00221 
00222     phTHIS_UNLOCK_RET(locked,retrc,0);
00223 }
00224 
00225 /* ---------------------------------------------------------------------- */
00226 int phLiveCookie::take(uint32_t flag)
00227 {
00228     phFUNCTION("phLiveCookie::take")
00229     int retrc = phLiveCookieTAKEN;
00230 
00231     /* Check for the wakeup signal */
00232     rc = this->m_wakeup.tryTake();
00233     if (rc == phSemaphoreTAKEN)
00234     {
00235         retrc = phLiveCookieNOTAKE;
00236     }
00237     /* return now if we got the wakeup signal */
00238     if (retrc) goto success;
00239     
00240     rc = this->phSemaphore::take(flag);
00241     if (rc == phSemaphoreNOTAKE)
00242     {
00243         retrc = phLiveCookieNOTAKE;
00244     }
00245  
00246     /* Stop the jitter time interval */
00247     if (retrc == phLiveCookieTAKEN)
00248     {
00249         this->m_jitter.stop();
00250         this->setJitter(this->m_jitter.lastElapsed().getMicroseconds());
00251     }
00252    
00253     /* Check to see if we should ignore the semaphore we just got */
00254     rc = this->m_wakeup.tryTake();
00255     if (rc == phSemaphoreTAKEN)
00256     {
00257         retrc = phLiveCookieNOTAKE;
00258     }
00259 
00260 success:
00261     return retrc;
00262 }
00263 
00264 /* ---------------------------------------------------------------------- */
00265 int phLiveCookie::wakeup()
00266 {
00267     phFUNCTION("phLiveCookie::wakeup")
00268 
00269     rc = this->m_wakeup.post(this->getMax());
00270     phPRINT_RC(rc,NULL,"this->m_wakeup.post()");
00271     
00272     return phSUCCESS;
00273 }
00274 
00275 /* ---------------------------------------------------------------------- */
00276 int phLiveCookie::setJitter( int32_t jitter )
00277 {
00278     phFUNCTION("phLiveCookie::setJitter")
00279     int             locked = 0;
00280 
00281     phTHIS_LOCK(locked);
00282    
00283     this->m_jitter_us = jitter;
00284     
00285     phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL);
00286 }
00287 
00288 /* ---------------------------------------------------------------------- */
00289 int32_t phLiveCookie::getJitter( )
00290 {
00291     phFUNCTION("phLiveCookie::getJitter")
00292     int         locked = 0;
00293     int32_t     retval = 0;
00294 
00295     phTHIS_LOCK(locked);
00296    
00297     retval = this->m_jitter_us;
00298     
00299     phTHIS_UNLOCK_RET(locked,retval,phFAIL);
00300 }
00301 
00302 /* ---------------------------------------------------------------------- */
00303 /* LIVE OBJECT */
00304 /* ---------------------------------------------------------------------- */
00305 
00306 /* ---------------------------------------------------------------------- */
00307 phLiveObject::phLiveObject( ) : phMutex()
00308 {
00309     phFUNCTION("phLiveObject::phLiveObject")
00310     int locked      = 0;
00311     int cm_locked   = 0;
00312 
00313     phTHIS_LOOSE_LOCK(locked);
00314     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00315     
00316     setName("phLiveObject");
00317     
00318     /* Source stuff */
00319     this->m_cookie_head     = NULL;
00320     this->m_cookie_tail     = NULL;
00321     this->m_cookie_count    = 0;
00322 #if 0
00323     this->m_reading_clients = 0;
00324 #endif
00325 
00326 #if 0
00327     srandom(time(NULL));
00328     this->m_source_object_key = random();
00329 #else
00330     this->m_source_object_key = (uint64_t)this;
00331 #endif
00332     /* Here is a logical point to release this lock */
00333     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
00334     
00335     /* Client stuff */
00336     this->m_cookie          = NULL;
00337     this->m_source_object   = NULL;
00338     this->m_connected       = 0;
00339 
00340     this->m_flags           = phLiveObjectDEFAULTFLAGS;
00341 
00342     /* notify enabled by default */
00343     this->m_notify_disabled = 0;
00344 
00345     /* swap enabled by default */
00346     this->m_swap_disabled   = 0;
00347 
00348     /* Jitter stuff */
00349     this->m_notify_jitter_us        = -1;
00350     this->m_notify_jitter_samples   = 0;
00351     this->m_notify_jitter_avg       = -1;
00352     this->m_client_jitter_us        = -1;
00353     this->m_client_jitter_samples   = 0;
00354     this->m_client_jitter_avg       = -1;
00355 
00356     this->m_waiting_var = new phConditionCounter();
00357     
00358     phTHIS_LOOSE_UNLOCK(locked);
00359 }
00360 
00361 /* ---------------------------------------------------------------------- */
00362 phLiveObject::~phLiveObject( )
00363 {
00364     phFUNCTION("phLiveObject::~phLiveObject")
00365     int locked      = 0;
00366     int cm_locked   = 0;
00367   
00368     /* Source stuff: releases all clients, 
00369      *  sets m_cookie_count to 0, head and tail pointers to NULL */
00370     this->release_clients();
00371 
00372     phTHIS_LOOSE_LOCK(locked);
00373  
00374 #if 0
00375     /* OS should signal any waiting threads when lock is finally
00376      * destroyed */
00377     /* VDK won't signal the thread when this is destroyed */
00378     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00379 #endif
00380     
00381     /* Client stuff */
00382     /* disconnect if still connected */
00383     if (this->m_connected) this->disconnect();
00384 
00385     phDelete(this->m_waiting_var);
00386 }
00387 
00388 /* ---------------------------------------------------------------------- */
00389 int phLiveObject::release_clients()
00390 {
00391     phFUNCTION("phLiveObject::release_clients")
00392     int cm_locked = 0;
00393 
00394     phLiveCookie    *cookie         = NULL;
00395     phLiveObject    *owner          = NULL;
00396     int             owner_locked        = 0;
00397     int             owner_update_locked = 0;
00398    
00399     phMUTEX_LOCK(this->m_cookie_mutex,cm_locked);
00400     
00401     cookie = this->m_cookie_head;
00402     while (cookie != NULL)
00403     {
00404         /* Lock the owner of the cookie */
00405         phMUTEX_LOCK((*(cookie->getOwner())),owner_locked);
00406         owner = cookie->getOwner();
00407         /* Lock the updateLock mutex of the owner so it can't update */
00408         phMUTEX_LOCK(owner->m_updateLock,owner_update_locked);
00409 
00410         /* NULLify the source object of the owner */
00411         owner->setSourceObject(NULL);
00412         /* Set the key to an invalid key value: 0 */
00413         cookie->setKey(0);
00414         /* TODO: postToWaiting once postToWaiting is fixed */
00415         cookie->postCookie();
00416         /* Get the next cookie in the list */
00417         cookie = cookie->getNext();
00418         
00419         /* Release the updateLock */
00420         phMUTEX_UNLOCK(owner->m_updateLock,owner_update_locked);
00421         /* Release the object lock of the owner */
00422         phMUTEX_UNLOCK((*owner),owner_locked);
00423     
00424         this->m_cookie_count--;
00425     }
00426 
00427     this->m_cookie_head = this->m_cookie_tail = NULL;
00428 
00429     phMUTEX_UNLOCK(this->m_cookie_mutex,cm_locked);
00430     
00431     return phSUCCESS;
00432 error:
00433     phMUTEX_ERROR_UNLOCK(owner->m_updateLock,owner_locked);
00434     phMUTEX_ERROR_UNLOCK((*owner),owner_locked);
00435     phMUTEX_ERROR_UNLOCK(this->m_cookie_mutex,cm_locked);
00436     
00437     return phFAIL;
00438 }
00439 
00440 /* ---------------------------------------------------------------------- */
00441 void phLiveObject::disableSwap(int disable)
00442 {
00443     phFUNCTION("phLiveObject::disableSwap")
00444     int locked      = 0;
00445     int cm_locked   = 0;
00446 
00447     phTHIS_LOOSE_LOCK(locked);
00448     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00449    
00450     this->m_swap_disabled = disable;
00451 
00452     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
00453     phTHIS_LOOSE_UNLOCK(locked);
00454 }
00455 
00456 /* ---------------------------------------------------------------------- */
00457 int phLiveObject::isSwapDisabled()
00458 {
00459     return this->m_swap_disabled;
00460 }
00461 /* ---------------------------------------------------------------------- */
00462 int phLiveObject::isSwapEnabled()
00463 {
00464     return (this->m_swap_disabled ? 0 : 1 );
00465 }
00466 /* ---------------------------------------------------------------------- */
00467 void phLiveObject::enableSwap(int enable)
00468 {
00469     phFUNCTION("phLiveObject::enableSwap")
00470     int locked      = 0;
00471     int cm_locked   = 0;
00472 
00473     phTHIS_LOOSE_LOCK(locked);
00474     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00475 
00476     this->m_swap_disabled = (enable == 1) ? 0/*disable:off*/: 1/*on*/;
00477 
00478     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
00479     phTHIS_LOOSE_UNLOCK(locked);
00480 }
00481 
00482 /* ---------------------------------------------------------------------- */
00483 void phLiveObject::disableNotify(int disable)
00484 {
00485     phFUNCTION("phLiveObject::disableNotify")
00486     int locked      = 0;
00487     int cm_locked   = 0;
00488 
00489     phTHIS_LOOSE_LOCK(locked);
00490     /* m_notify_disabled is used by methods that lock with only
00491      * the following lock. Make sure to lock it too; this ensures
00492      * they wait for the value to be updated */
00493     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00494    
00495     this->m_notify_disabled = disable;
00496 
00497     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
00498     phTHIS_LOOSE_UNLOCK(locked);
00499 }
00500 
00501 /* ---------------------------------------------------------------------- */
00502 int phLiveObject::isNotifyDisabled()
00503 {
00504     return this->m_notify_disabled;
00505 }
00506 
00507 /* ---------------------------------------------------------------------- */
00508 int phLiveObject::isNotifyEnabled()
00509 {
00510     return (this->m_notify_disabled ? 0 : 1 );
00511 }
00512 
00513 /* ---------------------------------------------------------------------- */
00514 void phLiveObject::enableNotify(int enable)
00515 {
00516     phFUNCTION("phLiveObject::enableNotify")
00517     int locked      = 0;
00518     int cm_locked   = 0;
00519 
00520     phTHIS_LOOSE_LOCK(locked);
00521     /* m_notify_disabled is used by methods that lock with only
00522      * the following lock. Make sure to lock it too; this ensures
00523      * they wait for the value to be updated */
00524     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
00525 
00526     this->m_notify_disabled = (enable == 1) ? 0/*disable:off*/: 1/*on*/;
00527 
00528     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
00529     phTHIS_LOOSE_UNLOCK(locked);
00530 }
00531 
00532 /* ---------------------------------------------------------------------- */
00533 /* private function to redo the default flags if they need live altering */
00534 /* ---------------------------------------------------------------------- */
00535 uint32_t phLiveObject::factorFlags(uint32_t newflags)
00536 {
00537     uint32_t localflags = this->m_flags;
00538     if (newflags)
00539     {
00540         /* Setup the flags to use the defaults taking into
00541          * account the flags passed to this funciton */
00542         /* 1.) turn off default WAIT and use NOWAIT */
00543         if ((newflags & phLiveObjectNOWAIT) &&
00544             (localflags & phLiveObjectWAIT))
00545         {
00546             localflags &= (~phLiveObjectWAIT);
00547             localflags |= phLiveObjectNOWAIT;
00548         }
00549         /* 2.) Turn off default NOWAIT and use WAIT */
00550         /* if both WAIT and NOWAIT are supplied, then WAIT
00551          * will be used; come ON!! pick one and stop trying
00552          * to break my code */
00553         if ((newflags & phLiveObjectWAIT) &&
00554             (localflags & phLiveObjectNOWAIT))
00555         {
00556             localflags &= (~phLiveObjectNOWAIT);
00557             localflags |= phLiveObjectWAIT;
00558         }
00559         /* 3.) Turn off default COPY and use SWAP */
00560         if ((newflags & phLiveObjectSWAP) &&
00561             (localflags & phLiveObjectCOPY))
00562         {
00563             localflags &= (~phLiveObjectCOPY);
00564             localflags |= phLiveObjectSWAP;
00565         }
00566         /* 4.) turn of default SWAP and use COPY */
00567         /* if both SWAP and COPY are supplied, then COPY
00568          * will be used; who would do that anyway? geez */
00569         if ((newflags & phLiveObjectCOPY) &&
00570             (localflags & phLiveObjectSWAP))
00571         {
00572             localflags &= (~phLiveObjectSWAP);
00573             localflags |= phLiveObjectCOPY;
00574         }
00575 
00576         /* 5.) make sure a TRANSFER flag is specified */
00577         if (!(localflags & phLiveObjectTRANSFERMASK))
00578         {
00579             localflags |= phLiveObjectCOPY;
00580         }
00581         /* 6.) Make sure a WAIT flag is specified */
00582         if (!(localflags & phLiveObjectWAITMASK))
00583         {
00584             localflags |= phLiveObjectWAIT;
00585         }
00586         if (newflags & phLiveObjectFORCE)
00587         {
00588             localflags |= phLiveObjectFORCE;
00589         }
00590     }
00591     return localflags;
00592 }
00593 
00594 /* ---------------------------------------------------------------------- */
00595 int phLiveObject::setFlags( uint32_t flags )
00596 {
00597     phFUNCTION("phLiveObject::setFlags")
00598     int locked = 0;
00599 
00600     phTHIS_LOOSE_LOCK(locked);
00601     
00602     if (flags)
00603     {
00604         this->m_flags = flags & (phLiveObjectFLAGMASK);
00605         
00606         /* 1.) make sure a TRANSFER flag is specified */
00607         if (!(this->m_flags & phLiveObjectTRANSFERMASK))
00608         {
00609             this->m_flags |= phLiveObjectCOPY;
00610         }
00611         /* 2.) Make sure a WAIT flag is specified */
00612         if (!(this->m_flags & phLiveObjectWAITMASK))
00613         {
00614             this->m_flags |= phLiveObjectWAIT;
00615         }
00616     }    
00617     
00618     phTHIS_LOOSE_UNLOCK(locked);
00619 
00620     return phSUCCESS;
00621 }
00622 
00623 /* ---------------------------------------------------------------------- */
00624 uint32_t phLiveObject::getFlags() 
00625 {
00626     return this->m_flags; 
00627 }
00628 
00629 /* ---------------------------------------------------------------------- */
00630 /* LIVE CLIENT INTERFACE */
00631 /* ---------------------------------------------------------------------- */
00632 
00633 /* ---------------------------------------------------------------------- */
00634 /* If this is connected to something already, it will disconnect */
00635 /* ---------------------------------------------------------------------- */
00636 int phLiveObject::connect(phLiveObject *object,
00637                           uint32_t flags /* phLiveObjectNOFLAG */ )
00638 {
00639     phFUNCTION("phLiveObject::connect")
00640     int locked          = 0;
00641     int updateLocked    = 0;
00642     
00643     /*phCHECK_NULLPTR(object,NULL,"object == NULL");*/
00644     
00645     phTHIS_LOCK(locked);
00646     phMUTEX_LOCK(this->m_updateLock,updateLocked);
00647     
00648     if (this->m_connected) 
00649     {
00650         rc = this->disconnect();
00651         phPRINT_RC(rc,NULL,"this->disconnect() failed.");
00652     }
00653     
00654     this->m_source_object = object;
00655     if (flags) this->setFlags(flags);
00656     
00657     if (this->m_source_object != NULL)
00658     {
00659         DEBUG_PRINT("Established live source connection.\n");
00660         /* TODO: supply a default SYNC or ASYNC flag */
00661         rc = this->m_source_object->source_connect(this,&this->m_cookie);
00662         phCHECK_RC(rc,NULL,"this->m_source_object->source_connect() failed.");
00663     
00664         this->m_connected = 1;
00665     }
00666 
00667     phMUTEX_UNLOCK(this->m_updateLock,updateLocked);
00668     phTHIS_UNLOCK(locked);
00669 
00670     return phSUCCESS;
00671 error:
00672     phMUTEX_ERROR_UNLOCK(this->m_updateLock,updateLocked);
00673     phTHIS_ERROR_UNLOCK(locked);
00674 
00675     return phFAIL;
00676 }
00677 /* ---------------------------------------------------------------------- */
00678 int phLiveObject::disconnect()
00679 {
00680     phFUNCTION("phLiveObject::disconnect")
00681     int locked          = 0;
00682     int updateLocked    = 0;
00683     
00684     phTHIS_LOCK(locked);
00685     phMUTEX_LOCK(this->m_updateLock,updateLocked);
00686    
00687     if ((this->m_connected == 1) && (this->m_source_object != NULL))
00688     {
00689         DEBUG_PRINT("Disconnecting from live source.\n");
00690         rc = this->m_source_object->source_disconnect(&this->m_cookie);
00691         phPRINT_RC(rc,NULL,"this->m_source_object->disconnect() failed.");
00692     }
00693     else if ((this->m_cookie != NULL) && 
00694              (this->m_cookie->getKey() == 0))
00695     {
00696         phDelete(this->m_cookie);
00697         this->m_cookie = NULL;
00698     }
00699     
00700     this->m_connected = 0;
00701     this->m_source_object = NULL;
00702     
00703 error:
00704     phMUTEX_ERROR_UNLOCK(this->m_updateLock,updateLocked);
00705     phTHIS_ERROR_UNLOCK(locked);
00706     
00707     return phSUCCESS;
00708 }
00709 
00710 /* ---------------------------------------------------------------------- */
00711 /* flag == 1: non-blocking update */
00712 /* Called on a client object */
00713 /* Returns 1 if unblocked or in non-blocking mode and got no data */
00714 /* ---------------------------------------------------------------------- */
00715 int phLiveObject::update(uint32_t flags /* phLiveObjectNOFLAG */ )
00716 {
00717     phFUNCTION("phLiveObject::update")
00718     int ret_rc          = phSUCCESS;
00719     int updateLocked    = 0;
00720 
00721     /* !!! Don't call this method from two separate threads.
00722      * 
00723      * It doesn't make sense because that case would
00724      * be if there were two threads trying to copy data from
00725      * some source into some destination object.
00726      */
00727         
00728     /* make sure the connection isn't severed by the client
00729      * during an update call */
00730     phMUTEX_LOCK(this->m_updateLock,updateLocked);
00731     
00732     if ((this->m_source_object  != NULL) && 
00733         (this->m_cookie         != NULL))
00734     {
00735         rc = this->m_source_object->source_update(this,
00736                                                   this->m_cookie,
00737                                                   this->factorFlags(flags) );
00738         if (rc >= phLiveObjectNOUPDATE) ret_rc = phLiveObjectNOUPDATE;
00739         if (rc < 0) ret_rc = phFAIL;
00740         phPRINT_RC(rc,NULL,"waitForUpdate returned error");
00741     }
00742     else
00743     {
00744         ret_rc = phLiveObjectNOUPDATE;
00745     }
00746     
00747 error:
00748     phMUTEX_ERROR_UNLOCK(this->m_updateLock,updateLocked);
00749     
00750     return ret_rc;
00751 }
00752 
00753 /* ------------------------------------------------------------------------- *
00754  * wakeup_self: Allow other's that aren't part of the thread to wakeup the
00755  * object blocked on an update call. It performs the wakeup on an object by
00756  * allowing the releasing of conditions that block itself
00757  * ------------------------------------------------------------------------- */
00758 int phLiveObject::wakeup_self()
00759 {
00760     phFUNCTION("phLiveObject::wakeup")
00761     int locked = 0;
00762     
00763     phTHIS_LOCK(locked);
00764 
00765     if (this->m_cookie != NULL)
00766     {
00767         rc = this->m_cookie->wakeup();
00768         phPRINT_RC(rc,NULL,"this->m_cookie->wakeup()");
00769 
00770         /* TODO: postToWaiting once postToWaiting is fixed */
00771         rc = this->m_cookie->postCookie();
00772         phCHECK_RC(rc,NULL,"this->m_cookie->postCookie() failed");
00773     }
00774 
00775     phTHIS_UNLOCK(locked);
00776 
00777     return phSUCCESS;
00778 error:
00779     phTHIS_ERROR_UNLOCK(locked);
00780 
00781     return phFAIL;
00782 }
00783 
00784 /* ---------------------------------------------------------------------- */
00785 int phLiveObject::wakeup_clients()
00786 {
00787     phFUNCTION("phLiveObject::wakeup_clients")
00788     
00789     rc = this->notify(1);
00790     phPRINT_RC(rc,NULL,"this->notify(1)");
00791     
00792     return rc;
00793 }
00794 
00795 /* ---------------------------------------------------------------------- */
00796 int phLiveObject::isConnected()
00797 {
00798     phFUNCTION("phLiveObject::isConnected")
00799     int ret_rc = phSUCCESS;
00800     int locked = 0;
00801 
00802     phTHIS_LOOSE_LOCK(locked);
00803     
00804     /* 0: not connected; 1: connected */
00805     if (this->m_cookie != NULL)
00806     {
00807         ret_rc = ((this->m_cookie->getKey() != 0) ? 1 : 0);
00808     }
00809     /* There is no cookie, therefore there is no connection
00810      * and no possible way of disconnecting */
00811     else
00812     {
00813         ret_rc = 0;
00814         //this->m_connected = 0;
00815     }
00816     
00817     /* if not really connected and still connected ... */
00818     if ((ret_rc == 0) && (this->m_connected == 1))
00819     {
00820         this->disconnect();
00821     }
00822     
00823     phTHIS_LOOSE_UNLOCK(locked);
00824 
00825     return ret_rc;
00826 }
00827 
00828 /* ---------------------------------------------------------------------- */
00829 /* LIVE SOURCE INTERFACE */
00830 /* ---------------------------------------------------------------------- */
00831 
00832 /* ---------------------------------------------------------------------- */
00833 /* Called by client object on source object */
00834 /* ---------------------------------------------------------------------- */
00835 int phLiveObject::source_connect(phLiveObject *owner,
00836                                  phLiveCookie **cookie)
00837 {
00838     phFUNCTION("phLiveObject::source_connect")
00839     int             locked      = 0;
00840     int             c_locked    = 0;
00841     phLiveCookie    *insertAfter= NULL;
00842     
00843     /* THe cookies are allocated here and returned through a parameter */
00844     (*cookie) = new phLiveCookie();
00845     phCHECK_NULLPTR(*cookie,"new","new failed to allocate cookie");
00846 
00847     phTHIS_LOCK(locked);
00848     
00849     /* Set the cookie's key to the key of the source object */
00850     rc = (*cookie)->setKey(this->m_source_object_key);
00851     phPRINT_RC(rc,NULL,"(*cookie)->setKey failed");
00852     
00853     /* m_source_object_key was retrieved, this lock isn't needed any longer */
00854     phTHIS_UNLOCK(locked);
00855     
00856     /* Set the owner of the cookie so that if the source_object/this is being
00857      * freed, the sourcE_object/this can reset certain parameters */
00858     rc = (*cookie)->setOwner(owner);
00859     phPRINT_RC(rc,NULL,"(*cookie)->setOwner failed");
00860     
00861     phMUTEX_LOCK(this->m_cookie_mutex,c_locked);
00862     
00863     /* increment the number of cookies that are providing connections
00864      * to the source_object/this */
00865     this->m_cookie_count++;
00866 
00867     /* Empty list */
00868     if (this->m_cookie_head == NULL)
00869     {
00870         this->m_cookie_tail = this->m_cookie_head = (*cookie);
00871     }
00872     /* inset the cookie at the end of the list */
00873     else
00874     {
00875         insertAfter = this->m_cookie_tail;
00876         
00877         (*cookie)->setPrev(insertAfter);
00878         insertAfter->setNext((*cookie));
00879 
00880         /* Set the tail to the new cookie */
00881         this->m_cookie_tail = (*cookie);
00882     }
00883     
00884     phMUTEX_UNLOCK(this->m_cookie_mutex,c_locked);
00885     
00886     return phSUCCESS;
00887     
00888 error:
00889     if (*cookie != NULL)
00890     {
00891         phFree(*cookie);
00892     }
00893     phTHIS_ERROR_UNLOCK(locked);
00894     phMUTEX_ERROR_UNLOCK(this->m_cookie_mutex,c_locked);
00895 
00896     return phFAIL;
00897 }
00898 
00899 /* ---------------------------------------------------------------------- */
00900 /* Called by the client object on the source object */
00901 /* ---------------------------------------------------------------------- */
00902 int phLiveObject::source_disconnect(phLiveCookie **cookie)
00903 {
00904     phFUNCTION("phLiveObject::source_disconnect")
00905     int locked      = 0;
00906     int cm_locked   = 0;
00907     
00908     phLiveCookie *prev = NULL;
00909     phLiveCookie *next = NULL;
00910     
00911     if (this != NULL)
00912     {
00913         phTHIS_LOCK(locked);
00914         phMUTEX_LOCK(this->m_cookie_mutex,cm_locked);
00915     }
00916     
00917     phCHECK_NULLPTR(cookie,NULL,  "Invalid argument: cookie == NULL" );
00918     phCHECK_NULLPTR(*cookie,NULL, "Invalid argument: *cookie == NULL");
00919 
00920     prev = (*cookie)->getPrev();
00921     next = (*cookie)->getNext();
00922     
00923     if (this != NULL)
00924     {
00925         /* If the cookie list head is equal to cookie then point it to
00926          * the next cookie pointed to by (*cookie); whether it's NULL
00927          * or not */
00928         if (this->m_cookie_head == (*cookie)) 
00929             this->m_cookie_head = next;
00930         /* If the last cookie address equals the cookie being removed,
00931          * then set the last cookie to point to the previous cookie
00932          * that is pointed to by (*cookie); whether it's valid or NULL */
00933         if (this->m_cookie_tail == (*cookie))
00934             this->m_cookie_tail = prev;
00935     }
00936 
00937     if (next != NULL) next->setPrev( prev );
00938     if (prev != NULL) prev->setNext( next );
00939    
00940     phDelete(*cookie);
00941     cookie = NULL;
00942     
00943     this->m_cookie_count--;
00944 
00945     if (this != NULL)
00946     {
00947         phMUTEX_UNLOCK(this->m_cookie_mutex,cm_locked);
00948         phTHIS_UNLOCK(locked);
00949     }
00950     return phSUCCESS;
00951     
00952 error:
00953     if (this != NULL)
00954     {
00955         phMUTEX_ERROR_UNLOCK(this->m_cookie_mutex,cm_locked);
00956         phTHIS_ERROR_UNLOCK(locked);
00957     }
00958     return phFAIL;
00959 }
00960 
00961 /* ---------------------------------------------------------------------- */
00962 /* Called by client object on source object */
00963 /* returns 0: success
00964  *         1: no semaphore */
00965 /* ---------------------------------------------------------------------- */
00966 /* ??? */
00967 
00968 /* ---------------------------------------------------------------------- */
00969 int phLiveObject::resetJitter()
00970 {
00971     phFUNCTION("phLiveObject::resetJitter")
00972     int         notify_locked  = 0;
00973     int         client_locked  = 0;
00974  
00975     phMUTEX_LOCK(this->m_notify_jitter_lock,notify_locked);
00976     phRWLOCK_WRITELOCK(this->m_client_jitter_rwlock,client_locked);
00977     
00978     this->m_notify_jitter_us = -1;
00979     this->m_notify_jitter_avg = -1;
00980     this->m_client_jitter_us = -1;
00981     this->m_client_jitter_avg = -1;
00982         
00983     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,client_locked);
00984     phMUTEX_UNLOCK(this->m_notify_jitter_lock,notify_locked);
00985 
00986     return phSUCCESS;
00987 error:
00988     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,client_locked);
00989     phMUTEX_ERROR_UNLOCK(this->m_notify_jitter_lock,notify_locked);
00990     
00991     return phFAIL;
00992 }
00993 
00994 /* ---------------------------------------------------------------------- */
00995 int phLiveObject::resetNotifyJitter()
00996 {
00997     phFUNCTION("phLiveObject::resetNotifyJitter")
00998     int         locked  = 0;
00999  
01000     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01001     
01002     this->m_notify_jitter_us = -1;
01003     
01004     phMUTEX_UNLOCK_RET(this->m_notify_jitter_lock,locked,phSUCCESS,phFAIL);
01005 }
01006 
01007 /* ---------------------------------------------------------------------- */
01008 int phLiveObject::setNotifyJitter( int32_t jitter )
01009 {
01010     phFUNCTION("phLiveObject::setNotifyJitter")
01011     int         locked  = 0;
01012     int         gotit   = 0;
01013  
01014     phMUTEX_LOOSE_TRYLOCK(this->m_notify_jitter_lock,locked,gotit);
01015     
01016     if (gotit)
01017     {
01018         double      avg     = 0.0;
01019         double      major   = 0.0;
01020         double      minor   = 0.0;
01021         double      samples = 0.0;
01022         
01023         this->m_notify_jitter_us = jitter;
01024 
01025         /* moving average */
01026         if (this->m_notify_jitter_samples > 0)
01027         {
01028             avg = this->m_notify_jitter_avg;
01029             samples = this->m_notify_jitter_samples;
01030             
01031             major = (samples - 1.0) / samples;
01032             minor = 1.0 / samples;
01033             
01034             avg = (avg * major) + (jitter * minor);
01035             
01036             this->m_notify_jitter_avg = (int32_t)avg;
01037         }
01038         else
01039         {
01040             this->m_notify_jitter_avg = jitter;
01041         }
01042         phMUTEX_LOOSE_UNLOCK(this->m_notify_jitter_lock,locked);
01043     }
01044     
01045     return phSUCCESS;
01046 }
01047 
01048 /* ---------------------------------------------------------------------- */
01049 /* Returns the notify jitter in microseconds */
01050 /* ---------------------------------------------------------------------- */
01051 int32_t phLiveObject::getNotifyJitter()
01052 {
01053     phFUNCTION("phLiveObject::getNotifyJitter")
01054     int         locked  = 0;
01055     int32_t     retval  = 0;
01056 
01057     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01058     
01059     retval = this->m_notify_jitter_us;
01060 
01061     phMUTEX_UNLOCK_RET(this->m_notify_jitter_lock,locked,retval,phFAIL);
01062 }
01063 
01064 /* ---------------------------------------------------------------------- */
01065 int phLiveObject::setNotifyJitterAvg( int32_t avg )
01066 {
01067     phFUNCTION("phLiveObject::setNotifyJitterAvg")
01068     int         locked  = 0;
01069  
01070     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01071     
01072     this->m_notify_jitter_us = avg;
01073     
01074     phMUTEX_UNLOCK(this->m_notify_jitter_lock,locked);
01075 
01076     return phSUCCESS;
01077 error:
01078     phMUTEX_ERROR_UNLOCK(this->m_notify_jitter_lock,locked);
01079     
01080     return phFAIL;
01081 }
01082 
01083 /* ---------------------------------------------------------------------- */
01084 int32_t phLiveObject::getNotifyJitterAvg()
01085 {
01086     phFUNCTION("phLiveObject::getNotifyJitterAvg")
01087     int         locked  = 0;
01088     int32_t     retval  = 0;
01089 
01090     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01091     
01092     retval = this->m_notify_jitter_avg;
01093 
01094     phMUTEX_UNLOCK(this->m_notify_jitter_lock,locked);
01095 
01096     return retval;
01097 error:
01098     phMUTEX_ERROR_UNLOCK(this->m_notify_jitter_lock,locked);
01099     
01100     return phFAIL;
01101 }
01102 
01103 /* ---------------------------------------------------------------------- */
01104 /* Set the number of samples for the moving average of the notify jitter  */
01105 int phLiveObject::setNotifyJitterAvgSamples( int32_t samples )
01106 {
01107     phFUNCTION("phLiveObject::setNotifyJitterAvgSamples")
01108     int         locked  = 0;
01109  
01110     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01111     
01112     this->m_notify_jitter_samples = samples;
01113     
01114     phMUTEX_UNLOCK(this->m_notify_jitter_lock,locked);
01115 
01116     return phSUCCESS;
01117 error:
01118     phMUTEX_ERROR_UNLOCK(this->m_notify_jitter_lock,locked);
01119     
01120     return phFAIL;
01121 }
01122 
01123 /* ---------------------------------------------------------------------- */
01124 /* Returns the last notify jitter in microseconds */
01125 /* ---------------------------------------------------------------------- */
01126 int32_t phLiveObject::getNotifyJitterAvgSamples()
01127 {
01128     phFUNCTION("phLiveObject::getNotifyJitterAvgSamples")
01129     int         locked  = 0;
01130     int32_t     retval  = 0;
01131 
01132     phMUTEX_LOCK(this->m_notify_jitter_lock,locked);
01133     
01134     retval = this->m_notify_jitter_samples;
01135 
01136     phMUTEX_UNLOCK(this->m_notify_jitter_lock,locked);
01137 
01138     return retval;
01139 error:
01140     phMUTEX_ERROR_UNLOCK(this->m_notify_jitter_lock,locked);
01141     
01142     return 0;
01143 }
01144 
01145 /* ---------------------------------------------------------------------- */
01146 /* Resets only the client jitter values */
01147 /* ---------------------------------------------------------------------- */
01148 int phLiveObject::resetClientJitter()
01149 {
01150     phFUNCTION("phLiveObject::resetClientJitter")
01151     int         locked  = 0;
01152  
01153     phRWLOCK_WRITELOCK(this->m_client_jitter_rwlock,locked);
01154     
01155     this->m_client_jitter_us = -1;
01156     this->m_client_jitter_avg = -1;
01157         
01158     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01159 
01160     return phSUCCESS;
01161 error:
01162     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01163     
01164     return phFAIL;
01165 }
01166 
01167 /* ---------------------------------------------------------------------- */
01168 /* Set the client jitter in microseconds and factor it into the moving 
01169  * average for the last N samples of minimum client jitter value*/
01170 /* ---------------------------------------------------------------------- */
01171 int phLiveObject::setClientJitter( int32_t jitter )
01172 {
01173     phFUNCTION("phLiveObject::setClientJitter")
01174     int         locked  = 0;
01175     double      avg     = 0.0;
01176     double      major   = 0.0;
01177     double      minor   = 0.0;
01178     double      samples = 0.0;
01179  
01180     phRWLOCK_WRITELOCK(this->m_client_jitter_rwlock,locked);
01181     
01182     this->m_client_jitter_us = jitter;
01183     
01184     /* moving average */
01185     if (this->m_client_jitter_samples > 0)
01186     {
01187         avg = this->m_client_jitter_avg;
01188         samples = this->m_client_jitter_samples;
01189         
01190         major = (samples - 1.0) / samples;
01191         minor = 1.0 / samples;
01192         
01193         avg = (avg * major) + (jitter * minor);
01194         
01195         this->m_client_jitter_avg = (int32_t)avg;
01196     }
01197     else
01198     {
01199         this->m_client_jitter_avg = jitter;
01200     }
01201     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01202 
01203     return phSUCCESS;
01204 error:
01205     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01206     
01207     return phFAIL;
01208 }
01209 
01210 /* ---------------------------------------------------------------------- */
01211 /* Returns the minimum client jitter in microseconds */
01212 /* ---------------------------------------------------------------------- */
01213 int32_t phLiveObject::getClientJitter()
01214 {
01215     phFUNCTION("phLiveObject::getClientJitter")
01216     int         locked  = 0;
01217     int32_t     retval  = 0;
01218 
01219     phRWLOCK_READLOCK(this->m_client_jitter_rwlock,locked);
01220     
01221     retval = this->m_client_jitter_us;
01222 
01223     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01224 
01225     return retval;
01226 error:
01227     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01228     
01229     return phFAIL;
01230 }
01231 
01232 /* ---------------------------------------------------------------------- */
01233 /* Set the client jitter moving average value */
01234 /* ---------------------------------------------------------------------- */
01235 int phLiveObject::setClientJitterAvg( int32_t avg )
01236 {
01237     phFUNCTION("phLiveObject::setClientJitterAvg")
01238     int         locked  = 0;
01239  
01240     phRWLOCK_WRITELOCK(this->m_client_jitter_rwlock,locked);
01241     
01242     this->m_client_jitter_us = avg;
01243     
01244     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01245 
01246     return phSUCCESS;
01247 error:
01248     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01249     
01250     return phFAIL;
01251 }
01252 
01253 /* ---------------------------------------------------------------------- */
01254 /* Returns the minimum client jitter in microseconds */
01255 /* ---------------------------------------------------------------------- */
01256 int32_t phLiveObject::getClientJitterAvg()
01257 {
01258     phFUNCTION("phLiveObject::getClientJitterAvg")
01259     int         locked  = 0;
01260     int32_t     retval  = 0;
01261 
01262     phRWLOCK_READLOCK(this->m_client_jitter_rwlock,locked);
01263     
01264     retval = this->m_client_jitter_avg;
01265 
01266     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01267 
01268     return retval;
01269 error:
01270     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01271     
01272     return phFAIL;
01273 }
01274 
01275 /* ---------------------------------------------------------------------- */
01276 /* Set the number of samples for the moving average of the client jitter  */
01277 /* ---------------------------------------------------------------------- */
01278 int phLiveObject::setClientJitterAvgSamples( int32_t samples )
01279 {
01280     phFUNCTION("phLiveObject::setClientJitterAvgSamples")
01281     int         locked  = 0;
01282  
01283     phRWLOCK_WRITELOCK(this->m_client_jitter_rwlock,locked);
01284     
01285     this->m_client_jitter_samples = samples;
01286     
01287     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01288 
01289     return phSUCCESS;
01290 error:
01291     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01292     
01293     return phFAIL;
01294 }
01295 
01296 /* ---------------------------------------------------------------------- */
01297 /* Returns the minimum average client jitter in microseconds */
01298 /* ---------------------------------------------------------------------- */
01299 int32_t phLiveObject::getClientJitterAvgSamples()
01300 {
01301     phFUNCTION("phLiveObject::getClientJitterAvgSamples")
01302     int         locked  = 0;
01303     int32_t     retval  = 0;
01304 
01305     phRWLOCK_READLOCK(this->m_client_jitter_rwlock,locked);
01306     
01307     retval = this->m_client_jitter_samples;
01308 
01309     phRWLOCK_UNLOCK(this->m_client_jitter_rwlock,locked);
01310 
01311     return retval;
01312 error:
01313     phRWLOCK_UNLOCK_ERROR(this->m_client_jitter_rwlock,locked);
01314     
01315     return 0;
01316 }
01317 
01318 /* ---------------------------------------------------------------------- */
01319 phConditionCounter *phLiveObject::getWaitingCounter()
01320 {
01321     return this->m_waiting_var;  
01322 }
01323 
01324 /* ---------------------------------------------------------------------- */
01325 /* - Called by source object on source object.
01326  * - Source object is locked to prevent modification of the cookie list
01327  *      while posting cookie. */
01328 /* ---------------------------------------------------------------------- */
01329 int phLiveObject::notify(int wakeup)
01330 {
01331     phFUNCTION("phLiveObject::notify")
01332     /*char tmp[255];*/
01333     int             i               = 0;
01334     int             cm_locked       = 0;
01335     phLiveCookie    *cookie         = NULL;
01336 
01337     /* need to lock because of m_cookie_count/this->m_cookie_head */
01338     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
01339 
01340     if ((this->m_notify_disabled == 0) || (wakeup))
01341     {
01342         int32_t        min_client_jitter   = INT32_MAX;
01343         int32_t        jitter              = 0;
01344     
01345         /* Get the end time since the last start call */
01346         this->m_notify_jitter.stop();
01347         
01348         #if 0
01349         sprintf(tmp,"%p",this);
01350         this->m_notify_jitter.report(tmp);
01351         #endif
01352         rc = this->setNotifyJitter(this->m_notify_jitter.elapsed().getMicroseconds());
01353         phPRINT_RC(rc,NULL,"this->setNotifyJitter");
01354 
01355         /* Start the new notify interval time */
01356         this->m_notify_jitter.start();
01357 
01358         cookie = this->m_cookie_head;
01359         
01360         while(cookie != NULL)
01361         {
01362             /* TODO: */
01363             /* This should be 1, right? */
01364             /* Would post(1) make more since when every client
01365              * object has a cookie of their own? */
01366             /* Figure out the best way to do this,
01367              * Maybe the Cookie should be a phCondition
01368              * that every client sees and knows whether they
01369              * have received it already...
01370              * EventCounters? Hmmm, This is a crucial object
01371              * that needs some more thought even though
01372              * things work */
01373             if (wakeup)
01374             {
01375                 cookie->wakeup();
01376             }
01377            
01378             if (jitter > -1)
01379             {
01380                 jitter = cookie->getJitter();
01381                 if (jitter < min_client_jitter)
01382                 {
01383                     min_client_jitter = jitter;
01384                 }
01385             }        
01386             /* TODO: postToWaiting once postToWaiting is fixed */
01387             cookie->postCookie();
01388             cookie = cookie->getNext();
01389             i++;
01390         }
01391 
01392         if (min_client_jitter < INT32_MAX)
01393         {
01394             //phPROGRESS("%u\n",min_client_jitter);
01395             rc = this->setClientJitter(min_client_jitter);
01396             phPRINT_RC(rc,NULL,"setClientJitter(min_client_jitter)");
01397         }
01398         else
01399         {
01400             rc = this->resetClientJitter();
01401             phPRINT_RC(rc,NULL,"resetClientJitter()");
01402         }
01403     }
01404 
01405     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
01406     
01407     return phSUCCESS;
01408 }
01409 
01410 /* ---------------------------------------------------------------------- */
01411 /* - Called by client object on source object.
01412  * - Source object will only be locked if client got an update. 
01413  * - Client object will be[should be] locked during the copy. */
01414 /* ---------------------------------------------------------------------- */
01415 int phLiveObject::source_update( phObject       *object, 
01416                                  phLiveCookie   *cookie, 
01417                                  uint32_t       flags /*phLiveObjectNOFLAG*/)
01418 {
01419     phFUNCTION("phLiveObject::source_update")
01420 
01421     uint32_t    cookieflag      = 0;
01422     uint32_t    localflags      = 0;
01423     int         reenable_notify = 0;
01424     int         update_rc       = 0;
01425 
01426     /* locked is only needed for the 'error' case */
01427     /*
01428     uint32_t locked = 0;
01429     int dec_readers = 0;
01430     */
01431     
01432     /* Verify all pointers */
01433     phCHECK_NULLPTR(this,NULL,"this == NULL");
01434     phCHECK_NULLPTR(object,NULL,"object == NULL");
01435     phCHECK_NULLPTR(cookie,NULL,"cookie == NULL");
01436 
01437     DEBUG_PRINT("(this:%p)\n",this,(void*)phGetCurrentThreadId());
01438 #if 0
01439     /* lock "this" to try and keep it from being destroyed for now */
01440     phTHIS_LOCK(locked);
01441 #endif
01442 
01443     DEBUG_PRINT("(this:%p)\n",this,(void*)phGetCurrentThreadId());
01444 
01445     /* First make sure the cookie is valid */
01446     if (cookie->getKey() != this->m_source_object_key)
01447     {
01448         phCHECK_RC(-1,NULL, "Cookie key doesn't match object key."
01449                           "(Cookie key): %u != (Object key): %u",
01450                  cookie->getKey(), this->m_source_object_key);
01451     }
01452 #if 0
01453     /* Done with m_source_object_key */
01454     phTHIS_UNLOCK(locked);
01455 #endif
01456     localflags = this->factorFlags(flags);
01457     
01458     /* Convert the phLiveObject flags to phLiveCookie flags */
01459     if (localflags & phLiveObjectFORCE)
01460     {
01461         cookieflag |= phLiveCookieNOWAIT;
01462     }
01463     else if (localflags & phLiveObjectWAIT)
01464     {
01465         cookieflag |= phLiveCookieWAIT;
01466     }
01467     else if (localflags & phLiveObjectNOWAIT)
01468     {
01469         cookieflag |= phLiveCookieNOWAIT;
01470     }
01471 
01472     rc = this->m_waiting_var->increment();
01473     phPRINT_RC(rc,NULL,"this->m_waiting_var->increment()");
01474 
01475     /* Wait for a cookie, Mmmmm ...*/
01476     /* XXX: This would be the spot for a phCondition variable,
01477      * that checks for a variable's count (cookie_countLeft) that would be 
01478      * set to nClientsConnected. */
01479     rc = cookie->take(cookieflag);
01480     phCHECK_RC(rc,NULL,"cookie take failed.");
01481     
01482     DEBUG_PRINT("(this:%p)rc=%d\n",this,rc);
01483     
01484     rc = this->m_waiting_var->decrement();
01485     phPRINT_RC(rc,NULL,"this->m_waiting_var->increment()");
01486 
01487     /* if take failed and/or the cookie is no longer connected */
01488     if ((rc == phSemaphoreNOTAKE) || (cookie->getKey() == 0))
01489     { 
01490         /* Any looping process will take 1 to mean there
01491          * wasn't an update made and hopefully will be checking
01492          * to make sure the client object is still connected.
01493          * It won't call here again if the client object
01494          * was disconnected (determined by getKey() )*/
01495         if (!(localflags & phLiveObjectFORCE)) 
01496             return phLiveObjectNOUPDATE;
01497     }
01498 #if 0
01499     /* unlocked interval #1 */
01500     /* Object not locked by copy/swap seeking object */
01501     /* The object will be locked appropriately in swap/copy */
01502     /* This interval is the same as the interval below and
01503      * not much can be done about it except more synchronization. */
01504     
01505     /* lock here and get a copy, IMMEDIATELY! */
01506     phTHIS_LOCK(locked);
01507     
01508     /* Verify the objects are the same */
01509     /* XXX: Possibly verify this before hand. Doing this constantly
01510      * may incur a performance hit */
01511         
01512     this->m_reading_clients++;
01513     dec_readers = 1;
01514     DEBUG_PRINT("readers:%u\n",this->m_reading_clients);
01515     
01516     /* unlock here, copy/swap will lock again */
01517     phTHIS_UNLOCK(locked);
01518         
01519     /* This interval is the same as the interval above */
01520 #endif
01521 
01522     if (localflags & phLiveObjectSWAP)
01523     {
01524         rc = this->writeLock();
01525         phPRINT_RC(rc,NULL,"this->writeLock()");
01526       
01527         /* We don't want to signal 'this' again when we swap
01528          * the data out of 'object'. In the case both
01529          * objects may be signaled, disable 'this' object */
01530         if (this->isNotifyEnabled())
01531         {
01532             this->disableNotify();
01533             reenable_notify = 1;
01534         }
01535         
01536         DEBUG_PRINT("(this:%p)swap-source:%p object:%p\n",
01537                 this,this,object);
01538         update_rc = this->swap(object);
01539         if ((update_rc < 0) && (!(localflags & phLiveObjectFORCE)))
01540         {
01541             phPRINT_RC(update_rc,NULL,"swap()");
01542         }
01543         
01544         if (reenable_notify)                
01545         {
01546             this->enableNotify();
01547             reenable_notify = 0;
01548         }
01549         
01550         rc = this->rwUnlock();
01551         phPRINT_RC(rc,NULL,"this->rwUnlock()");
01552     }
01553     else
01554     {
01555         rc = this->readLock();
01556         phPRINT_RC(rc,NULL,"this->readLock()");
01557         
01558         DEBUG_PRINT("(this:%p)copy-source:%p object:%p\n",
01559                 this,this,object);
01560         update_rc = this->copy(object);
01561         if ((update_rc < 0) && (!(localflags & phLiveObjectFORCE)))
01562         {
01563             phPRINT_RC(update_rc,NULL,"copy()");
01564         }
01565 
01566         rc = this->rwUnlock();
01567         phPRINT_RC(rc,NULL,"this->rwUnlock()");
01568     }
01569 
01570     /* If we didn't successfully copy/swap data and the FORCE flag was 
01571      * supplied, then remove the FORCE flag this time and re-try. */
01572     if ((update_rc < phSUCCESS) &&
01573         (localflags & phLiveObjectFORCE))
01574     {
01575         return this->source_update(object,
01576                 cookie,
01577                 flags & (~phLiveObjectFORCE));
01578     }
01579     
01580 #if 0
01581     phTHIS_LOCK(locked);
01582     
01583     if (dec_readers)
01584     {
01585         this->m_reading_clients--;
01586         DEBUG_PRINT("readers:%u\n",this->m_reading_clients);
01587         dec_readers = 0;
01588     }
01589     
01590     phTHIS_UNLOCK(locked);
01591 #endif
01592  
01593     return (update_rc >= phSUCCESS) ? 
01594             phLiveObjectUPDATED :
01595             phLiveObjectNOUPDATE;
01596 error:
01597 #if 0
01598     if (dec_readers)
01599     {
01600         this->m_reading_clients--;
01601         DEBUG_PRINT("readers:%u\n",this->m_reading_clients);
01602         dec_readers = 0;
01603     }
01604     phTHIS_ERROR_UNLOCK(locked);
01605 #endif
01606     
01607     return phFAIL;
01608 }
01609 
01610 /* ---------------------------------------------------------------------- */
01611 int phLiveObject::setSourceObject( phLiveObject *source )
01612 {
01613     phFUNCTION("phLiveObject::setSourceObject")
01614     int locked          = 0;
01615 
01616     phTHIS_LOOSE_LOCK(locked);
01617 
01618     this->m_source_object = source;
01619     
01620     phTHIS_LOOSE_UNLOCK(locked);
01621    
01622     return phSUCCESS;
01623 }
01624 
01625 /* ---------------------------------------------------------------------- */
01626 int phLiveObject::hasClients()
01627 {
01628     phFUNCTION("phLiveObject::hasClients")
01629     int ret_rc      = 0;
01630     int cm_locked   = 0;
01631     
01632     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
01633    
01634     if (this->m_cookie_count > 0) ret_rc = 1;
01635     
01636     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
01637     
01638     return ret_rc;
01639 }
01640 
01641 /* ---------------------------------------------------------------------- */
01642 int phLiveObject::clientCount()
01643 {
01644     phFUNCTION("phLiveObject::clientCount")
01645     int ret_rc      = 0;
01646     int cm_locked   = 0;
01647 
01648     phMUTEX_LOOSE_LOCK(this->m_cookie_mutex,cm_locked);
01649    
01650     ret_rc = this->m_cookie_count;
01651     
01652     phMUTEX_LOOSE_UNLOCK(this->m_cookie_mutex,cm_locked);
01653     
01654     return ret_rc;
01655 }
01656 
01657 /* ---------------------------------------------------------------------- */
01658 /* Read Write Lock support to emulate multiple inheritence */
01659 /* ---------------------------------------------------------------------- */
01660 int phLiveObject::readLock() {
01661     return this->m_accessLock.readLock();
01662 }
01663 int phLiveObject::tryReadLock() {
01664     return this->m_accessLock.tryReadLock();
01665 }
01666 int phLiveObject::writeLock() {
01667     return this->m_accessLock.writeLock();
01668 }
01669 int phLiveObject::tryWriteLock() {
01670     return this->m_accessLock.tryWriteLock();
01671 }
01672 int phLiveObject::rwUnlock() {
01673     return this->m_accessLock.rwUnlock();
01674 }
01675 
01676 /* ---------------------------------------------------------------------- */
01677 /* END */
01678 
01679 
01680 




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