spinlock.cpp

00001 
00002 /***************************************************************************
00003  *  spinlock.h - Spinlock
00004  *
00005  *  Created: Wed Apr 02 13:20:31 2008
00006  *  Copyright  2006-2008  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/spinlock.h>
00025 #include <core/threading/thread.h>
00026 #include <core/exception.h>
00027 
00028 #include <pthread.h>
00029 #include <unistd.h>
00030 
00031 // cf. http://people.redhat.com/drepper/posix-option-groups.html
00032 #if defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS - 200112L) >= 0
00033 #  define USE_POSIX_SPIN_LOCKS
00034 #else
00035 #  undef USE_POSIX_SPIN_LOCKS
00036 #  include <core/threading/mutex.h>
00037 #endif
00038 
00039 namespace fawkes {
00040 
00041 /** @class Spinlock <core/threading/spinlock.h>
00042  * Spin lock.
00043  * This class is similar to a Mutex in that it is used in a multi-threading
00044  * environment to lock access to resources.
00045  *
00046  * The difference is that the spinlock will do a busy waiting until it acquires
00047  * the lock while the mutex would block and wait, and may even starve if another
00048  * threads releases a lock only for a short period of time.
00049  *
00050  * Spinlocks are risky, priority inversion may be caused if used improperly.
00051  * Be sure what you are doing if you use spinlocks.
00052  *
00053  * @ingroup Threading
00054  * @ingroup FCL
00055  *
00056  * @author Tim Niemueller
00057  */
00058 
00059 /// @cond INTERNALS
00060 class SpinlockData
00061 {
00062  public:
00063 #ifdef USE_POSIX_SPIN_LOCKS
00064   pthread_spinlock_t spinlock;
00065 #else
00066   Mutex              mutex;
00067 #endif
00068 };
00069 /// @endcond
00070 
00071 
00072 /** Constructor */
00073 Spinlock::Spinlock()
00074 {
00075   spinlock_data = new SpinlockData();
00076 #ifdef USE_POSIX_SPIN_LOCKS
00077   pthread_spin_init(&(spinlock_data->spinlock), PTHREAD_PROCESS_PRIVATE);
00078 #endif
00079 }
00080 
00081 /** Destructor */
00082 Spinlock::~Spinlock()
00083 {
00084 #ifdef USE_POSIX_SPIN_LOCKS
00085   pthread_spin_destroy(&(spinlock_data->spinlock));
00086 #endif
00087   delete spinlock_data;
00088   spinlock_data = NULL;
00089 }
00090 
00091 
00092 /** Lock this spinlock.
00093  * A call to lock() will block until the lock on the spinlock could be aquired.
00094  * If you want to avoid see consider using try_lock().
00095  */
00096 void
00097 Spinlock::lock()
00098 {
00099 #ifdef USE_POSIX_SPIN_LOCKS
00100   int err = 0;
00101   if ( (err = pthread_spin_lock(&(spinlock_data->spinlock))) != 0 ) {
00102     throw Exception(err, "Failed to aquire lock for thread %s", Thread::current_thread()->name());
00103   }
00104 #else
00105   bool locked = false;
00106   while ( ! locked ) {
00107     locked = spinlock_data->mutex.try_lock();
00108   }
00109 #endif
00110 }
00111 
00112 
00113 /** Tries to lock the spinlock.
00114  * This can also be used to check if a spinlock is locked. The code for this
00115  * can be:
00116  *
00117  * @code
00118  * bool locked = false;
00119  * if ( spinlock->try_lock() ) {
00120  *   spinlock->unlock();
00121  *   locked = true;
00122  * }
00123  * @endcode
00124  *
00125  * This cannot be implemented in Spinlock in a locked() method since this
00126  * would lead to race conditions in many situations.
00127  *
00128  * @return true, if the spinlock could be locked, false otherwise.
00129  */
00130 bool
00131 Spinlock::try_lock()
00132 {
00133 #ifdef USE_POSIX_SPIN_LOCKS
00134   if (pthread_spin_trylock(&(spinlock_data->spinlock)) == 0) {
00135     return true;
00136   } else {
00137     return false;
00138   }
00139 #else
00140   return spinlock_data->mutex.try_lock();
00141 #endif
00142 }
00143 
00144 
00145 /** Unlock the spinlock. */
00146 void
00147 Spinlock::unlock()
00148 {
00149 #ifdef USE_POSIX_SPIN_LOCKS
00150   pthread_spin_unlock(&(spinlock_data->spinlock));
00151 #else
00152   spinlock_data->mutex.unlock();
00153 #endif
00154 }
00155 
00156 
00157 } // end namespace fawkes

Generated on Tue Feb 22 13:32:26 2011 for Fawkes API by  doxygen 1.4.7