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