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

phSemaphore.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 
00035 #include <phSemaphore.h>
00036 
00037 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32)
00038     #include <semaphore.h>
00039 #endif
00040 #if defined(WIN32)
00041     #include <windows.h>
00042 #endif
00043 #if defined(__ADSPBLACKFIN__)
00044     #include <PhissionVDK.h>
00045 #endif
00046 #ifdef HAVE_ERRNO_H
00047     #include <errno.h>
00048 #endif
00049 
00050 #include <phError.h>
00051 #include <phMemory.h>
00052 #include <phPrint.h>
00053 
00054 /* ---------------------------------------------------------------------- */
00055 struct ph_semaphore_info_t
00056 {
00057 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32)
00058     sem_t               m_semaphore;
00059 #endif
00060 #if defined(WIN32)
00061     HANDLE              m_semaphore;
00062 #endif
00063 #if defined(__ADSPBLACKFIN__)
00064     VDK::SemaphoreID    m_semaphore;
00065 #endif
00066 };
00067 
00068 /* ---------------------------------------------------------------------- */
00069 phSemaphore::phSemaphore(uint32_t value, uint32_t max)
00070 {
00071     phFUNCTION("phSemaphore::phSemaphore")
00072     int locked = 0;
00073 
00074     phTHIS_LOCK(locked);
00075 
00076     this->setName("phSemaphore");
00077     
00078     /* Make sure max is within proper value boundaries */
00079     if (max < 1)                    max = 1;
00080     else if (max > phSemVALUEMAX)   max = phSemVALUEMAX;
00081 
00082     /* make sure the value is within permitted boundaries */
00083     if (value > phSemVALUEMAX)  value = phSemVALUEMAX;
00084     if (value > max)            value = max;
00085 
00086     this->m_info = (struct ph_semaphore_info_t *)phCalloc(1,
00087                             sizeof(struct ph_semaphore_info_t));
00088     phPRINT_PTR(this->m_info,"phCalloc","phCalloc failed.");
00089     
00090 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32)
00091     rc = sem_init(&(this->m_info->m_semaphore),
00092                   0, /* not shared, it's not supported anyway */
00093                   value);
00094     phPRINT_RC(rc,"sem_init","sem_init failed to create semaphore.");
00095 #endif
00096 #if defined(WIN32)
00097     this->m_info->m_semaphore = CreateSemaphore(NULL,value,max,NULL);
00098     phPRINT_NULLPTR(this->m_info->m_semaphore,
00099                   "CreateSemaphore",
00100                   "CreateSemaphore failed.");
00101                   
00102 #endif
00103 #if defined(__ADSPBLACKFIN__)
00104     this->m_info->m_semaphore = VDK::CreateSemaphore(value,max,0,0);
00105     if (this->m_info->m_semaphore == UINT_MAX)
00106     {
00107         /* Handle error ? *
00108         int e = VDK::GetLastThreadErrorValue();
00109         if (e == kMaxCountExceeded)
00110         {
00111             phCHECK_RC(-1,NULL,
00112                 "inInitialValue is greater than inMaxCount");
00113         }
00114         else if (e == kSemaphoreCreationFailure)
00115         {
00116             phCHECK_RC(-1,NULL,
00117                 "kernel is not able to allocate and/or initialize memory for the semaphore");
00118         }
00119         */
00120         phCHECK_RC(-1,NULL,"CreateSemaphore failed.");
00121     }
00122 #endif
00123     this->m_waiting = 0;
00124     this->m_max     = max;
00125     this->m_count   = 0;
00126     
00127     phTHIS_UNLOCK(locked);
00128     return;
00129 error:
00130     phTHIS_ERROR_UNLOCK(locked);
00131     return;
00132 }
00133 
00134 /* ---------------------------------------------------------------------- */
00135 phSemaphore::~phSemaphore()
00136 {
00137     phFUNCTION("phSemaphore::~phSemaphore")
00138     int locked = 0;
00139 #if defined(WIN32)
00140     BOOL bResult;
00141 #endif
00142 
00143     phTHIS_LOOSE_LOCK(locked);
00144 
00145     this->m_count   = 0;
00146     this->m_max     = 0;
00147     
00148 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32) 
00149     rc = sem_destroy(&(this->m_info->m_semaphore));
00150     phPRINT_RC(rc,"sem_destroy","sem_destroy failed");
00151 #endif
00152 
00153 #if defined(WIN32)
00154     bResult = CloseHandle(this->m_info->m_semaphore);
00155     if (!bResult) rc = phFAIL; else rc = phSUCCESS;
00156     phPRINT_RC(rc,"CloseHandle","Close handle failed");
00157 #endif
00158 
00159 #if defined(__ADSPBLACKFIN__)
00160     VDK::DestroySemaphore(this->m_info->m_semaphore);
00161 #endif
00162 
00163     /* this doesn't need to be unlocked because when phMutex is destroy
00164      * and the mutex finally destroyed, the OS should signal any waiting
00165      * threads */
00166     phFree(this->m_info);
00167 }
00168 
00169 /* ---------------------------------------------------------------------- */
00170 int phSemaphore::copy( phObject *copyto_obj )
00171 { 
00172     return phObject::swap(copyto_obj); 
00173 }
00174 
00175 /* ---------------------------------------------------------------------- */
00176 int phSemaphore::swap( phObject *obj ) 
00177 { 
00178     return phObject::swap(obj); 
00179 }
00180 
00181 /* ---------------------------------------------------------------------- */
00182 /* By locking the object, it also provides us the ability to post
00183  * all the semaphores for all the waiting threads without having more 
00184  * enter */
00185 /* ---------------------------------------------------------------------- */
00186 int phSemaphore::post(uint32_t value)
00187 {
00188     phFUNCTION("phSemaphore::post")
00189     int locked = 0;
00190 
00191     int         retrc = phSUCCESS;
00192 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32) || defined(__ADSPBLACKFIN__)
00193     uint32_t    i       = 0;
00194 #endif
00195 #if defined(WIN32)
00196     BOOL        bResult = TRUE;
00197 #endif
00198 
00199     if (value == 0) goto success;
00200     
00201     phTHIS_LOOSE_LOCK(locked);
00202 
00203     /* if we've hit the maximum... */
00204     /* ... We don't want to post more than we're permitted */
00205     if (this->m_max == this->m_count)
00206     {
00207         /* ... then value needs to be set to 0 */
00208         value = 0;
00209     }
00210     /* if we haven't hit the maximum, then... */
00211     else if (this->m_max > this->m_count)
00212     {
00213         /* Figure out the limit on how many we can post... */
00214         if ((this->m_max - this->m_count) < value)
00215         {
00216             retrc = (value - (this->m_max - this->m_count));
00217             value = this->m_max - this->m_count;
00218         }
00219     }
00220     
00221     if (value > 0)
00222     {
00223 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32) 
00224         for (i = 0; (i < value); i++ )
00225         {
00226             rc = sem_post( &(this->m_info->m_semaphore) );
00227             phPRINT_RC(rc,"sem_post","sem_post failed." );
00228             if (rc == 0)
00229             {
00230                 this->m_count++;
00231             }
00232         }
00233 #endif
00234     
00235 #if defined(WIN32)
00236         /* ... Post the amount of semaphores we're allowed */
00237         bResult = TRUE;
00238         bResult = ReleaseSemaphore(this->m_info->m_semaphore,
00239                                    value,
00240                                    NULL);
00241         if (!bResult)
00242         {
00243             rc = phFAIL; 
00244         }
00245         else 
00246         {
00247             this->m_count += value;
00248             rc = phSUCCESS;
00249         }
00250         phPRINT_RC(rc,"ReleaseSemaphore",
00251                  "Releasing the rest of the semaphores failed."); 
00252 #endif
00253 
00254 #if defined(__ADSPBLACKFIN__)
00255         for (i = 0; (i < value); i++ )
00256         {
00257             this->m_count++;
00258             VDK::PostSemaphore( this->m_info->m_semaphore );
00259         }
00260 #endif
00261     } 
00262     phTHIS_LOOSE_UNLOCK(locked);
00263 success:    
00264     return retrc;
00265 }
00266 
00267 /* ---------------------------------------------------------------------- */
00268 int phSemaphore::postToWaiting(uint32_t minimum)
00269 {
00270     phFUNCTION("phSemaphore::postToWaiting")
00271     int locked = 0;
00272 
00273     phTHIS_LOOSE_LOCK(locked);
00274    
00275     rc = this->post((this->m_waiting < minimum) ? minimum : this->m_waiting);
00276     phPRINT_RC(rc,NULL,"this->post(%u)",this->m_waiting);
00277     
00278     phTHIS_LOOSE_UNLOCK(locked);
00279     
00280     return phSUCCESS;
00281 }
00282 
00283 /* ---------------------------------------------------------------------- */
00284 int phSemaphore::postMax()
00285 {
00286     phFUNCTION("phSemaphore::postMax")
00287     int locked = 0;
00288 
00289     phTHIS_LOOSE_LOCK(locked);
00290    
00291     rc = this->post(this->m_max);
00292     phPRINT_RC(rc,NULL,"this->post(%u)",this->m_waiting);
00293     
00294     phTHIS_LOOSE_UNLOCK(locked);
00295     
00296     return phSUCCESS;
00297 }
00298 
00299 /* ---------------------------------------------------------------------- */
00300 /* Cookie will be locked when semaphore successfully taken */
00301 /* ---------------------------------------------------------------------- */
00302 int phSemaphore::take( uint32_t flag )
00303 {
00304     phFUNCTION("phSemaphore::take")
00305     int locked  = 0;
00306     int ret_rc  = phFAIL;
00307     bool brc    = true;
00308 
00309 #if defined(WIN32)
00310     DWORD dwWaitResult;
00311 #endif
00312 
00313     phTHIS_LOOSE_LOCK(locked);
00314    
00315     this->m_waiting++;
00316 
00317     /* blocking */
00318     if (((flag & phSemaphoreWAIT) == phSemaphoreWAIT) || (!flag))
00319     {
00320         /* unlock here while waiting for the semaphore */
00321         /* This prevents the cookie from being locked
00322          * which would keep a sem_post from occuring */
00323         phTHIS_LOOSE_UNLOCK(locked);
00324 
00325         ret_rc = rc = phSUCCESS;
00326 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32)
00327         do {
00328             ret_rc = rc = sem_wait( &(this->m_info->m_semaphore) );
00329         } while ((rc != 0) && (errno == EINTR));
00330         phPRINT_RC(rc,"sem_wait", "m_info->m_semaphore wait failed.");
00331 #endif
00332 
00333 #if defined(WIN32)
00334         dwWaitResult = WaitForSingleObject( this->m_info->m_semaphore, INFINITE );
00335         /* There was an error waiting on the thread */
00336         if (dwWaitResult == WAIT_FAILED) 
00337         {
00338             rc      = phFAIL; 
00339             ret_rc  = phFAIL;
00340         }
00341         else
00342         {
00343             rc      = phSUCCESS;
00344             ret_rc  = phSUCCESS;
00345         }
00346         phPRINT_RC(rc,"WaitForSingleObject","Wait on semaphore failed.");    
00347 #endif
00348 
00349 #if defined(__ADSPBLACKFIN__)
00350         brc = VDK::PendSemaphore(this->m_info->m_semaphore,0);
00351         /* Handle error? *
00352          * brc == FALSE is Pend timed out */
00353         if (brc != false)
00354         {
00355             rc      = phSUCCESS;
00356             ret_rc  = phSUCCESS;
00357         }
00358         else
00359         {
00360             rc      = phFAIL;
00361             ret_rc  = phFAIL;
00362         }
00363 #endif
00364         /* lock again here before altering m_waiting below */
00365         phTHIS_LOOSE_LOCK(locked);
00366     }
00367     /* non-blocking */
00368     /* Don't unlock here as it would be unnecessary
00369      * We're only checking to see if a semaphore is available and 
00370      * will drop through right away.
00371      * 
00372      * Unlock when we find out if we got the semaphore.
00373      * If we didn't, then unlock, Yield and then return*/
00374     else if ((flag & phSemaphoreNOWAIT) == phSemaphoreNOWAIT)
00375     {
00376         ret_rc = rc = phSUCCESS;
00377 #if defined(HAVE_SEMAPHORE_H) && !defined(WIN32)
00378         do {
00379             ret_rc = rc = sem_trywait( &(this->m_info->m_semaphore) );
00380         } while ((rc != 0) && (errno == EINTR));
00381 
00382         if (ret_rc < 0)
00383         {
00384             /* only set ret_rc to zero for non-blocking, otherwise
00385              * there will be alot of error messages */
00386             if (errno == EAGAIN)
00387             {
00388                 /* no new obj */
00389                 ret_rc = phSemaphoreNOTAKE;
00390             }
00391             else
00392                 ret_rc = phSemaphoreTAKEN;
00393         }
00394         /* TODO: Try out rc here instead of ret_rc; otherwise this macro's
00395          * body is never invoked */
00396         /* phPRINT_RC(ret_rc,"sem_wait", "m_info->m_semaphore wait failed."); */
00397 #endif
00398 
00399 #if defined(WIN32)
00400         dwWaitResult = WaitForSingleObject( this->m_info->m_semaphore, 0L );
00401         /* There was an error waiting on the thread */
00402         if (dwWaitResult == WAIT_FAILED) 
00403         {
00404             rc      = phFAIL; 
00405             ret_rc  = phFAIL;
00406         }
00407         else if (dwWaitResult == WAIT_TIMEOUT)
00408         {
00409             rc      = phSUCCESS;
00410             ret_rc  = phSemaphoreNOTAKE;
00411         }
00412         else 
00413         {
00414             rc      = phSUCCESS;
00415             ret_rc  = phSUCCESS;
00416         }
00417         phPRINT_RC(rc,"WaitForSingleObject","Wait on semaphore failed.");    
00418 #endif
00419 
00420 #if defined(__ADSPBLACKFIN__)
00421         brc = VDK::PendSemaphore(this->m_info->m_semaphore,
00422                                  1 | VDK::kNoTimeoutError);
00423         if (brc == false)
00424         {
00425             rc      = phSUCCESS;
00426             ret_rc  = phSemaphoreNOTAKE;
00427         }
00428 #endif
00429     }
00430 
00431     if (ret_rc == phSUCCESS)
00432     {
00433         if (this->m_count == 0)
00434         {
00435             phERR_PRINT("This thread got a semaphore it shouldn't have. Count equaled 0.\n");
00436         }
00437         else
00438         {
00439             this->m_count -= 1;
00440         }
00441     }
00442 
00443     this->m_waiting--;
00444 
00445     phTHIS_LOOSE_UNLOCK(locked);
00446     
00447     /* If we were non-blocking and didn't get a semaphore, then
00448      * yield internally (here) to prevent tight loops on 
00449      * non-blocking calls */
00450     if (((flag & phSemaphoreNOWAIT) == phSemaphoreNOWAIT) &&
00451         (ret_rc == phSemaphoreNOTAKE))
00452     {
00453         phYield();
00454     }
00455 
00456     return ret_rc;
00457 #if 0
00458 error:
00459     phTHIS_LOOSE_UNLOCK(locked);
00460     
00461     return phFAIL;
00462 #endif
00463 }
00464 
00465 /* ---------------------------------------------------------------------- */
00466 int phSemaphore::tryTake()
00467 {
00468     /* phFUNCTION("phSemaphore::tryTake") */
00469 
00470     /* returns 1 if failed to get a semaphore */
00471     return this->take(phSemaphoreNOWAIT);
00472 }
00473 
00474 /* ---------------------------------------------------------------------- */
00475 uint32_t phSemaphore::getValue()
00476 {
00477     phFUNCTION("phSemaphore::getValue")
00478     int locked = 0;
00479     int semval = 0;
00480 
00481     phTHIS_LOOSE_LOCK(locked);
00482      
00483     /* This semaphore is now conceivably a thread accessable semaphore.
00484      * There is no sem_getvalue equivalent method for Win32 */
00485 #if 0
00486 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00487     rc = sem_getvalue( &(this->m_info->m_semaphore), &semval);
00488     phCHECK_RC(rc,"sem_getvalue","sem_getvalue failed.");
00489 #endif
00490 #endif
00491     semval = this->m_count;
00492     
00493     phTHIS_LOOSE_UNLOCK(locked);
00494             
00495     return semval;
00496 #if 0
00497 error:
00498     phTHIS_LOOSE_UNLOCK(locked);
00499             
00500     return rc;
00501 #endif
00502 }
00503 
00504 /* ---------------------------------------------------------------------- */
00505 /* I know what you're thinking:
00506  * 
00507  * Q: "What happens if someone is waiting on the lock, then m_waiting won't 
00508  * reflect the accurate waiting count, right?"
00509  * 
00510  * A: It's the same for SYSV semaphores. If someone doesn't get to the 
00511  * semaphore before the waiting count is retrieved, it won't accurately
00512  * reflect the wainting count of the FUTURE, but it will (as does m_waiting)
00513  * reflect the accurate waiting count of NOW 
00514  * Whether the future count will be different because someone is blocked 
00515  * on a mutex or just hasn't made a _wait call; there's no difference.
00516  *
00517  * (The FUTURE count could also be less than the NOW count)
00518  */
00519 /* ---------------------------------------------------------------------- */
00520 uint32_t phSemaphore::getWaitingCount()
00521 {
00522     phFUNCTION("phSemaphore::getWaitingCount")
00523     int locked = 0;
00524     uint32_t w = 0;
00525     
00526     phTHIS_LOOSE_LOCK(locked);
00527     
00528     w = this->m_waiting;
00529     
00530     phTHIS_LOOSE_UNLOCK(locked);
00531     
00532     return w;
00533 }
00534 
00535 /* ---------------------------------------------------------------------- */
00536 uint32_t phSemaphore::getMax() 
00537 { 
00538     return this->m_max; 
00539 }
00540 




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