LCOV - code coverage report
Current view: top level - cppthread - mutex.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 236 19.9 %
Date: 2021-08-21 09:27:22 Functions: 9 16 56.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2013-2021  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/cppthread
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : /** \file
      21             :  * \brief Implementation of the Thread Runner and Managers.
      22             :  *
      23             :  * This file includes the implementation used by the cppthread environment.
      24             :  */
      25             : 
      26             : 
      27             : // self
      28             : //
      29             : #include    "cppthread/mutex.h"
      30             : 
      31             : #include    "cppthread/exception.h"
      32             : #include    "cppthread/guard.h"
      33             : #include    "cppthread/log.h"
      34             : 
      35             : 
      36             : // C lib
      37             : //
      38             : #include    <string.h>
      39             : #include    <sys/time.h>
      40             : 
      41             : 
      42             : // last include
      43             : //
      44             : #include    <snapdev/poison.h>
      45             : 
      46             : 
      47             : 
      48             : 
      49             : namespace cppthread
      50             : {
      51             : 
      52             : 
      53             : 
      54             : namespace detail
      55             : {
      56             : 
      57             : 
      58             : 
      59             : /** \brief The implementation of the mutex.
      60             :  *
      61             :  * We have an internal implementation of the mutex to avoid leaking the
      62             :  * pthread library to the outside.
      63             :  *
      64             :  * The class holds a mutex and a condition which we use to wait in various
      65             :  * circumstances such as when we pop items from a currently empty fifo.
      66             :  */
      67          28 : class mutex_impl
      68             : {
      69             : public:
      70             :     pthread_mutex_t     f_mutex = pthread_mutex_t();
      71             :     pthread_cond_t      f_condition = pthread_cond_t();
      72             : };
      73             : 
      74             : 
      75             : /** \var pthread_mutex_t mutex_impl::f_mutex
      76             :  * \brief Mutex to support guards & signals.
      77             :  *
      78             :  * This is the actual system mutex. It is useful to protect areas of code
      79             :  * that only one thread is allowed to access at a time.
      80             :  *
      81             :  * The mutex also supports a condition that it can wait on and signal. This
      82             :  * is useful to signal a new state such as the end of FIFO as any thread
      83             :  * waiting on that FIFO now needs to wake up a give up (no more messages
      84             :  * will be sent to the FIFO).
      85             :  */
      86             : 
      87             : 
      88             : /** \var pthread_mutex_t mutex_impl::f_condition
      89             :  * \brief Condition linked to the mutex to support signalling.
      90             :  *
      91             :  * We often have to signal that a thread is done in regard to something or
      92             :  * other. That will wake up another thread which can then take over the
      93             :  * next step of the work.
      94             :  *
      95             :  * The condition is used for that purpose as we can wait on it with the
      96             :  * attached mutex.
      97             :  */
      98             : 
      99             : 
     100             : 
     101             : }
     102             : 
     103             : 
     104             : 
     105             : /** \class mutex
     106             :  * \brief A mutex object to ensures atomicity.
     107             :  *
     108             :  * This class is used by threads when some data accessed by more than
     109             :  * one thread is about to be accessed. In most cases it is used with the
     110             :  * guard class so it is safe even in the event an exception is raised.
     111             :  *
     112             :  * The mutex also includes a condition variable which can be signaled
     113             :  * using the signal() function. This wakes threads that are currently
     114             :  * waiting on the condition with one of the wait() functions.
     115             :  *
     116             :  * \note
     117             :  * We use a recursive mutex so you may lock the mutex any number of times.
     118             :  * It has to be unlocked that many times, of course.
     119             :  */
     120             : 
     121             : 
     122             : 
     123             : 
     124             : /** \brief An inter-thread mutex to ensure unicity of execution.
     125             :  *
     126             :  * The mutex object is used to lock part of the code that needs to be run
     127             :  * by only one thread at a time. This is also called a critical section
     128             :  * and a memory barrier.
     129             :  *
     130             :  * In most cases one uses the guard object to temporarily lock
     131             :  * the mutex using the FIFO to help ensure the mutex gets unlocked as
     132             :  * required in the event an exception occurs.
     133             :  *
     134             :  * \code
     135             :  * {
     136             :  *    cppthread::guard lock(&my_mutex)
     137             :  *    ... // protected code
     138             :  * }
     139             :  * \endcode
     140             :  *
     141             :  * The lock can be tried to see whether another thread already has the
     142             :  * lock and fail if so. See the try_lock() function.
     143             :  *
     144             :  * The class also includes a condition in order to send signals and wait
     145             :  * on signals. There are two ways to send signals and three ways to wait.
     146             :  * Note that to call any one of the wait functions you must first have the
     147             :  * mutex locked, what otherwise happens is undefined.
     148             :  *
     149             :  * \code
     150             :  * {
     151             :  *      // wake one waiting thread
     152             :  *      my_mutex.signal();
     153             :  *
     154             :  *      // wake all the waiting thread
     155             :  *      my_mutex.broadcast();
     156             :  *
     157             :  *      // wait on the signal forever
     158             :  *      {
     159             :  *          cppthread::guard lock(&my_mutex);
     160             :  *          my_mutex.wait();
     161             :  *      }
     162             :  *
     163             :  *      // wait on the signal for the specified amount of time
     164             :  *      {
     165             :  *          cppthread::guard lock(&my_mutex);
     166             :  *          my_mutex.timed_wait(1000000UL); // wait up to 1 second
     167             :  *      }
     168             :  *
     169             :  *      // wait on the signal for until date or later or the signal
     170             :  *      {
     171             :  *          cppthread::guard lock(&my_mutex);
     172             :  *          my_mutex.dated_wait(date); // wait on signal or until date
     173             :  *      }
     174             :  * }
     175             :  * \endcode
     176             :  *
     177             :  * If you need a FIFO of messages between your threads, look at the
     178             :  * snap_fifo template.
     179             :  *
     180             :  * \note
     181             :  * Care must be used to always initialized a mutex before it
     182             :  * is possibly accessed by more than one thread. This is usually
     183             :  * the case in the constructor of your objects.
     184             :  *
     185             :  * \exception cppthread_exception_invalid_error
     186             :  * If any one of the initialization functions fails, this exception is
     187             :  * raised. The function also logs the error.
     188             :  */
     189          28 : mutex::mutex()
     190          28 :     : f_impl(std::make_shared<detail::mutex_impl>())
     191             : {
     192             :     // initialize the mutex
     193          28 :     pthread_mutexattr_t mattr;
     194          28 :     int err(pthread_mutexattr_init(&mattr));
     195          28 :     if(err != 0)
     196             :     {
     197           0 :         log << log_level_t::fatal
     198           0 :             << "a mutex attribute structure could not be initialized, error #"
     199           0 :             << err
     200           0 :             << end;
     201           0 :         throw cppthread_invalid_error("pthread_muteattr_init() failed");
     202             :     }
     203          28 :     err = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
     204          28 :     if(err != 0)
     205             :     {
     206           0 :         log << log_level_t::fatal
     207           0 :             << "a mutex attribute structure type could not be setup, error #"
     208           0 :             << err
     209           0 :             << end;
     210           0 :         pthread_mutexattr_destroy(&mattr);
     211           0 :         throw cppthread_invalid_error("pthread_muteattr_settype() failed");
     212             :     }
     213          28 :     err = pthread_mutex_init(&f_impl->f_mutex, &mattr);
     214          28 :     if(err != 0)
     215             :     {
     216           0 :         log << log_level_t::fatal
     217           0 :             << "a mutex structure could not be initialized, error #"
     218           0 :             << err
     219           0 :             << end;
     220           0 :         pthread_mutexattr_destroy(&mattr);
     221           0 :         throw cppthread_invalid_error("pthread_mutex_init() failed");
     222             :     }
     223          28 :     err = pthread_mutexattr_destroy(&mattr);
     224          28 :     if(err != 0)
     225             :     {
     226           0 :         log << log_level_t::fatal
     227           0 :             << "a mutex attribute structure could not be destroyed, error #"
     228           0 :             << err
     229           0 :             << end;
     230           0 :         pthread_mutex_destroy(&f_impl->f_mutex);
     231           0 :         throw cppthread_invalid_error("pthread_mutexattr_destroy() failed");
     232             :     }
     233             : 
     234             :     // initialize the condition
     235          28 :     pthread_condattr_t cattr;
     236          28 :     err = pthread_condattr_init(&cattr);
     237          28 :     if(err != 0)
     238             :     {
     239           0 :         log << log_level_t::fatal
     240           0 :             << "a mutex condition attribute structure could not be initialized, error #"
     241           0 :             << err
     242           0 :             << end;
     243           0 :         pthread_mutex_destroy(&f_impl->f_mutex);
     244           0 :         throw cppthread_invalid_error("pthread_condattr_init() failed");
     245             :     }
     246          28 :     err = pthread_cond_init(&f_impl->f_condition, &cattr);
     247          28 :     if(err != 0)
     248             :     {
     249           0 :         log << log_level_t::fatal
     250           0 :             << "a mutex condition structure could not be initialized, error #"
     251           0 :             << err
     252           0 :             << end;
     253           0 :         pthread_condattr_destroy(&cattr);
     254           0 :         pthread_mutex_destroy(&f_impl->f_mutex);
     255           0 :         throw cppthread_invalid_error("pthread_cond_init() failed");
     256             :     }
     257          28 :     err = pthread_condattr_destroy(&cattr);
     258          28 :     if(err != 0)
     259             :     {
     260           0 :         log << log_level_t::fatal
     261           0 :             << "a mutex condition attribute structure could not be destroyed, error #"
     262           0 :             << err
     263           0 :             << end;
     264           0 :         pthread_mutex_destroy(&f_impl->f_mutex);
     265           0 :         throw cppthread_invalid_error("pthread_condattr_destroy() failed");
     266             :     }
     267          28 : }
     268             : 
     269             : 
     270             : /** \brief Clean up a mutex object.
     271             :  *
     272             :  * This function ensures that the mutex object is cleaned up, which means
     273             :  * the mutex and conditions get destroyed.
     274             :  *
     275             :  * This destructor verifies that the mutex is not currently locked. A
     276             :  * locked mutex can't be destroyed. If still locked, then an error is
     277             :  * sent to the logger and the function calls exit(1).
     278             :  */
     279          50 : mutex::~mutex()
     280             : {
     281             :     // Note that the following reference count test only ensure that
     282             :     // you don't delete a mutex which is still locked; however, if
     283             :     // you still have multiple threads running, we can't really know
     284             :     // if another thread is not just about to use this thread...
     285             :     //
     286          25 :     if(f_reference_count != 0UL)
     287             :     {
     288             :         // we cannot legally throw in a destructor so we instead generate a fatal error
     289             :         //
     290           0 :         log << log_level_t::fatal
     291           0 :             << "a mutex is being destroyed when its reference count is "
     292           0 :             << f_reference_count
     293           0 :             << " instead of zero."
     294           0 :             << end;
     295           0 :         std::terminate();
     296             :     }
     297          25 :     int err(pthread_cond_destroy(&f_impl->f_condition));
     298          25 :     if(err != 0)
     299             :     {
     300           0 :         log << log_level_t::error
     301           0 :             << "a mutex condition destruction generated error #"
     302           0 :             << err
     303           0 :             << end;
     304             :     }
     305          25 :     err = pthread_mutex_destroy(&f_impl->f_mutex);
     306          25 :     if(err != 0)
     307             :     {
     308           0 :         log << log_level_t::fatal
     309           0 :             << "a mutex destruction generated error #"
     310           0 :             << err
     311           0 :             << end;
     312             :     }
     313          25 : }
     314             : 
     315             : 
     316             : /** \brief Lock a mutex
     317             :  *
     318             :  * This function locks the mutex. The function waits until the mutex is
     319             :  * available if it is not currently available. To avoid waiting one may
     320             :  * want to use the try_lock() function instead.
     321             :  *
     322             :  * Although the function cannot fail, the call can lock up a process if
     323             :  * two or more mutexes are used and another thread is already waiting
     324             :  * on this process.
     325             :  *
     326             :  * \exception cppthread_exception_invalid_error
     327             :  * If the lock fails, this exception is raised.
     328             :  */
     329         137 : void mutex::lock()
     330             : {
     331         137 :     int const err(pthread_mutex_lock(&f_impl->f_mutex));
     332         137 :     if(err != 0)
     333             :     {
     334           0 :         log << log_level_t::error
     335           0 :             << "a mutex lock generated error #"
     336           0 :             << err
     337           0 :             << " -- "
     338           0 :             << strerror(err)
     339           0 :             << end;
     340           0 :         throw cppthread_invalid_error("pthread_mutex_lock() failed");
     341             :     }
     342             : 
     343             :     // note: we do not need an atomic call since we
     344             :     //       already know we are running alone here...
     345         137 :     ++f_reference_count;
     346         137 : }
     347             : 
     348             : 
     349             : /** \brief Try locking the mutex.
     350             :  *
     351             :  * This function tries locking the mutex. If the mutex cannot be locked
     352             :  * because another process already locked it, then the function returns
     353             :  * immediately with false.
     354             :  *
     355             :  * \exception cppthread_exception_invalid_error
     356             :  * If the lock fails, this exception is raised.
     357             :  *
     358             :  * \return true if the lock succeeded, false otherwise.
     359             :  */
     360           0 : bool mutex::try_lock()
     361             : {
     362           0 :     int const err(pthread_mutex_trylock(&f_impl->f_mutex));
     363           0 :     if(err == 0)
     364             :     {
     365             :         // note: we do not need an atomic call since we
     366             :         //       already know we are running alone here...
     367           0 :         ++f_reference_count;
     368           0 :         return true;
     369             :     }
     370             : 
     371             :     // failed because another thread has the lock?
     372           0 :     if(err == EBUSY)
     373             :     {
     374           0 :         return false;
     375             :     }
     376             : 
     377             :     // another type of failure
     378           0 :     log << log_level_t::error
     379           0 :         << "a mutex try lock generated error #"
     380           0 :         << err
     381           0 :         << " -- "
     382           0 :         << strerror(err)
     383           0 :         << end;
     384           0 :     throw cppthread_invalid_error("pthread_mutex_trylock() failed");
     385             : }
     386             : 
     387             : 
     388             : /** \brief Unlock a mutex.
     389             :  *
     390             :  * This function unlock the specified mutex. The function must be called
     391             :  * exactly once per call to the lock() function, or successful call to
     392             :  * the try_lock() function.
     393             :  *
     394             :  * The unlock never waits.
     395             :  *
     396             :  * \exception cppthread_exception_invalid_error
     397             :  * If the unlock fails, this exception is raised.
     398             :  *
     399             :  * \exception cppthread_exception_not_locked_error
     400             :  * If the function is called too many times, then the lock count is going
     401             :  * to be zero and this exception will be raised.
     402             :  */
     403         137 : void mutex::unlock()
     404             : {
     405             :     // We can't unlock if it wasn't locked before!
     406         137 :     if(f_reference_count <= 0UL)
     407             :     {
     408           0 :         log << log_level_t::fatal
     409           0 :             << "attempting to unlock a mutex when it is still locked "
     410           0 :             << f_reference_count
     411           0 :             << " times"
     412           0 :             << end;
     413           0 :         throw cppthread_not_locked_error("unlock was called too many times");
     414             :     }
     415             : 
     416             :     // NOTE: we do not need an atomic call since we
     417             :     //       already know we are running alone here...
     418         137 :     --f_reference_count;
     419             : 
     420         137 :     int const err(pthread_mutex_unlock(&f_impl->f_mutex));
     421         137 :     if(err != 0)
     422             :     {
     423           0 :         log << log_level_t::fatal
     424           0 :             << "a mutex unlock generated error #"
     425           0 :             << err
     426           0 :             << " -- "
     427           0 :             << strerror(err)
     428           0 :             << end;
     429           0 :         throw cppthread_invalid_error("pthread_mutex_unlock() failed");
     430             :     }
     431         137 : }
     432             : 
     433             : 
     434             : /** \brief Wait on a mutex condition.
     435             :  *
     436             :  * At times it is useful to wait on a mutex to become available without
     437             :  * polling the mutex (which uselessly wastes precious processing time.)
     438             :  * This function can be used to wait on a mutex condition.
     439             :  *
     440             :  * This version of the wait() blocks until a signal is received.
     441             :  *
     442             :  * \warning
     443             :  * This function cannot be called if the mutex is not locked or the
     444             :  * wait will fail in unpredictable ways.
     445             :  *
     446             :  * \exception cppthread_exception_not_locked_once_error
     447             :  * This exception is raised if the reference count is not exactly 1.
     448             :  * In other words, the mutex must be locked by the caller but only
     449             :  * one time.
     450             :  *
     451             :  * \exception cppthread_exception_mutex_failed_error
     452             :  * This exception is raised in the event the conditional wait fails.
     453             :  */
     454           0 : void mutex::wait()
     455             : {
     456             :     // For any mutex wait to work, we MUST have the
     457             :     // mutex locked already and just one time.
     458             :     //
     459             :     // note: the 1 time is just for assurance that it will
     460             :     //       work in most cases; it should work even when locked
     461             :     //       multiple times, but it is less likely. For sure, it
     462             :     //       has to be at least once.
     463             :     //if(f_reference_count != 1UL)
     464             :     //{
     465             :     //    log << log_level_t::fatal
     466             :     //        << "attempting to wait on a mutex when it is not locked exactly once, current count is "
     467             :     //        << f_reference_count
     468             :     //        << end;
     469             :     //    throw cppthread_exception_not_locked_once_error();
     470             :     //}
     471           0 :     int const err(pthread_cond_wait(&f_impl->f_condition, &f_impl->f_mutex));
     472           0 :     if(err != 0)
     473             :     {
     474             :         // an error occurred!
     475           0 :         log << log_level_t::fatal
     476           0 :             << "a mutex conditional wait generated error #"
     477           0 :             << err
     478           0 :             << " -- "
     479           0 :             << strerror(err)
     480           0 :             << end;
     481           0 :         throw cppthread_mutex_failed_error("pthread_cond_wait() failed");
     482             :     }
     483           0 : }
     484             : 
     485             : 
     486             : /** \brief Wait on a mutex condition with a time limit.
     487             :  *
     488             :  * At times it is useful to wait on a mutex to become available without
     489             :  * polling the mutex, but only for some time. This function waits for
     490             :  * the number of specified micro seconds. The function returns early if
     491             :  * the condition was triggered. Otherwise it waits until the specified
     492             :  * number of micro seconds elapsed and then returns.
     493             :  *
     494             :  * \warning
     495             :  * This function cannot be called if the mutex is not locked or the
     496             :  * wait will fail in unpredictable ways.
     497             :  *
     498             :  * \exception cppthread_exception_system_error
     499             :  * This exception is raised if a function returns an unexpected error.
     500             :  *
     501             :  * \exception cppthread_exception_mutex_failed_error
     502             :  * This exception is raised when the mutex wait function fails.
     503             :  *
     504             :  * \param[in] usecs  The maximum number of micro seconds to wait until you
     505             :  *                   receive the signal.
     506             :  *
     507             :  * \return true if the condition was raised, false if the wait timed out.
     508             :  */
     509           0 : bool mutex::timed_wait(uint64_t const usecs)
     510             : {
     511             :     // For any mutex wait to work, we MUST have the
     512             :     // mutex locked already and just one time.
     513             :     //
     514             :     // note: the 1 time is just for assurance that it will
     515             :     //       work in most cases; it should work even when locked
     516             :     //       multiple times, but it is less likely. For sure, it
     517             :     //       has to be at least once.
     518             :     //if(f_reference_count != 1UL)
     519             :     //{
     520             :     //  log << log_level_t::fatal
     521             :     //         << "attempting to timed wait "
     522             :     //         << usec
     523             :     //         << " usec on a mutex when it is not locked exactly once, current count is "
     524             :     //         << f_reference_count
     525             :     //         << end;
     526             :     //    throw cppthread_exception_not_locked_once_error();
     527             :     //}
     528             : 
     529           0 :     int err(0);
     530             : 
     531             :     // get time now
     532           0 :     struct timespec abstime;
     533           0 :     if(clock_gettime(CLOCK_REALTIME, &abstime) != 0)
     534             :     {
     535           0 :         err = errno;
     536           0 :         log << log_level_t::fatal
     537           0 :             << "gettimeofday() failed with errno: "
     538           0 :             << err
     539           0 :             << " -- "
     540           0 :             << strerror(err)
     541           0 :             << end;
     542           0 :         throw cppthread_system_error("gettimeofday() failed");
     543             :     }
     544             : 
     545             :     // now + user specified usec
     546           0 :     abstime.tv_sec += usecs / 1'000'000ULL;
     547           0 :     std::uint64_t nanos(abstime.tv_nsec + (usecs % 1'000'000ULL) * 1'000ULL);
     548           0 :     if(nanos > 1'000'000'000ULL)
     549             :     {
     550           0 :         ++abstime.tv_sec;
     551           0 :         nanos -= 1'000'000'000ULL;
     552             :     }
     553           0 :     abstime.tv_nsec = static_cast<long>(nanos);
     554             : 
     555           0 :     err = pthread_cond_timedwait(&f_impl->f_condition, &f_impl->f_mutex, &abstime);
     556           0 :     if(err != 0)
     557             :     {
     558           0 :         if(err == ETIMEDOUT)
     559             :         {
     560           0 :             return false;
     561             :         }
     562             : 
     563             :         // an error occurred!
     564           0 :         log << log_level_t::fatal
     565           0 :             << "a mutex conditional timed wait generated error #"
     566           0 :             << err
     567           0 :             << " -- "
     568           0 :             << strerror(err)
     569           0 :             << " (time out sec = "
     570           0 :             << abstime.tv_sec
     571           0 :             << ", nsec = "
     572           0 :             << abstime.tv_nsec
     573           0 :             << ")"
     574           0 :             << end;
     575           0 :         throw cppthread_mutex_failed_error("pthread_cond_timedwait() failed");
     576             :     }
     577             : 
     578           0 :     return true;
     579             : }
     580             : 
     581             : 
     582             : /** \brief Wait on a mutex until the specified date.
     583             :  *
     584             :  * This function waits on the mutex condition to be signaled up until the
     585             :  * specified date is passed.
     586             :  *
     587             :  * \warning
     588             :  * This function cannot be called if the mutex is not locked or the
     589             :  * wait will fail in unpredictable ways.
     590             :  *
     591             :  * \exception cppthread_exception_mutex_failed_error
     592             :  * This exception is raised whenever the thread wait function fails.
     593             :  *
     594             :  * \param[in] usec  The date when the mutex times out in microseconds.
     595             :  *
     596             :  * \return true if the condition occurs before the function times out,
     597             :  *         false if the function times out.
     598             :  */
     599           0 : bool mutex::dated_wait(uint64_t usec)
     600             : {
     601             :     // For any mutex wait to work, we MUST have the
     602             :     // mutex locked already and just one time.
     603             :     //
     604             :     // note: the 1 time is just for assurance that it will
     605             :     //       work in most cases; it should work even when locked
     606             :     //       multiple times, but it is less likely. For sure, it
     607             :     //       has to be at least once.
     608             :     //if(f_reference_count != 1UL)
     609             :     //{
     610             :     //    log << log_level_t::fatal
     611             :     //        << "attempting to dated wait until "
     612             :     //        << usec
     613             :     //        << " msec on a mutex when it is not locked exactly once, current count is "
     614             :     //        << f_reference_count
     615             :     //        << end;
     616             :     //    throw cppthread_exception_not_locked_once_error();
     617             :     //}
     618             : 
     619             :     // setup the timeout date
     620           0 :     struct timespec timeout;
     621           0 :     timeout.tv_sec = static_cast<long>(usec / 1000000ULL);
     622           0 :     timeout.tv_nsec = static_cast<long>((usec % 1000000ULL) * 1000ULL);
     623             : 
     624           0 :     int const err(pthread_cond_timedwait(&f_impl->f_condition, &f_impl->f_mutex, &timeout));
     625           0 :     if(err != 0)
     626             :     {
     627           0 :         if(err == ETIMEDOUT)
     628             :         {
     629           0 :             return false;
     630             :         }
     631             : 
     632             :         // an error occurred!
     633           0 :         log << log_level_t::error
     634           0 :             << "a mutex conditional dated wait generated error #"
     635           0 :             << err
     636           0 :             << " -- "
     637           0 :             << strerror(err)
     638           0 :             << end;
     639           0 :         throw cppthread_mutex_failed_error("pthread_cond_timedwait() failed");
     640             :     }
     641             : 
     642           0 :     return true;
     643             : }
     644             : 
     645             : 
     646             : /** \brief Signal at least one mutex.
     647             :  *
     648             :  * Our mutexes include a condition that get signaled by calling this
     649             :  * function. This function wakes up one or more listening threads.
     650             :  *
     651             :  * The function does not lock the mutext before sending the signal. This
     652             :  * is useful if you already are in a guarded block or you do not mind
     653             :  * waking up more than one thread as a result of the call.
     654             :  *
     655             :  * \note
     656             :  * If you need to wake up exactly one other thread, then make sure to
     657             :  * use the safe_signal() function instead.
     658             :  *
     659             :  * \exception cppthread_exception_invalid_error
     660             :  * If one of the pthread system functions return an error, the function
     661             :  * raises this exception.
     662             :  *
     663             :  * \sa safe_signal()
     664             :  */
     665          32 : void mutex::signal()
     666             : {
     667          32 :     int const err(pthread_cond_signal(&f_impl->f_condition));
     668          32 :     if(err != 0)
     669             :     {
     670           0 :         log << log_level_t::fatal
     671           0 :             << "a mutex condition signal generated error #"
     672           0 :             << err
     673           0 :             << end;
     674           0 :         throw cppthread_invalid_error("pthread_cond_signal() failed");
     675             :     }
     676          32 : }
     677             : 
     678             : 
     679             : /** \brief Signal a mutex.
     680             :  *
     681             :  * Our mutexes include a condition that get signaled by calling this
     682             :  * function. This function wakes up one listening thread.
     683             :  *
     684             :  * The function ensures that the mutex is locked before sending
     685             :  * the signal so you do not have to lock the mutex yourself.
     686             :  *
     687             :  * \exception cppthread_exception_invalid_error
     688             :  * If one of the pthread system functions return an error, the function
     689             :  * raises this exception.
     690             :  *
     691             :  * \sa signal()
     692             :  */
     693           0 : void mutex::safe_signal()
     694             : {
     695           0 :     guard lock(*this);
     696             : 
     697           0 :     int const err(pthread_cond_signal(&f_impl->f_condition));
     698           0 :     if(err != 0)
     699             :     {
     700           0 :         log << log_level_t::fatal
     701           0 :             << "a mutex condition signal generated error #"
     702           0 :             << err
     703           0 :             << end;
     704           0 :         throw cppthread_invalid_error("pthread_cond_signal() failed");
     705             :     }
     706           0 : }
     707             : 
     708             : 
     709             : /** \brief Broadcast a mutex signal.
     710             :  *
     711             :  * Our mutexes include a condition that get signaled by calling this
     712             :  * function. This function actually signals all the threads that are
     713             :  * currently listening to the mutex signal. The order in which the
     714             :  * threads get awaken is unspecified.
     715             :  *
     716             :  * The function ensures that the mutex is locked before broadcasting
     717             :  * the signal so you do not have to lock the mutex yourself. Note that
     718             :  * is not required to lock a mutex before broadcasting a signal. The
     719             :  * effects are similar.
     720             :  *
     721             :  * \exception cppthread_exception_invalid_error
     722             :  * If one of the pthread system functions return an error, the function
     723             :  * raises this exception.
     724             :  *
     725             :  * \sa broadcast()
     726             :  */
     727           0 : void mutex::safe_broadcast()
     728             : {
     729           0 :     guard lock(*this);
     730             : 
     731           0 :     int const err(pthread_cond_broadcast(&f_impl->f_condition));
     732           0 :     if(err != 0)
     733             :     {
     734           0 :         log << log_level_t::fatal
     735           0 :             << "a mutex signal broadcast generated error #"
     736           0 :             << err
     737           0 :             << end;
     738           0 :         throw cppthread_invalid_error("pthread_cond_broadcast() failed");
     739             :     }
     740           0 : }
     741             : 
     742             : 
     743             : /** \brief Broadcast a mutex signal.
     744             :  *
     745             :  * Our mutexes include a condition that get signaled by calling this
     746             :  * function. This function actually signals all the threads that are
     747             :  * currently listening to the mutex signal. The order in which the
     748             :  * threads get awaken is unspecified.
     749             :  *
     750             :  * The function ensures that the mutex is locked before broadcasting
     751             :  * the signal so you do not have to lock the mutex yourself.
     752             :  *
     753             :  * \note
     754             :  * We also offer a safe_broadcast(). If you expect absolutely all the
     755             :  * other threads to receive the signal, then make sure to use the
     756             :  * safe_broadcast() function instead. However, if you are already in
     757             :  * a guarded block, then there is no need for an additional lock and
     758             :  * this function will work exactly as expected.
     759             :  *
     760             :  * \exception cppthread_exception_invalid_error
     761             :  * If one of the pthread system functions return an error, the function
     762             :  * raises this exception.
     763             :  *
     764             :  * \sa safe_broadcast()
     765             :  */
     766           0 : void mutex::broadcast()
     767             : {
     768           0 :     guard lock(*this);
     769             : 
     770           0 :     int const err(pthread_cond_broadcast(&f_impl->f_condition));
     771           0 :     if(err != 0)
     772             :     {
     773           0 :         log << log_level_t::fatal
     774           0 :             << "a mutex signal broadcast generated error #"
     775           0 :             << err
     776           0 :             << end;
     777           0 :         throw cppthread_invalid_error("pthread_cond_broadcast() failed");
     778             :     }
     779           0 : }
     780             : 
     781             : 
     782             : /** \brief The system mutex.
     783             :  *
     784             :  * This mutex is created and initialized whenever this library is
     785             :  * loaded. This means it will always be ready for any library
     786             :  * that depends on the cppthread library.
     787             :  *
     788             :  * It should be used for things that may happen at any time and
     789             :  * require to be done by one thread at a time. For example, a
     790             :  * class with a get_instance() may want to lock this mutex, do
     791             :  * it's instance creation and then unlock the mutex.
     792             :  *
     793             :  * The mutex locking should be done using the guard class.
     794             :  *
     795             :  * \code
     796             :  *     ptr * get_instance()
     797             :  *     {
     798             :  *         cppthread::guard lock(*g_system_mutex);
     799             :  *
     800             :  *         ...proceed with your instance allocation...
     801             :  *     }
     802             :  * \endcode
     803             :  *
     804             :  * Because of the order in which things get initialized under
     805             :  * Linux, you can be sure that this mutex will be ready for
     806             :  * use as soon as the cppthread is loaded. So you can even
     807             :  * use it in your own C++ initialization (i.e. your global
     808             :  * objects.)
     809             :  *
     810             :  * Obviously, if you also have your own mutex, you need to
     811             :  * initialize it and therefore you may have problems in
     812             :  * your initialization process (i.e. your C++ globals may
     813             :  * not get initialized in the correct order--the mutex may
     814             :  * get initialized after your other parameters...)
     815             :  */
     816             : mutex *         g_system_mutex = nullptr;
     817             : 
     818             : 
     819             : /** \brief This is an internal function called by the logger constructor.
     820             :  *
     821             :  * The logger constructor is called whenever the cppthread library is loaded
     822             :  * and that happens in your main thread at initialization time. This means
     823             :  * any of your code can access the g_system_mutex as required.
     824             :  *
     825             :  * This function is not defined externally so that other users can't call
     826             :  * it from the outside (there would be no need anyway). Just in case, if
     827             :  * called a second time, the function writes an error message and fails
     828             :  * with a call to std::terminate().
     829             :  *
     830             :  * Another way to safely create a new mutex is to use a static variable
     831             :  * in a function. The initialization of that static variable will always
     832             :  * be safe so that mutex will be available to all your threads even if
     833             :  * you already had multiple threads the first time that function was called.
     834             :  *
     835             :  * \code
     836             :  *     void myfunc()
     837             :  *     {
     838             :  *         static cppthread::mutex m = cppthread::mutex();
     839             :  *
     840             :  *         // here "m" is a safe to use mutex
     841             :  *         cppthread::guard lock(m);
     842             :  *
     843             :  *         ...do atomic work here...
     844             :  *     }
     845             :  * \endcode
     846             :  *
     847             :  * You could even create a function which returns a reference to that
     848             :  * local mutex (just make sure you don't copy that mutex).
     849             :  *
     850             :  * \note
     851             :  * Although this function gets called from the logger contructor, it is not
     852             :  * used by the logger at all.
     853             :  */
     854           2 : void create_system_mutex()
     855             : {
     856           2 :     if(g_system_mutex != nullptr)
     857             :     {
     858           0 :         std::cerr << "fatal: create_system_mutex() called twice." << std::endl;
     859           0 :         std::terminate();
     860             :     }
     861             : 
     862           2 :     g_system_mutex = new mutex;
     863           2 : }
     864             : 
     865             : 
     866             : 
     867             : 
     868             : /** \typedef mutex::pointer_t
     869             :  * \brief Shared pointer to a mutex.
     870             :  *
     871             :  * You can allocate mutexes as global variables, local variables, variable
     872             :  * members and once in a while you  may want to allocate them. In that
     873             :  * case, we suggest that you use a shared pointer.
     874             :  */
     875             : 
     876             : 
     877             : /** \typedef mutex::vector_t
     878             :  * \brief A vector of mutexes.
     879             :  *
     880             :  * This type defines a vector that can be used to manage mutexes. In
     881             :  * this case, the mutexes must be allocated.
     882             :  */
     883             : 
     884             : 
     885             : /** \typedef mutex::direct_vector_t
     886             :  * \brief A vector of mutexes.
     887             :  *
     888             :  * This type defines a vector of direct mutexes (i.e. not pointers to
     889             :  * mutexes). This type can be used when you know the number of mutexes
     890             :  * to allocate. Dynamically adding/removing mutexes with this type
     891             :  * can be rather complicated.
     892             :  */
     893             : 
     894             : 
     895             : /** \var mutex::f_impl
     896             :  * \brief The pthread mutex implementation.
     897             :  *
     898             :  * This variable member holds the actual pthread mutex. The mutex
     899             :  * implementation manages this field as required.
     900             :  */
     901             : 
     902             : 
     903             : /** \var mutex::f_reference_count
     904             :  * \brief The lock reference count.
     905             :  *
     906             :  * The mutex tracks the number of times the mutex gets locked.
     907             :  * In the end, the lock reference must be zero for the mutex
     908             :  * to be properly destroyed.
     909             :  */
     910             : 
     911             : 
     912             : 
     913             : 
     914           6 : } // namespace cppthread
     915             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13