Fawkes API  Fawkes Development Version
wait_condition.cpp
00001 
00002 /***************************************************************************
00003  *  wait_condition.cpp - condition variable implementation
00004  *
00005  *  Created: Thu Sep 14 21:43:30 2006
00006  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program 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 Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <core/threading/wait_condition.h>
00025 #include <core/threading/mutex.h>
00026 #include <core/threading/mutex_data.h>
00027 #include <core/exception.h>
00028 
00029 #include <pthread.h>
00030 #include <cerrno>
00031 #if defined(__MACH__) && defined(__APPLE__)
00032 #  include <sys/time.h>
00033 #endif
00034 
00035 namespace fawkes {
00036 
00037 /// @cond INTERNALS
00038 class WaitConditionData
00039 {
00040  public:
00041   pthread_cond_t cond;
00042 };
00043 /// @endcond
00044 
00045 
00046 /** @class WaitCondition <core/threading/wait_condition.h>
00047  * Wait until a given condition holds.
00048  * Consider two values x and y and you want to wait until they are equal.
00049  * For instance there may be a thread counting up after he has finished one
00050  * particular job before he goes to handle the next one. After 10 threads you
00051  * want to send out the produced entities in one batch run. So the sending
00052  * thread has to wait for the producing thread until 10 packages have been
00053  * produced. Simplified this could be implemented as
00054  *
00055  * @code
00056  * virtual void run()
00057  * {
00058  *   forever {
00059  *     mutex->lock();
00060  *     while (count != 10) {
00061  *       wait_condition->wait();
00062  *     }
00063  *   }
00064  * }
00065  * @endcode
00066  *
00067  * The other thread will wake up this waiting thread after each produced
00068  * package (the thread does not have to know after how many packages they are
00069  * sent out). The code could look like this:
00070  *
00071  * @code
00072  * virtual void run()
00073  * {
00074  *   forever {
00075  *     produce_package();
00076  *     wait_condition->wake_one();
00077  *   }
00078  * }
00079  * @endcode
00080  *
00081  * The WaitCondition can operate in two principal modes, either with an internal
00082  * or with an external Mutex. If no mutex is passed to the constructor an
00083  * internal mutex is created and used. If a mutex is passed this instance is used,
00084  * but ownership is not claimed and you have to delete it manually. Additionally,
00085  * for external mutexes they are <i>never</i> locked by the wait condition. For
00086  * external mutexes you get all the freedom, but also have the duty to ensure
00087  * proper locking from the outside! This applies to wait and wake methods.
00088  *
00089  * @ingroup Threading
00090  * @ingroup FCL
00091  * @see Mutex
00092  * @see qa_waitcond_serialize.cpp
00093  * @see qa_waitcond.cpp
00094  *
00095  * @author Tim Niemueller
00096  *
00097  */
00098 
00099 
00100 /** Constructor.
00101  * @param mutex the mutex used for this wait condition. If none is given, an
00102  * internal mutex will be created and used.
00103  */
00104 WaitCondition::WaitCondition(Mutex *mutex)
00105 {
00106   __cond_data   = new WaitConditionData();
00107   pthread_cond_init( &(__cond_data->cond), NULL);
00108   if (mutex) {
00109     __mutex     = mutex;
00110     __own_mutex = false;
00111   } else {
00112     __mutex     = new Mutex();
00113     __own_mutex = true;
00114   }
00115 }
00116 
00117 
00118 /** Destructor. */
00119 WaitCondition::~WaitCondition()
00120 {
00121   pthread_cond_destroy( &(__cond_data->cond) );
00122   delete __cond_data;
00123   if (__own_mutex) {
00124     delete __mutex;
00125   }
00126 }
00127 
00128 
00129 /** Wait for the condition forever.
00130  * This waits forever until a wakup signal is received by another thread calling
00131  * wake_all() or wake_one(). If an external mutex is used it must be locked or
00132  * before calling wait() or the result is undefined. After the method returns
00133  * the mutex is locked again.
00134  */
00135 void
00136 WaitCondition::wait()
00137 {
00138   int err;
00139   if ( __own_mutex) {
00140     __mutex->lock();
00141     err = pthread_cond_wait( &(__cond_data->cond), &(__mutex->mutex_data->mutex) );
00142     __mutex->unlock();
00143   } else {
00144     err = pthread_cond_wait( &(__cond_data->cond), &(__mutex->mutex_data->mutex) );
00145   }
00146   if ( err != 0 ) {
00147     throw Exception(err, "Waiting for wait condition failed");
00148   }
00149 }
00150 
00151 
00152 /** Wait with absolute timeout.
00153  * This waits for the given mutex until either a wakup signal is received or
00154  * the timeout has passed. The timeout has to be given in absolute system time,
00155  * a simulated clock source cannot be used.
00156  * @param sec Seconds of absolute time since the epoch (value compatible to
00157  * timeval tv_sec part is sufficient).
00158  * @param nanosec Nanoseconds part of the absolute timeout. Added to the seconds
00159  * part.
00160  * @return true, if the thread was woken up by another thread calling
00161  * wake_one() or wake_all(), false otherwise if the timeout has been reached
00162  * @exception Exception thrown if another error occurs for the POSIX wait condition
00163  */
00164 bool
00165 WaitCondition::abstimed_wait(long int sec, long int nanosec)
00166 {
00167   int err = 0;
00168   struct timespec ts = { sec, nanosec };
00169 
00170   if ( __own_mutex) {
00171     __mutex->lock();
00172     err = pthread_cond_timedwait( &(__cond_data->cond), &(__mutex->mutex_data->mutex), &ts );
00173     __mutex->unlock();
00174   } else {
00175     err = pthread_cond_timedwait( &(__cond_data->cond), &(__mutex->mutex_data->mutex), &ts );
00176   }
00177 
00178   if ( err == ETIMEDOUT ) {
00179     return false;
00180   } else if ( err != 0 ) {
00181     // some other error happened, a "real" error
00182     throw Exception(err, "Waiting for wait condition failed");
00183   } else {
00184     return true;
00185   }
00186 }
00187 
00188 
00189 /** Wait with relative timeout.
00190  * This waits for the given mutex until either a wakup signal is received or
00191  * the timeout has passed. The timeout has to be given in relative system time.
00192  * It is added to the current time and is then used similar to abstime_wait().
00193  * A timeout of (0,0) will cause this method to wait forever, similar to wait().
00194  * @param sec Number of seconds to wait
00195  * @param nanosec Number of nanoseconds to wait, added to seconds value
00196  * @return true, if the thread was woken up by another thread calling
00197  * wake_one() or wake_all(), false otherwise if the timeout has been reached
00198  * @exception Exception thrown if another error occurs for the POSIX wait condition
00199  */
00200 bool
00201 WaitCondition::reltimed_wait(unsigned int sec, unsigned int nanosec)
00202 {
00203   if ( ! (sec || nanosec) ) {
00204     wait();
00205     return true;
00206   } else {
00207     struct timespec now;
00208 #if defined(__MACH__) && defined(__APPLE__)
00209     struct timeval nowt;
00210     if ( gettimeofday(&nowt, NULL) != 0 ) {
00211       throw Exception(errno, "WaitCondition::reltimed_wait: Failed to get current time");
00212     }
00213     now.tv_sec  = nowt.tv_sec;
00214     now.tv_nsec = nowt.tv_usec * 1000;
00215 #else
00216     if ( clock_gettime(CLOCK_REALTIME, &now) != 0 ) {
00217       throw Exception(errno, "WaitCondition::reltimed_wait: Failed to get current time");
00218     }
00219 #endif
00220 
00221     long int s  = now.tv_sec  + sec;
00222     long int ns = now.tv_nsec + nanosec;
00223     if (ns >= 1000000000) {
00224       s  += 1;
00225       ns -= 1000000000;
00226     }
00227 
00228     struct timespec ts = { s, ns };
00229     long err = 0;
00230 
00231     if ( __own_mutex) {
00232       __mutex->lock();
00233       err = pthread_cond_timedwait( &(__cond_data->cond), &(__mutex->mutex_data->mutex), &ts );
00234       __mutex->unlock();
00235     } else {
00236       err = pthread_cond_timedwait( &(__cond_data->cond), &(__mutex->mutex_data->mutex), &ts );
00237     }
00238 
00239     if ( err == ETIMEDOUT ) {
00240       return false;
00241     } else if ( err != 0 ) {
00242       // some other error happened, a "real" error
00243       throw Exception(err, "Waiting for wait condition failed");
00244     } else {
00245       return true;
00246     }
00247   }
00248 }
00249 
00250 
00251 /** Wake another thread waiting for this condition.
00252  * This wakes up any thread waiting for the condition, not a particular one.
00253  * No guarantee is given about the order of the woken up threads.
00254  * Note: If the internal mutex is used for this wait/wakeup cycle, the lock
00255  * to this mutex will be acquired during the wakeup, to ensure that all waiting
00256  * threads are woken up, even if a call to wait() and wake_one() overlapped.
00257  * If however, an external Mutex is used, you must ensure by yourself that it
00258  * is properly locked during the wakeup to ensure this.
00259  */
00260 void
00261 WaitCondition::wake_one()
00262 {
00263   if (__own_mutex) {  // it's our internal mutex, lock!
00264     __mutex->lock();
00265     pthread_cond_signal( &(__cond_data->cond) );
00266     __mutex->unlock();
00267   } else {            // it's an external mutex, the user should care
00268     pthread_cond_signal( &(__cond_data->cond) );
00269   }
00270 }
00271 
00272 
00273 /** Wake up all waiting threads.
00274  * This wakes up all threads waiting for this condition.
00275  * Note: If the internal mutex is used for this wait/wakeup cycle, the lock
00276  * to this mutex will be acquired during the wakeup, to ensure that all waiting
00277  * threads are woken up, even if a call to wait() and wake_one() overlapped.
00278  * If however, an external Mutex is used, you must ensure by yourself that it
00279  * is properly locked during the wakeup to ensure this.
00280  */
00281 void
00282 WaitCondition::wake_all()
00283 {
00284   if (__own_mutex) {  // it's our internal mutex, lock!
00285     __mutex->lock();
00286     pthread_cond_broadcast( &(__cond_data->cond) );
00287     __mutex->unlock();
00288   } else {            // it's an external mutex, the user should care
00289     pthread_cond_broadcast( &(__cond_data->cond) );
00290   }
00291 }
00292 
00293 
00294 } // end namespace fawkes