interruptible_barrier.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <core/threading/interruptible_barrier.h>
00025 #include <core/threading/thread_list.h>
00026 #include <core/exceptions/system.h>
00027 #include <core/macros.h>
00028
00029 #include <core/threading/mutex.h>
00030 #include <core/threading/wait_condition.h>
00031
00032 namespace fawkes {
00033 #if 0
00034 }
00035 #endif
00036
00037
00038
00039 class InterruptibleBarrierData
00040 {
00041 public:
00042 unsigned int threads_left;
00043 Mutex *mutex;
00044 WaitCondition *waitcond;
00045 bool own_mutex;
00046
00047 InterruptibleBarrierData(Mutex *mutex)
00048 {
00049 if (mutex) {
00050 this->mutex = mutex;
00051 own_mutex = false;
00052 } else {
00053 this->mutex = new Mutex();
00054 own_mutex = true;
00055 }
00056 waitcond = new WaitCondition(this->mutex);
00057 }
00058
00059 ~InterruptibleBarrierData()
00060 {
00061 if (own_mutex) delete mutex;
00062 delete waitcond;
00063 }
00064 };
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 InterruptibleBarrier::InterruptibleBarrier(unsigned int count)
00091 : Barrier()
00092 {
00093 _count = count;
00094 if ( _count == 0 ) {
00095 throw Exception("Barrier count must be at least 1");
00096 }
00097 __data = new InterruptibleBarrierData(NULL);
00098 __data->threads_left = 0;
00099 __passed_threads = RefPtr<ThreadList>(new ThreadList());
00100
00101 __interrupted = false;
00102 __timeout = false;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 InterruptibleBarrier::InterruptibleBarrier(Mutex *mutex, unsigned int count)
00115 : Barrier()
00116 {
00117 _count = count;
00118 if ( _count == 0 ) {
00119 throw Exception("Barrier count must be at least 1");
00120 }
00121 __data = new InterruptibleBarrierData(mutex);
00122 __data->threads_left = 0;
00123 __passed_threads = RefPtr<ThreadList>(new ThreadList());
00124
00125 __interrupted = false;
00126 __timeout = false;
00127 }
00128
00129
00130 InterruptibleBarrier::~InterruptibleBarrier()
00131 {
00132 delete __data;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142 RefPtr<ThreadList>
00143 InterruptibleBarrier::passed_threads()
00144 {
00145 return __passed_threads;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155 void
00156 InterruptibleBarrier::interrupt() throw()
00157 {
00158 if (likely(__data->own_mutex)) __data->mutex->lock();
00159 __interrupted = true;
00160 __data->waitcond->wake_all();
00161 if (likely(__data->own_mutex)) __data->mutex->unlock();
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 void
00171 InterruptibleBarrier::reset() throw()
00172 {
00173 if (likely(__data->own_mutex)) __data->mutex->lock();
00174 __interrupted = false;
00175 __timeout = false;
00176 __data->threads_left = _count;
00177 __passed_threads.clear();
00178 if (likely(__data->own_mutex)) __data->mutex->unlock();
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 bool
00196 InterruptibleBarrier::wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
00197 {
00198 if (likely(__data->own_mutex)) __data->mutex->lock();
00199
00200 if ( __data->threads_left == 0 ) {
00201
00202 __timeout = __interrupted = false;
00203 __data->threads_left = _count;
00204 __passed_threads->clear();
00205 } else {
00206 if ( __interrupted || __timeout ) {
00207
00208 if (likely(__data->own_mutex)) __data->mutex->unlock();
00209 return true;
00210 }
00211 }
00212 --__data->threads_left;
00213 try {
00214 __passed_threads->push_back_locked(Thread::current_thread());
00215 } catch (Exception &e) {
00216
00217
00218 e.print_trace();
00219 }
00220
00221 bool local_timeout = false;
00222 while ( __data->threads_left && !__interrupted && !__timeout && ! local_timeout) {
00223 local_timeout = ! __data->waitcond->reltimed_wait(timeout_sec, timeout_nanosec);
00224 }
00225 if (local_timeout) __timeout = true;
00226 if ( __interrupted ) {
00227 if (likely(__data->own_mutex)) __data->mutex->unlock();
00228 throw InterruptedException("InterruptibleBarrier forcefully interrupted, only "
00229 "%u of %u threads reached the barrier",
00230 _count - __data->threads_left, _count);
00231 }
00232
00233 __data->waitcond->wake_all();
00234 if (likely(__data->own_mutex)) __data->mutex->unlock();
00235
00236 return ! __timeout;
00237 }
00238
00239 }