log4cplus  1.1.0
syncprims-pthreads.h
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //  Copyright (C) 2009-2010, Vaclav Haisman. All rights reserved.
00003 //
00004 //  Redistribution and use in source and binary forms, with or without modifica-
00005 //  tion, are permitted provided that the following conditions are met:
00006 //
00007 //  1. Redistributions of  source code must  retain the above copyright  notice,
00008 //     this list of conditions and the following disclaimer.
00009 //
00010 //  2. Redistributions in binary form must reproduce the above copyright notice,
00011 //     this list of conditions and the following disclaimer in the documentation
00012 //     and/or other materials provided with the distribution.
00013 //
00014 //  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
00015 //  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
00016 //  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
00017 //  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
00018 //  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
00019 //  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
00020 //  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
00021 //  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
00022 //  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
00023 //  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00024 
00030 
00031 #include "log4cplus/thread/threads.h"
00032 #include <limits>
00033 #include <algorithm>
00034 
00035 
00036 namespace log4cplus { namespace thread { namespace impl {
00037 
00038 
00039 struct PthreadMutexAttr
00040 {
00041     PthreadMutexAttr ()
00042     {
00043         int ret = pthread_mutexattr_init (&attr);
00044         if (ret != 0)
00045             LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::PthreadMutexAttr");
00046     }
00047 
00048 
00049     ~PthreadMutexAttr ()
00050     {
00051         try
00052         {
00053             int ret = pthread_mutexattr_destroy (&attr);
00054             if (ret != 0)
00055                 LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::~PthreadMutexAttr");
00056         }
00057         catch (...)
00058         { }
00059     }
00060 
00061 
00062     void
00063     set_type (log4cplus::thread::Mutex::Type t)
00064     {
00065         int mutex_type;
00066         switch (t)
00067         {
00068         case log4cplus::thread::Mutex::RECURSIVE:
00069             mutex_type = PTHREAD_MUTEX_RECURSIVE;
00070             break;
00071 
00072         default:
00073             mutex_type = PTHREAD_MUTEX_DEFAULT;
00074         }
00075 
00076         int ret = pthread_mutexattr_settype (&attr, mutex_type);
00077         if (ret != 0)
00078             LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::set_type");
00079     }
00080 
00081 
00082     pthread_mutexattr_t attr;
00083 };
00084 
00085 
00086 //
00087 //
00088 //
00089 
00090 inline
00091 Mutex::Mutex (log4cplus::thread::Mutex::Type t)
00092 {
00093     PthreadMutexAttr attr;
00094     attr.set_type (t);
00095 
00096     int ret = pthread_mutex_init (&mtx, &attr.attr);
00097     if (ret != 0)
00098         LOG4CPLUS_THROW_RTE ("Mutex::Mutex");
00099 }
00100 
00101 
00102 inline
00103 Mutex::~Mutex ()
00104 {
00105     try
00106     {
00107         int ret = pthread_mutex_destroy (&mtx);
00108         if (ret != 0)
00109             LOG4CPLUS_THROW_RTE ("Mutex::~Mutex");
00110     }
00111     catch (...)
00112     { }
00113 }
00114 
00115 
00116 inline
00117 void
00118 Mutex::lock () const
00119 {
00120     int ret = pthread_mutex_lock (&mtx);
00121     if (ret != 0)
00122         LOG4CPLUS_THROW_RTE ("Mutex::lock");
00123 }
00124 
00125 
00126 inline
00127 void
00128 Mutex::unlock () const
00129 {
00130     int ret = pthread_mutex_unlock (&mtx);
00131     if (ret != 0)
00132         LOG4CPLUS_THROW_RTE ("Mutex::unlock");
00133 }
00134 
00135 
00136 //
00137 //
00138 //
00139 
00140 inline
00141 Semaphore::Semaphore (unsigned max, unsigned initial)
00142 {
00143     unsigned const sem_value_max =
00144 #if defined (SEM_VALUE_MAX)
00145         SEM_VALUE_MAX
00146 #else
00147         (std::numeric_limits<int>::max) ()
00148 #endif
00149         ;
00150 
00151     unsigned const limited_max = (std::min) (max, sem_value_max);
00152     unsigned const limited_initial = (std::min) (initial, limited_max);
00153     int ret = 0;
00154 
00155 #if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
00156     std::ostringstream oss;
00157     char size_check[2 * (static_cast<int>(sizeof (std::ptrdiff_t))
00158                          - static_cast<int>(sizeof (this))) + 1];
00159     (void)size_check;
00160     oss << getpid () << "-" << reinterpret_cast<std::ptrdiff_t>(this);
00161     std::string name (oss.str ());
00162 
00163     sem = sem_open (name.c_str (), O_CREAT, S_IRWXU | S_IRWXG, limited_max);
00164     ret = sem == SEM_FAILED;
00165     if (ret != 0)
00166         LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
00167 
00168     try
00169     {
00170         // Unlink the semaphore early to simulate anonymous semaphore.
00171         ret = sem_unlink (name.c_str ());
00172         if (ret != 0)
00173             LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
00174     }
00175     catch (std::runtime_error const &)
00176     {
00177         ret = sem_close (sem);
00178         if (ret != 0)
00179             LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
00180 
00181         throw;
00182     }
00183 
00184 #else
00185     ret = sem_init (&sem, 0, limited_max);
00186     if (ret != 0)
00187         LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
00188 
00189 #endif
00190 
00191     try
00192     {
00193         for (unsigned i = limited_initial; i < limited_max; ++i)
00194             lock ();
00195     }
00196     catch (std::runtime_error const &)
00197     {
00198 #if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
00199         ret = sem_close (sem);
00200 #else
00201         ret = sem_destroy (&sem);
00202 #endif
00203         if (ret != 0)
00204             LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
00205 
00206         throw;
00207     }
00208 }
00209 
00210 
00211 inline
00212 Semaphore::~Semaphore ()
00213 {
00214     try
00215     {
00216         int ret = 0;
00217 #if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
00218         ret = sem_close (sem);
00219 #else
00220         ret = sem_destroy (&sem);
00221 #endif
00222         if (ret != 0)
00223             LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
00224     }
00225     catch (...)
00226     { }
00227 }
00228 
00229 
00230 inline
00231 void
00232 Semaphore::unlock () const
00233 {
00234 #if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
00235     int ret = sem_post (sem);
00236 #else
00237     int ret = sem_post (&sem);
00238 #endif
00239     if (ret != 0)
00240         LOG4CPLUS_THROW_RTE ("Semaphore::unlock");
00241 }
00242 
00243 
00244 inline
00245 void
00246 Semaphore::lock () const
00247 {
00248 #if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
00249     int ret = sem_wait (sem);
00250 #else
00251     int ret = sem_wait (&sem);
00252 #endif
00253     if (ret != 0)
00254         LOG4CPLUS_THROW_RTE ("Semaphore::lock");
00255 }
00256 
00257 
00258 //
00259 //
00260 //
00261 
00262 
00263 inline
00264 FairMutex::FairMutex ()
00265     : sem (1, 1)
00266 { }
00267 
00268 
00269 inline
00270 FairMutex::~FairMutex ()
00271 { }
00272 
00273 
00274 inline
00275 void
00276 FairMutex::lock () const
00277 {
00278     sem.lock ();
00279 }
00280 
00281 
00282 inline
00283 void
00284 FairMutex::unlock () const
00285 {
00286     sem.unlock ();
00287 }
00288 
00289 
00290 //
00291 //
00292 //
00293 
00294 inline
00295 ManualResetEvent::ManualResetEvent (bool sig)
00296     : mtx (log4cplus::thread::Mutex::DEFAULT)
00297     , sigcount (0)
00298     , signaled (sig)
00299 {
00300     int ret = pthread_cond_init (&cv, 0);
00301     if (ret != 0)
00302         LOG4CPLUS_THROW_RTE ("ManualResetEvent::ManualResetEvent");
00303 }
00304 
00305 
00306 inline
00307 ManualResetEvent::~ManualResetEvent ()
00308 {
00309     try
00310     {
00311         int ret = pthread_cond_destroy (&cv);
00312         if (ret != 0)
00313             LOG4CPLUS_THROW_RTE ("ManualResetEvent::~ManualResetEvent");
00314     }
00315     catch (...)
00316     { }
00317 }
00318 
00319 
00320 inline
00321 void
00322 ManualResetEvent::signal () const
00323 {
00324     MutexGuard mguard (mtx);
00325 
00326     signaled = true;
00327     sigcount += 1;
00328     int ret = pthread_cond_broadcast (&cv);
00329     if (ret != 0)
00330         LOG4CPLUS_THROW_RTE ("ManualResetEVent::signal");
00331 
00332 }
00333 
00334 
00335 inline
00336 void
00337 ManualResetEvent::wait () const
00338 {
00339     MutexGuard mguard (mtx);
00340 
00341     if (! signaled)
00342     {
00343         unsigned prev_count = sigcount;
00344         do
00345         {
00346             int ret = pthread_cond_wait (&cv, &mtx.mtx);
00347             if (ret != 0)
00348             {
00349                 mguard.unlock ();
00350                 mguard.detach ();
00351                 LOG4CPLUS_THROW_RTE ("ManualResetEvent::wait");
00352             }
00353         }
00354         while (prev_count == sigcount);
00355     }
00356 }
00357 
00358 
00359 inline
00360 bool
00361 ManualResetEvent::timed_wait (unsigned long msec) const
00362 {
00363     MutexGuard mguard (mtx);
00364 
00365     if (! signaled)
00366     {
00367         helpers::Time const wakeup_time (helpers::Time::gettimeofday ()
00368             + helpers::Time (msec / 1000, (msec % 1000) * 1000));
00369         struct timespec const ts = {wakeup_time.sec (),
00370             wakeup_time.usec () * 1000};
00371         unsigned prev_count = sigcount;
00372         do
00373         {
00374             int ret = pthread_cond_timedwait (&cv, &mtx.mtx, &ts);
00375             switch (ret)
00376             {
00377             case 0:
00378                 break;
00379 
00380             case ETIMEDOUT:
00381                 return false;
00382 
00383             default:
00384                 mguard.unlock ();
00385                 mguard.detach ();
00386                 LOG4CPLUS_THROW_RTE ("ManualResetEvent::timed_wait");
00387             }
00388         }
00389         while (prev_count == sigcount);
00390     }
00391 
00392     return true;
00393 }
00394 
00395 
00396 inline
00397 void
00398 ManualResetEvent::reset () const
00399 {
00400     MutexGuard mguard (mtx);
00401 
00402     signaled = false;
00403 }
00404 
00405 
00406 //
00407 //
00408 //
00409 
00410 #if defined (LOG4CPLUS_POOR_MANS_SHAREDMUTEX)
00411 #include "log4cplus/thread/impl/syncprims-pmsm.h"
00412 
00413 #else
00414 inline
00415 SharedMutex::SharedMutex ()
00416 {
00417     int ret = pthread_rwlock_init (&rwl, 0);
00418     if (ret != 0)
00419         LOG4CPLUS_THROW_RTE ("SharedMutex::SharedMutex");
00420 }
00421 
00422 
00423 inline
00424 SharedMutex::~SharedMutex ()
00425 {
00426     try
00427     {
00428         int ret = pthread_rwlock_destroy (&rwl);
00429         if (ret != 0)
00430             LOG4CPLUS_THROW_RTE ("SharedMutex::~SharedMutex");
00431     }
00432     catch (...)
00433     { }
00434 }
00435 
00436 
00437 inline
00438 void
00439 SharedMutex::rdlock () const
00440 {
00441     int ret;
00442 
00443     do
00444     {
00445         ret = pthread_rwlock_rdlock (&rwl);
00446         switch (ret)
00447         {
00448         case EAGAIN:
00449             // The read lock could not be acquired because the maximum
00450             // number of read locks for rwlock has been exceeded.
00451 
00452             log4cplus::thread::yield ();
00453             // Fall through.
00454 
00455         case 0:
00456             break;
00457 
00458         default:
00459             LOG4CPLUS_THROW_RTE ("SharedMutex::rdlock");
00460 
00461         }
00462     }
00463     while (ret != 0);
00464 }
00465 
00466 
00467 inline
00468 void
00469 SharedMutex::rdunlock () const
00470 {
00471     unlock ();
00472 }
00473 
00474 
00475 inline
00476 void
00477 SharedMutex::wrlock () const
00478 {
00479     int ret = pthread_rwlock_wrlock (&rwl);
00480     if (ret != 0)
00481         LOG4CPLUS_THROW_RTE ("SharedMutex::wrlock");
00482 }
00483 
00484 
00485 inline
00486 void
00487 SharedMutex::wrunlock () const
00488 {
00489     unlock ();
00490 }
00491 
00492 
00493 inline
00494 void
00495 SharedMutex::unlock () const
00496 {
00497     int ret = pthread_rwlock_unlock (&rwl);
00498     if (ret != 0)
00499         LOG4CPLUS_THROW_RTE ("SharedMutex::unlock");
00500 
00501 }
00502 
00503 
00504 #endif
00505 
00506 
00507 } } } // namespace log4cplus { namespace thread { namespace impl {