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