Fawkes API
Fawkes Development Version
|
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