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/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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends