log4cplus
1.1.0
|
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 {