Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * thread_list.cpp - Thread list 00004 * 00005 * Created: Tue Oct 31 18:20:59 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/thread_list.h> 00025 #include <core/threading/thread.h> 00026 #include <core/threading/mutex.h> 00027 #include <core/threading/mutex_locker.h> 00028 #include <core/threading/barrier.h> 00029 #include <core/threading/interruptible_barrier.h> 00030 #include <core/exceptions/software.h> 00031 #include <core/exceptions/system.h> 00032 00033 #include <string> 00034 #include <cstring> 00035 #include <cstdlib> 00036 #include <cstdio> 00037 #include <unistd.h> 00038 00039 namespace fawkes { 00040 00041 /** @class ThreadListSealedException <core/threading/thread_list.h> 00042 * Thread list sealed exception. 00043 * This exception is thrown whenever you execute an action that would 00044 * modify the thread list like adding or removing elements on a 00045 * sealed list. A list can only be sealed and never be unsealed afterwards. 00046 * This exception is meant to be only thrown by ThreadList. 00047 * @author Tim Niemueller 00048 */ 00049 00050 /** Constructor. 00051 * @param operation operation that failed 00052 */ 00053 ThreadListSealedException::ThreadListSealedException(const char *operation) 00054 : Exception("ThreadList is sealed") 00055 { 00056 append("Operation '%s' is not allowed on a sealed thread list", operation); 00057 } 00058 00059 00060 /** @class ThreadListNotSealedException <core/threading/thread_list.h> 00061 * Thread list not sealed exception. 00062 * This exception is thrown whenever the thread list is given to some 00063 * method that expects a sealed list (probably because it sealed the 00064 * list by itself). 00065 * This exception is meant to be only thrown by users of ThreadList. 00066 * @author Tim Niemueller 00067 */ 00068 00069 /** Constructor. 00070 * @param format format of message 00071 */ 00072 ThreadListNotSealedException::ThreadListNotSealedException(const char *format, ...) 00073 : Exception() 00074 { 00075 va_list va; 00076 va_start(va, format); 00077 append_va(format, va); 00078 va_end(va); 00079 } 00080 00081 /** @class ThreadList <core/threading/thread_list.h> 00082 * List of threads. 00083 * This is a list of threads derived from stl::list. It features special 00084 * wakeup methods that will wakeup all threads in the list. The list can 00085 * and must be locked in iterator operations and when adding or deleting 00086 * elements from the list. 00087 * @author Tim Niemueller 00088 */ 00089 00090 /** Constructor. 00091 * @param tlname optional name which is used for better readable error 00092 * messages. 00093 */ 00094 ThreadList::ThreadList(const char *tlname) 00095 { 00096 __name = strdup(tlname); 00097 __sealed = false; 00098 __finalize_mutex = new Mutex(); 00099 __wnw_barrier = NULL; 00100 clear(); 00101 } 00102 00103 00104 /** Constructor. 00105 * @param maintain_barrier if true, an internal barrier is maintained during add and 00106 * remove operations such that wakeup_and_wait() can be used. 00107 * @param tlname optional name which is used for better readable error 00108 * messages. 00109 */ 00110 ThreadList::ThreadList(bool maintain_barrier, const char *tlname) 00111 { 00112 __name = strdup(tlname); 00113 __sealed = false; 00114 __finalize_mutex = new Mutex(); 00115 __wnw_barrier = NULL; 00116 clear(); 00117 if ( maintain_barrier) update_barrier(); 00118 } 00119 00120 00121 /** Copy constructor. 00122 * @param tl thread list to copy 00123 */ 00124 ThreadList::ThreadList(const ThreadList &tl) 00125 : LockList<Thread *>(tl) 00126 { 00127 __name = strdup(tl.__name); 00128 __sealed = tl.__sealed; 00129 __finalize_mutex = new Mutex(); 00130 __wnw_barrier = NULL; 00131 if ( tl.__wnw_barrier != NULL ) update_barrier(); 00132 } 00133 00134 00135 /** Destructor. */ 00136 ThreadList::~ThreadList() 00137 { 00138 free(__name); 00139 delete __finalize_mutex; 00140 delete __wnw_barrier; 00141 } 00142 00143 00144 /** Assignment operator. 00145 * @param tl thread list to assign 00146 * @return reference to this instance 00147 */ 00148 ThreadList & 00149 ThreadList::operator= (const ThreadList &tl) 00150 { 00151 LockList<Thread *>::operator=(tl); 00152 __name = strdup(tl.__name); 00153 __sealed = tl.__sealed; 00154 __finalize_mutex = new Mutex(); 00155 __wnw_barrier = NULL; 00156 if ( tl.__wnw_barrier != NULL ) update_barrier(); 00157 00158 return *this; 00159 } 00160 00161 00162 /** Wakeup all threads in list. */ 00163 void 00164 ThreadList::wakeup() 00165 { 00166 MutexLocker lock(mutex()); 00167 00168 for (iterator i = begin(); i != end(); ++i) { 00169 (*i)->wakeup(); 00170 } 00171 } 00172 00173 00174 /** Wakeup all threads in list. 00175 * This method wakes up all thread without acquiring the lock first. 00176 * This method must only be used if the thread list is locked otherwise! 00177 */ 00178 void 00179 ThreadList::wakeup_unlocked() 00180 { 00181 for (iterator i = begin(); i != end(); ++i) { 00182 (*i)->wakeup(); 00183 } 00184 } 00185 00186 00187 /** Wakeup all threads in list and have them wait for the barrier. 00188 * @param barrier Barrier to wait for after loop 00189 */ 00190 void 00191 ThreadList::wakeup(Barrier *barrier) 00192 { 00193 MutexLocker lock(mutex()); 00194 00195 for (iterator i = begin(); i != end(); ++i) { 00196 (*i)->wakeup(barrier); 00197 } 00198 } 00199 00200 00201 /** Wakeup all threads in list and have them wait for the barrier. 00202 * This method wakes up all thread without aquiring the lock first. 00203 * This method must only be used if the thread list is locked otherwise! 00204 * @param barrier Barrier to wait for after loop 00205 */ 00206 void 00207 ThreadList::wakeup_unlocked(Barrier *barrier) 00208 { 00209 Exception *exc = NULL; 00210 unsigned int count = 1; 00211 for (iterator i = begin(); i != end(); ++i) { 00212 if ( ! (*i)->flagged_bad() ) { 00213 try { 00214 (*i)->wakeup(barrier); 00215 } catch (Exception &e) { 00216 if (! exc) { 00217 exc = new Exception(e); 00218 } else { 00219 exc->append(e); 00220 } 00221 } 00222 ++count; 00223 } 00224 } 00225 if (exc) { 00226 Exception te(*exc); 00227 delete exc; 00228 throw te; 00229 } 00230 if (count != barrier->count()) { 00231 throw Exception("ThreadList(%s)::wakeup(): barrier has count (%u) different " 00232 "from number of unflagged threads (%u)", __name, barrier->count(), count); 00233 } 00234 } 00235 00236 00237 /** Wakeup threads and wait for them to finish. 00238 * This assumes that all threads are in wait-for-wakeup mode. The threads are woken 00239 * up with an internally maintained barrier. The method will return when all threads 00240 * have finished one loop() iteration. 00241 * @param timeout_sec timeout in seconds 00242 * @param timeout_nanosec timeout in nanoseconds 00243 * @exception NullPointerException thrown, if no internal barrier is maintained. Make sure 00244 * you use the proper constructor. 00245 */ 00246 void 00247 ThreadList::wakeup_and_wait(unsigned int timeout_sec, unsigned int timeout_nanosec) 00248 { 00249 if ( ! __wnw_barrier ) { 00250 throw NullPointerException("ThreadList::wakeup_and_wait() can only be called if " 00251 "barrier is maintained"); 00252 } 00253 00254 MutexLocker lock(mutex()); 00255 00256 try { 00257 wakeup_unlocked(__wnw_barrier); 00258 } catch (Exception &e) { 00259 throw; 00260 } 00261 if ( ! __wnw_barrier->wait(timeout_sec, timeout_nanosec) ) { 00262 // timeout, we have a bad thread, flag it 00263 RefPtr<ThreadList> passed_threads = __wnw_barrier->passed_threads(); 00264 ThreadList bad_threads; 00265 for (iterator i = begin(); i != end(); ++i) { 00266 bool ok = false; 00267 for (iterator j = passed_threads->begin(); j != passed_threads->end(); ++j) { 00268 if (*j == *i) { 00269 ok = true; 00270 break; 00271 } 00272 } 00273 if (! ok) { 00274 bad_threads.push_back(*i); 00275 (*i)->set_flag(Thread::FLAG_BAD); 00276 } 00277 } 00278 00279 __wnw_bad_barriers.push_back(make_pair(__wnw_barrier, bad_threads)); 00280 00281 __wnw_barrier = NULL; 00282 update_barrier(); 00283 00284 // Formulate exception 00285 std::string s; 00286 if ( bad_threads.size() > 1 ) { 00287 s = "Multiple threads did not finish in time, flagging as bad: "; 00288 for (iterator i = bad_threads.begin(); i != bad_threads.end(); ++i) { 00289 s += std::string((*i)->name()) + " "; 00290 } 00291 } else if (bad_threads.size() == 0) { 00292 s = "Timeout happened, but no bad threads recorded."; 00293 } else { 00294 throw Exception("Thread %s did not finish in time (max %f), flagging as bad", 00295 bad_threads.front()->name(), 00296 (float)timeout_sec + (float)timeout_nanosec / 1000000000.); 00297 } 00298 throw Exception("%s", s.c_str()); 00299 } 00300 } 00301 00302 00303 /** Set if this thread list should maintain a barrier. 00304 * This operation does an implicit locking of the list. 00305 * @param maintain_barrier true to maintain an internal barrier, false to disable it. 00306 */ 00307 void 00308 ThreadList::set_maintain_barrier(bool maintain_barrier) 00309 { 00310 MutexLocker lock(mutex()); 00311 00312 delete __wnw_barrier; 00313 __wnw_barrier = NULL; 00314 if ( maintain_barrier ) update_barrier(); 00315 } 00316 00317 00318 /** Check if any of the bad barriers recovered. 00319 * If the ThreadList maintains the barrier these may get bad if a thread does 00320 * not finish in time. This method will check all bad barriers if the bad threads 00321 * have recovered, and if so it will re-integrate the bad threads. 00322 * @param recovered_threads upon return the names of any threads that could be 00323 * recovered from a bad state have been added to the list. 00324 */ 00325 void 00326 ThreadList::try_recover(std::list<std::string> &recovered_threads) 00327 { 00328 MutexLocker lock(mutex()); 00329 00330 bool changed = false; 00331 __wnw_bbit = __wnw_bad_barriers.begin(); 00332 while (__wnw_bbit != __wnw_bad_barriers.end()) { 00333 iterator i = __wnw_bbit->second.begin(); 00334 while (i != __wnw_bbit->second.end()) { 00335 if ( (*i)->waiting() ) { 00336 // waiting means running() finished and the barrier has been passed 00337 recovered_threads.push_back((*i)->name()); 00338 // it finally finished, re-integrate and hope that it does not bust again 00339 (*i)->unset_flag(Thread::FLAG_BAD); 00340 i = __wnw_bbit->second.erase(i); 00341 changed = true; 00342 } else { 00343 ++i; 00344 } 00345 } 00346 if ( __wnw_bbit->second.empty() ) { 00347 delete __wnw_bbit->first; 00348 __wnw_bbit = __wnw_bad_barriers.erase(__wnw_bbit); 00349 } else { 00350 ++__wnw_bbit; 00351 } 00352 } 00353 if ( changed ) update_barrier(); 00354 } 00355 00356 /** Initialize threads. 00357 * The threads are being initialized. 00358 * This operation is carried out unlocked. Lock it from the outside if needed. 00359 * This is done because it is likely that this will be chained with other 00360 * actions that require locking, thus you can lock the whole operation. 00361 * @param initializer thread initializer to use 00362 * @param finalizer finalizer to use to finalize threads that have been successfully 00363 * initialized before one thread failed. 00364 * @exception CannotInitializeThreadException thrown if at least one of the 00365 * threads in this list could not be initialized. 00366 */ 00367 void 00368 ThreadList::init(ThreadInitializer *initializer, ThreadFinalizer *finalizer) 00369 { 00370 CannotInitializeThreadException cite; 00371 ThreadList initialized_threads; 00372 bool success = true; 00373 for (ThreadList::iterator i = begin(); i != end(); ++i) { 00374 // if initializer fails, we assume it handles finalization 00375 try { 00376 initializer->init(*i); 00377 } catch (Exception &e) { 00378 cite.append("Initialized failed to initialize thread '%s'", (*i)->name()); 00379 cite.append(e); 00380 success = false; 00381 break; 00382 } 00383 // if the thread's init() method fails, we need to finalize that very 00384 // thread only with the finalizer, already initialized threads muts be 00385 // fully finalized 00386 try { 00387 (*i)->init(); 00388 initialized_threads.push_back(*i); 00389 } catch (CannotInitializeThreadException &e) { 00390 notify_of_failed_init(); 00391 cite.append("Initializing thread '%s' in list '%s' failed", 00392 (*i)->name(), __name); 00393 cite.append(e); 00394 finalizer->finalize(*i); 00395 success = false; 00396 break; 00397 } catch (Exception &e) { 00398 notify_of_failed_init(); 00399 cite.append("Could not initialize thread '%s'", (*i)->name()); 00400 cite.append(e); 00401 finalizer->finalize(*i); 00402 success = false; 00403 break; 00404 } catch (std::exception &e) { 00405 notify_of_failed_init(); 00406 cite.append("Could not initialize thread '%s'", (*i)->name()); 00407 cite.append("Caught std::exception or derivative: %s", e.what()); 00408 finalizer->finalize(*i); 00409 success = false; 00410 break; 00411 } catch (...) { 00412 notify_of_failed_init(); 00413 cite.append("Could not initialize thread '%s'", (*i)->name()); 00414 cite.append("Unknown exception caught"); 00415 finalizer->finalize(*i); 00416 success = false; 00417 break; 00418 } 00419 } 00420 00421 if ( ! success ) { 00422 initialized_threads.finalize(finalizer); 00423 throw cite; 00424 } 00425 } 00426 00427 00428 /** Start threads. 00429 * The threads are started. 00430 * This operation is carried out unlocked. Lock it from the outside if needed. 00431 * This is done because it is likely that this will be chained with other 00432 * actions that require locking, thus you can lock the whole operation. 00433 */ 00434 void 00435 ThreadList::start() 00436 { 00437 for (iterator i = begin(); i != end(); ++i) { 00438 (*i)->start(); 00439 } 00440 } 00441 00442 00443 /** Cancel threads. 00444 * The threads are canceled. 00445 * This operation is carried out unlocked. Lock it from the outside if needed. 00446 * This is done because it is likely that this will be chained with other 00447 * actions that require locking, thus you can lock the whole operation. 00448 * 00449 * This is especially handy for detached threads. Since errorneous behavior 00450 * has been seen when run inside gdb something like 00451 * @code 00452 * tl.cancel(); 00453 * tl.join(); 00454 * @endcode 00455 * shout be avoided. Instead use 00456 * @code 00457 * tl.stop(); 00458 * @endcode 00459 */ 00460 void 00461 ThreadList::cancel() 00462 { 00463 for (iterator i = begin(); i != end(); ++i) { 00464 (*i)->cancel(); 00465 } 00466 } 00467 00468 00469 /** Join threads. 00470 * The threads are joined. 00471 * This operation is carried out unlocked. Lock it from the outside if needed. 00472 * This is done because it is likely that this will be chained with other 00473 * actions that require locking, thus you can lock the whole operation. 00474 * 00475 * Since errorneous behavior 00476 * has been seen when run inside gdb something like 00477 * @code 00478 * tl.cancel(); 00479 * tl.join(); 00480 * @endcode 00481 * shout be avoided. Instead use 00482 * @code 00483 * tl.stop(); 00484 * @endcode 00485 */ 00486 void 00487 ThreadList::join() 00488 { 00489 for (iterator i = begin(); i != end(); ++i) { 00490 (*i)->join(); 00491 } 00492 } 00493 00494 00495 /** Stop threads. 00496 * The threads are canceled and joined. 00497 * This operation is carried out unlocked. Lock it from the outside if needed. 00498 * This is done because it is likely that this will be chained with other 00499 * actions that require locking, thus you can lock the whole operation. 00500 */ 00501 void 00502 ThreadList::stop() 00503 { 00504 for (reverse_iterator i = rbegin(); i != rend(); ++i) { 00505 (*i)->cancel(); 00506 (*i)->join(); 00507 // Workaround for pthreads annoyance 00508 usleep(5000); 00509 } 00510 } 00511 00512 00513 /** Prepare finalize. 00514 * The threads are prepared for finalization. If any of the threads return 00515 * false the whole list will return false. 00516 * This operation is carried out unlocked. Lock it from the outside if needed. 00517 * This is done because it is likely that this will be chained with other 00518 * actions that require locking, thus you can lock the whole operation. 00519 * @param finalizer thread finalizer to use to prepare finalization of the threads 00520 * @return true, if prepare_finalize() returned true for all threads in the 00521 * list, false if at least one thread returned false. 00522 */ 00523 bool 00524 ThreadList::prepare_finalize(ThreadFinalizer *finalizer) 00525 { 00526 MutexLocker lock(__finalize_mutex); 00527 00528 bool can_finalize = true; 00529 CannotFinalizeThreadException cfte("Cannot finalize one or more threads"); 00530 bool threw_exception = false; 00531 for (reverse_iterator i = rbegin(); i != rend(); ++i) { 00532 // Note that this loop may NOT be interrupted in the middle by break, 00533 // since even if the thread denies finalization it can still be finalized 00534 // and we have to ensure that every thread got a call to prepare_finalize()! 00535 try { 00536 if ( ! finalizer->prepare_finalize(*i) ) { 00537 can_finalize = false; 00538 } 00539 if ( ! (*i)->prepare_finalize() ) { 00540 can_finalize = false; 00541 } 00542 } catch (CannotFinalizeThreadException &e) { 00543 cfte.append("Thread '%s' throw an exception while preparing finalization of " 00544 "ThreadList '%s'", (*i)->name(), __name); 00545 threw_exception = true; 00546 } 00547 } 00548 if ( threw_exception ) { 00549 throw cfte; 00550 } 00551 return can_finalize; 00552 } 00553 00554 00555 00556 00557 /** Finalize Threads. 00558 * The threads are finalized. 00559 * This operation is carried out unlocked. Lock it from the outside if needed. 00560 * This is done because it is likely that this will be chained with other 00561 * actions that require locking, thus you can lock the whole operation. 00562 * @param finalizer thread finalizer to use to finalize the threads 00563 */ 00564 void 00565 ThreadList::finalize(ThreadFinalizer *finalizer) 00566 { 00567 bool error = false; 00568 Exception me("One or more threads failed to finalize"); 00569 for (reverse_iterator i = rbegin(); i != rend(); ++i) { 00570 try { 00571 finalizer->finalize(*i); 00572 } catch (CannotFinalizeThreadException &e) { 00573 error = true; 00574 me.append("Could not finalize thread '%s' in list '%s'", (*i)->name(), __name); 00575 me.append(e); 00576 } 00577 try { 00578 (*i)->finalize(); 00579 } catch (CannotFinalizeThreadException &e) { 00580 error = true; 00581 me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name()); 00582 me.append(e); 00583 } catch (Exception &e) { 00584 me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name()); 00585 me.append(e); 00586 } catch (...) { 00587 me.append("Thread[%s]::finalize() threw unsupported exception", (*i)->name()); 00588 } 00589 } 00590 if ( error ) { 00591 throw me; 00592 } 00593 } 00594 00595 00596 /** Cancel finalization on all threads. 00597 */ 00598 void 00599 ThreadList::cancel_finalize() 00600 { 00601 MutexLocker lock(__finalize_mutex); 00602 00603 for (reverse_iterator i = rbegin(); i != rend(); ++i) { 00604 (*i)->cancel_finalize(); 00605 } 00606 } 00607 00608 00609 /** Set prepfin hold on all threads. 00610 * This method will call Thread::set_prepfin_hold() for all threads in the list. If 00611 * any of the threads fails to set prepfin hold then all thread were it has already 00612 * been set are set to prepfin hold false. 00613 * @param hold prepfin hold value 00614 * @see Thread::set_prepfin_hold() 00615 */ 00616 void 00617 ThreadList::set_prepfin_hold(bool hold) 00618 { 00619 iterator i; 00620 try { 00621 for (i = begin(); i != end(); ++i) { 00622 (*i)->set_prepfin_hold(hold); 00623 } 00624 } catch (Exception &e) { 00625 // boom, we failed, at least one thread was already in the state of being prepared 00626 // for finalization, rollback the hold for the threads were we already set it 00627 for (iterator j = begin(); j != i; ++j) { 00628 (*j)->set_prepfin_hold(false); 00629 } 00630 throw; 00631 } 00632 } 00633 00634 00635 /** Force stop of all threads. 00636 * This will call prepare_finalize(), finalize(), cancel() and join() on the 00637 * list without caring about the return values in the prepare_finalize() step. 00638 * @param finalizer thread finalizer to use to finalize the threads. 00639 */ 00640 void 00641 ThreadList::force_stop(ThreadFinalizer *finalizer) 00642 { 00643 try { 00644 prepare_finalize(finalizer); 00645 stop(); 00646 finalize(finalizer); 00647 } catch (Exception &e) { 00648 // ignored 00649 } 00650 } 00651 00652 00653 /** Name of the thread list. 00654 * This can be used for better log output to identify the list that causes 00655 * problems. 00656 * @return name of thread list 00657 */ 00658 const char * 00659 ThreadList::name() 00660 { 00661 return __name; 00662 } 00663 00664 00665 /** Set name of thread. 00666 * Use parameters similar to printf(). 00667 * @param format format string 00668 */ 00669 void 00670 ThreadList::set_name(const char *format, ...) 00671 { 00672 va_list va; 00673 va_start(va, format); 00674 00675 char *tmpname; 00676 if (vasprintf(&tmpname, format, va) != -1) { 00677 free(__name); 00678 __name = tmpname; 00679 } else { 00680 throw OutOfMemoryException("ThreadList::set_name(): vasprintf() failed"); 00681 } 00682 va_end(va); 00683 } 00684 00685 00686 /** Check if list is sealed. 00687 * If the list is sealed, no more writing operations are allowed and will trigger 00688 * an exception. 00689 * @return true, if list is sealed, false otherwise 00690 */ 00691 bool 00692 ThreadList::sealed() 00693 { 00694 return __sealed; 00695 } 00696 00697 00698 /** Seal the list. */ 00699 void 00700 ThreadList::seal() 00701 { 00702 __sealed = true; 00703 } 00704 00705 00706 /** Add thread to the front. 00707 * Add thread to the beginning of the list. 00708 * @param thread thread to add 00709 */ 00710 void 00711 ThreadList::push_front(Thread *thread) 00712 { 00713 if ( __sealed ) throw ThreadListSealedException("push_front"); 00714 00715 LockList<Thread *>::push_front(thread); 00716 if ( __wnw_barrier) update_barrier(); 00717 } 00718 00719 00720 /** Add thread to the front with lock protection. 00721 * Add thread to the beginning of the list. The operation is protected 00722 * by the thread list lock. 00723 * The operation will succeed without blocking even 00724 * if the list is currently locked. It will push the thread to an internal temporary 00725 * list and will add the thread finally when the list is unlocked. 00726 * @param thread thread to add 00727 */ 00728 void 00729 ThreadList::push_front_locked(Thread *thread) 00730 { 00731 if ( __sealed ) throw ThreadListSealedException("push_front_locked"); 00732 00733 MutexLocker lock(mutex()); 00734 LockList<Thread *>::push_front(thread); 00735 if ( __wnw_barrier) update_barrier(); 00736 } 00737 00738 00739 /** Add thread to the end. 00740 * Add thread to the end of the list. 00741 * @param thread thread to add 00742 */ 00743 void 00744 ThreadList::push_back(Thread *thread) 00745 { 00746 if ( __sealed ) throw ThreadListSealedException("push_back"); 00747 00748 LockList<Thread *>::push_back(thread); 00749 if ( __wnw_barrier) update_barrier(); 00750 } 00751 00752 00753 /** Add thread to the end with lock protection. 00754 * Add thread to the end of the list. The operation is protected 00755 * by the thread list lock. 00756 * The operation will succeed without blocking even 00757 * if the list is currently locked. It will push the thread to an internal temporary 00758 * list and will add the thread finally when the list is unlocked. 00759 * @param thread thread to add 00760 */ 00761 void 00762 ThreadList::push_back_locked(Thread *thread) 00763 { 00764 if ( __sealed ) throw ThreadListSealedException("push_back_locked"); 00765 00766 MutexLocker lock(mutex()); 00767 LockList<Thread *>::push_back(thread); 00768 if ( __wnw_barrier) update_barrier(); 00769 } 00770 00771 00772 /** Clear the list. 00773 * Removes all elements. 00774 */ 00775 void 00776 ThreadList::clear() 00777 { 00778 if ( __sealed ) throw ThreadListSealedException("clear"); 00779 00780 LockList<Thread *>::clear(); 00781 if ( __wnw_barrier) update_barrier(); 00782 } 00783 00784 00785 /** Remove with lock protection. 00786 * @param thread thread to remove. 00787 */ 00788 void 00789 ThreadList::remove(Thread *thread) 00790 { 00791 if ( __sealed ) throw ThreadListSealedException("remove_locked"); 00792 00793 LockList<Thread *>::remove(thread); 00794 if ( __wnw_barrier) update_barrier(); 00795 } 00796 00797 00798 /** Remove with lock protection. 00799 * @param thread thread to remove. 00800 */ 00801 void 00802 ThreadList::remove_locked(Thread *thread) 00803 { 00804 if ( __sealed ) throw ThreadListSealedException("remove_locked"); 00805 00806 MutexLocker lock(mutex()); 00807 LockList<Thread *>::remove(thread); 00808 if ( __wnw_barrier) update_barrier(); 00809 } 00810 00811 00812 /** Remove first element. */ 00813 void 00814 ThreadList::pop_front() 00815 { 00816 if ( __sealed ) throw ThreadListSealedException("pop_front"); 00817 00818 LockList<Thread *>::pop_front(); 00819 if ( __wnw_barrier) update_barrier(); 00820 } 00821 00822 00823 /** Remove last element. */ 00824 void 00825 ThreadList::pop_back() 00826 { 00827 if ( __sealed ) throw ThreadListSealedException("pop_back"); 00828 00829 LockList<Thread *>::pop_back(); 00830 if ( __wnw_barrier) update_barrier(); 00831 } 00832 00833 00834 /** Erase element at given position. 00835 * @param pos iterator marking the element to remove. 00836 * @return iterator to element that follows pos 00837 */ 00838 ThreadList::iterator 00839 ThreadList::erase(iterator pos) 00840 { 00841 if ( __sealed ) throw ThreadListSealedException("erase"); 00842 00843 ThreadList::iterator rv = LockList<Thread *>::erase(pos); 00844 if ( __wnw_barrier) update_barrier(); 00845 return rv; 00846 } 00847 00848 00849 /** Update internal barrier. */ 00850 void 00851 ThreadList::update_barrier() 00852 { 00853 unsigned int num = 1; 00854 for (iterator i = begin(); i != end(); ++i) { 00855 if (! (*i)->flagged_bad() ) ++num; 00856 } 00857 delete __wnw_barrier; 00858 __wnw_barrier = new InterruptibleBarrier(num); 00859 } 00860 00861 00862 /** Notify all threads of failed init. */ 00863 void 00864 ThreadList::notify_of_failed_init() 00865 { 00866 for (ThreadList::iterator i = begin(); i != end(); ++i) { 00867 (*i)->notify_of_failed_init(); 00868 } 00869 } 00870 00871 00872 } // end namespace fawkes