Fawkes API  Fawkes Development Version
thread_list.cpp
1 
2 /***************************************************************************
3  * thread_list.cpp - Thread list
4  *
5  * Created: Tue Oct 31 18:20:59 2006
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exceptions/software.h>
25 #include <core/exceptions/system.h>
26 #include <core/threading/barrier.h>
27 #include <core/threading/interruptible_barrier.h>
28 #include <core/threading/mutex.h>
29 #include <core/threading/mutex_locker.h>
30 #include <core/threading/thread.h>
31 #include <core/threading/thread_list.h>
32 
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36 #include <string>
37 #include <unistd.h>
38 
39 namespace fawkes {
40 
41 /** @class ThreadListSealedException <core/threading/thread_list.h>
42  * Thread list sealed exception.
43  * This exception is thrown whenever you execute an action that would
44  * modify the thread list like adding or removing elements on a
45  * sealed list. A list can only be sealed and never be unsealed afterwards.
46  * This exception is meant to be only thrown by ThreadList.
47  * @author Tim Niemueller
48  */
49 
50 /** Constructor.
51  * @param operation operation that failed
52  */
54 : Exception("ThreadList is sealed")
55 {
56  append("Operation '%s' is not allowed on a sealed thread list", operation);
57 }
58 
59 /** @class ThreadListNotSealedException <core/threading/thread_list.h>
60  * Thread list not sealed exception.
61  * This exception is thrown whenever the thread list is given to some
62  * method that expects a sealed list (probably because it sealed the
63  * list by itself).
64  * This exception is meant to be only thrown by users of ThreadList.
65  * @author Tim Niemueller
66  */
67 
68 /** Constructor.
69  * @param format format of message
70  */
72 {
73  va_list va;
74  va_start(va, format);
75  append_va(format, va);
76  va_end(va);
77 }
78 
79 /** @class ThreadList <core/threading/thread_list.h>
80  * List of threads.
81  * This is a list of threads derived from stl::list. It features special
82  * wakeup methods that will wakeup all threads in the list. The list can
83  * and must be locked in iterator operations and when adding or deleting
84  * elements from the list.
85  * @author Tim Niemueller
86  */
87 
88 /** Constructor.
89  * @param tlname optional name which is used for better readable error
90  * messages.
91  */
92 ThreadList::ThreadList(const char *tlname)
93 {
94  name_ = strdup(tlname);
95  sealed_ = false;
96  finalize_mutex_ = new Mutex();
97  wnw_barrier_ = NULL;
98  clear();
99 }
100 
101 /** Constructor.
102  * @param maintain_barrier if true, an internal barrier is maintained during add and
103  * remove operations such that wakeup_and_wait() can be used.
104  * @param tlname optional name which is used for better readable error
105  * messages.
106  */
107 ThreadList::ThreadList(bool maintain_barrier, const char *tlname)
108 {
109  name_ = strdup(tlname);
110  sealed_ = false;
111  finalize_mutex_ = new Mutex();
112  wnw_barrier_ = NULL;
113  clear();
114  if (maintain_barrier)
115  update_barrier();
116 }
117 
118 /** Copy constructor.
119  * @param tl thread list to copy
120  */
122 {
123  name_ = strdup(tl.name_);
124  sealed_ = tl.sealed_;
125  finalize_mutex_ = new Mutex();
126  wnw_barrier_ = NULL;
127  if (tl.wnw_barrier_ != NULL)
128  update_barrier();
129 }
130 
131 /** Destructor. */
133 {
134  free(name_);
135  delete finalize_mutex_;
136  delete wnw_barrier_;
137 }
138 
139 /** Assignment operator.
140  * @param tl thread list to assign
141  * @return reference to this instance
142  */
143 ThreadList &
145 {
147  name_ = strdup(tl.name_);
148  sealed_ = tl.sealed_;
149  finalize_mutex_ = new Mutex();
150  wnw_barrier_ = NULL;
151  if (tl.wnw_barrier_ != NULL)
152  update_barrier();
153 
154  return *this;
155 }
156 
157 /** Wakeup all threads in list. */
158 void
160 {
162 
163  for (iterator i = begin(); i != end(); ++i) {
164  (*i)->wakeup();
165  }
166 }
167 
168 /** Wakeup all threads in list.
169  * This method wakes up all thread without acquiring the lock first.
170  * This method must only be used if the thread list is locked otherwise!
171  */
172 void
174 {
175  for (iterator i = begin(); i != end(); ++i) {
176  (*i)->wakeup();
177  }
178 }
179 
180 /** Wakeup all threads in list and have them wait for the barrier.
181  * @param barrier Barrier to wait for after loop
182  */
183 void
185 {
187 
188  for (iterator i = begin(); i != end(); ++i) {
189  (*i)->wakeup(barrier);
190  }
191 }
192 
193 /** Wakeup all threads in list and have them wait for the barrier.
194  * This method wakes up all thread without aquiring the lock first.
195  * This method must only be used if the thread list is locked otherwise!
196  * @param barrier Barrier to wait for after loop
197  */
198 void
200 {
201  Exception * exc = NULL;
202  unsigned int count = 1;
203  for (iterator i = begin(); i != end(); ++i) {
204  if (!(*i)->flagged_bad()) {
205  try {
206  (*i)->wakeup(barrier);
207  } catch (Exception &e) {
208  if (!exc) {
209  exc = new Exception(e);
210  } else {
211  exc->append(e);
212  }
213  }
214  ++count;
215  }
216  }
217  if (exc) {
218  Exception te(*exc);
219  delete exc;
220  throw te;
221  }
222  if (count != barrier->count()) {
223  throw Exception("ThreadList(%s)::wakeup(): barrier has count (%u) different "
224  "from number of unflagged threads (%u)",
225  name_,
226  barrier->count(),
227  count);
228  }
229 }
230 
231 /** Wakeup threads and wait for them to finish.
232  * This assumes that all threads are in wait-for-wakeup mode. The threads are woken
233  * up with an internally maintained barrier. The method will return when all threads
234  * have finished one loop() iteration.
235  * @param timeout_sec timeout in seconds
236  * @param timeout_nanosec timeout in nanoseconds
237  * @exception NullPointerException thrown, if no internal barrier is maintained. Make sure
238  * you use the proper constructor.
239  */
240 void
241 ThreadList::wakeup_and_wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
242 {
243  if (!wnw_barrier_) {
244  throw NullPointerException("ThreadList::wakeup_and_wait() can only be called if "
245  "barrier is maintained");
246  }
247 
249 
250  try {
251  wakeup_unlocked(wnw_barrier_);
252  } catch (Exception &e) {
253  throw;
254  }
255  if (!wnw_barrier_->wait(timeout_sec, timeout_nanosec)) {
256  // timeout, we have a bad thread, flag it
257  RefPtr<ThreadList> passed_threads = wnw_barrier_->passed_threads();
258  ThreadList bad_threads;
259  for (iterator i = begin(); i != end(); ++i) {
260  if ((*i)->flagged_bad()) {
261  // thread is already flagged as bad, don't add it to bad_threads
262  continue;
263  }
264  bool ok = false;
265  for (iterator j = passed_threads->begin(); j != passed_threads->end(); ++j) {
266  if (*j == *i) {
267  ok = true;
268  break;
269  }
270  }
271  if (!ok) {
272  bad_threads.push_back(*i);
273  (*i)->set_flag(Thread::FLAG_BAD);
274  }
275  }
276 
277  wnw_bad_barriers_.push_back(make_pair(wnw_barrier_, bad_threads));
278 
279  wnw_barrier_ = NULL;
280  update_barrier();
281 
282  // Formulate exception
283  std::string s;
284  if (bad_threads.size() > 1) {
285  s = "Multiple threads did not finish in time, flagging as bad: ";
286  for (iterator i = bad_threads.begin(); i != bad_threads.end(); ++i) {
287  s += std::string((*i)->name()) + " ";
288  }
289  } else if (bad_threads.size() == 0) {
290  s = "Timeout happened, but no bad threads recorded.";
291  } else {
292  throw Exception("Thread %s did not finish in time (max %f), flagging as bad",
293  bad_threads.front()->name(),
294  (float)timeout_sec + (float)timeout_nanosec / 1000000000.);
295  }
296  throw Exception("%s", s.c_str());
297  }
298 }
299 
300 /** Set if this thread list should maintain a barrier.
301  * This operation does an implicit locking of the list.
302  * @param maintain_barrier true to maintain an internal barrier, false to disable it.
303  */
304 void
305 ThreadList::set_maintain_barrier(bool maintain_barrier)
306 {
308 
309  if (wnw_barrier_ != NULL && !wnw_barrier_->no_threads_in_wait()) {
310  throw Exception("InterruptibleBarrier cannot be destroyed "
311  "when there still are threads in the wait() function");
312  }
313  delete wnw_barrier_;
314  wnw_barrier_ = NULL;
315  if (maintain_barrier)
316  update_barrier();
317 }
318 
319 /** Check if any of the bad barriers recovered.
320  * If the ThreadList maintains the barrier these may get bad if a thread does
321  * not finish in time. This method will check all bad barriers if the bad threads
322  * have recovered, and if so it will re-integrate the bad threads.
323  * @param recovered_threads upon return the names of any threads that could be
324  * recovered from a bad state have been added to the list.
325  */
326 void
327 ThreadList::try_recover(std::list<std::string> &recovered_threads)
328 {
330 
331  bool changed = false;
332  wnw_bbit_ = wnw_bad_barriers_.begin();
333  while (wnw_bbit_ != wnw_bad_barriers_.end()) {
334  iterator i = wnw_bbit_->second.begin();
335  while (i != wnw_bbit_->second.end()) {
336  if ((*i)->cancelled()) {
337  // thread is cancelled, remove it from the barrier
338  i = wnw_bbit_->second.erase(i);
339  changed = true;
340  } else if ((*i)->waiting()) {
341  // waiting means running() finished and the barrier has been passed
342  recovered_threads.push_back((*i)->name());
343  // it finally finished, re-integrate and hope that it does not bust again
344  (*i)->unset_flag(Thread::FLAG_BAD);
345  i = wnw_bbit_->second.erase(i);
346  changed = true;
347  } else {
348  ++i;
349  }
350  }
351  if (wnw_bbit_->second.empty() && wnw_bbit_->first->no_threads_in_wait()) {
352  delete wnw_bbit_->first;
353  wnw_bbit_ = wnw_bad_barriers_.erase(wnw_bbit_);
354  } else {
355  ++wnw_bbit_;
356  }
357  }
358  if (changed)
359  update_barrier();
360 }
361 
362 /** Initialize threads.
363  * The threads are being initialized.
364  * This operation is carried out unlocked. Lock it from the outside if needed.
365  * This is done because it is likely that this will be chained with other
366  * actions that require locking, thus you can lock the whole operation.
367  * @param initializer thread initializer to use
368  * @param finalizer finalizer to use to finalize threads that have been successfully
369  * initialized before one thread failed.
370  * @exception CannotInitializeThreadException thrown if at least one of the
371  * threads in this list could not be initialized.
372  */
373 void
375 {
377  ThreadList initialized_threads;
378  bool success = true;
379  for (ThreadList::iterator i = begin(); i != end(); ++i) {
380  // if initializer fails, we assume it handles finalization
381 #ifndef DEBUG_THREAD_INIT
382  try {
383 #endif
384  initializer->init(*i);
385 #ifndef DEBUG_THREAD_INIT
386  } catch (Exception &e) {
387  cite.append("Initialized failed to initialize thread '%s'", (*i)->name());
388  cite.append(e);
389  success = false;
390  break;
391  }
392 #endif
393  // if the thread's init() method fails, we need to finalize that very
394  // thread only with the finalizer, already initialized threads muts be
395  // fully finalized
396 #ifndef DEBUG_THREAD_INIT
397  try {
398 #endif
399  (*i)->init();
400  initialized_threads.push_back(*i);
401 #ifndef DEBUG_THREAD_INIT
402  } catch (CannotInitializeThreadException &e) {
403  notify_of_failed_init();
404  cite.append("Initializing thread '%s' in list '%s' failed", (*i)->name(), name_);
405  cite.append(e);
406  finalizer->finalize(*i);
407  success = false;
408  break;
409  } catch (Exception &e) {
410  notify_of_failed_init();
411  cite.append(e);
412  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
413  finalizer->finalize(*i);
414  success = false;
415  break;
416  } catch (std::exception &e) {
417  notify_of_failed_init();
418  cite.append("Caught std::exception: %s", e.what());
419  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
420  finalizer->finalize(*i);
421  success = false;
422  break;
423  } catch (...) {
424  notify_of_failed_init();
425  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
426  cite.append("Unknown exception caught");
427  finalizer->finalize(*i);
428  success = false;
429  break;
430  }
431 #endif
432  }
433 
434  if (!success) {
435  initialized_threads.finalize(finalizer);
436  throw cite;
437  }
438 }
439 
440 /** Start threads.
441  * The threads are started.
442  * This operation is carried out unlocked. Lock it from the outside if needed.
443  * This is done because it is likely that this will be chained with other
444  * actions that require locking, thus you can lock the whole operation.
445  */
446 void
448 {
449  for (iterator i = begin(); i != end(); ++i) {
450  (*i)->start();
451  }
452 }
453 
454 /** Cancel threads.
455  * The threads are canceled.
456  * This operation is carried out unlocked. Lock it from the outside if needed.
457  * This is done because it is likely that this will be chained with other
458  * actions that require locking, thus you can lock the whole operation.
459  *
460  * This is especially handy for detached threads. Since errorneous behavior
461  * has been seen when run inside gdb something like
462  * @code
463  * tl.cancel();
464  * tl.join();
465  * @endcode
466  * shout be avoided. Instead use
467  * @code
468  * tl.stop();
469  * @endcode
470  */
471 void
473 {
474  for (iterator i = begin(); i != end(); ++i) {
475  (*i)->cancel();
476  }
477 }
478 
479 /** Join threads.
480  * The threads are joined.
481  * This operation is carried out unlocked. Lock it from the outside if needed.
482  * This is done because it is likely that this will be chained with other
483  * actions that require locking, thus you can lock the whole operation.
484  *
485  * Since errorneous behavior
486  * has been seen when run inside gdb something like
487  * @code
488  * tl.cancel();
489  * tl.join();
490  * @endcode
491  * shout be avoided. Instead use
492  * @code
493  * tl.stop();
494  * @endcode
495  */
496 void
498 {
499  for (iterator i = begin(); i != end(); ++i) {
500  (*i)->join();
501  }
502 }
503 
504 /** Stop threads.
505  * The threads are canceled and joined.
506  * This operation is carried out unlocked. Lock it from the outside if needed.
507  * This is done because it is likely that this will be chained with other
508  * actions that require locking, thus you can lock the whole operation.
509  */
510 void
512 {
513  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
514  (*i)->cancel();
515  (*i)->join();
516  // Workaround for pthreads annoyance
517  usleep(5000);
518  }
519 }
520 
521 /** Prepare finalize.
522  * The threads are prepared for finalization. If any of the threads return
523  * false the whole list will return false.
524  * This operation is carried out unlocked. Lock it from the outside if needed.
525  * This is done because it is likely that this will be chained with other
526  * actions that require locking, thus you can lock the whole operation.
527  * @param finalizer thread finalizer to use to prepare finalization of the threads
528  * @return true, if prepare_finalize() returned true for all threads in the
529  * list, false if at least one thread returned false.
530  */
531 bool
533 {
534  MutexLocker lock(finalize_mutex_);
535 
536  bool can_finalize = true;
537  CannotFinalizeThreadException cfte("Cannot finalize one or more threads");
538  bool threw_exception = false;
539  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
540  // Note that this loop may NOT be interrupted in the middle by break,
541  // since even if the thread denies finalization it can still be finalized
542  // and we have to ensure that every thread got a call to prepare_finalize()!
543  try {
544  if (!finalizer->prepare_finalize(*i)) {
545  can_finalize = false;
546  }
547  if (!(*i)->prepare_finalize()) {
548  can_finalize = false;
549  }
550  } catch (CannotFinalizeThreadException &e) {
551  cfte.append("Thread '%s' threw an exception while preparing finalization of "
552  "ThreadList '%s' (IGNORED)",
553  (*i)->name(),
554  name_);
555  cfte.append(e);
556  threw_exception = true;
557  } catch (Exception &e) {
558  cfte.append("Thread '%s' threw a generic exception while preparing finalization of "
559  "ThreadList '%s' (IGNORED)",
560  (*i)->name(),
561  name_);
562  cfte.append(e);
563  threw_exception = true;
564  }
565  }
566  if (threw_exception) {
567  throw cfte;
568  }
569  return can_finalize;
570 }
571 
572 /** Finalize Threads.
573  * The threads are finalized.
574  * This operation is carried out unlocked. Lock it from the outside if needed.
575  * This is done because it is likely that this will be chained with other
576  * actions that require locking, thus you can lock the whole operation.
577  * @param finalizer thread finalizer to use to finalize the threads
578  */
579 void
581 {
582  bool error = false;
583  Exception me("One or more threads failed to finalize");
584  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
585  try {
586  (*i)->finalize();
587  } catch (CannotFinalizeThreadException &e) {
588  error = true;
589  me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name());
590  me.append(e);
591  } catch (Exception &e) {
592  error = true;
593  me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name());
594  me.append(e);
595  } catch (...) {
596  error = true;
597  me.append("Thread[%s]::finalize() threw unsupported exception", (*i)->name());
598  }
599  try {
600  finalizer->finalize(*i);
601  } catch (CannotFinalizeThreadException &e) {
602  error = true;
603  me.append("Could not finalize thread '%s' in list '%s'", (*i)->name(), name_);
604  me.append(e);
605  }
606  }
607  if (error) {
608  throw me;
609  }
610 }
611 
612 /** Cancel finalization on all threads.
613  */
614 void
616 {
617  MutexLocker lock(finalize_mutex_);
618 
619  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
620  (*i)->cancel_finalize();
621  }
622 }
623 
624 /** Set prepfin hold on all threads.
625  * This method will call Thread::set_prepfin_hold() for all threads in the list. If
626  * any of the threads fails to set prepfin hold then all thread were it has already
627  * been set are set to prepfin hold false.
628  * @param hold prepfin hold value
629  * @see Thread::set_prepfin_hold()
630  */
631 void
633 {
634  iterator i;
635  try {
636  for (i = begin(); i != end(); ++i) {
637  (*i)->set_prepfin_hold(hold);
638  }
639  } catch (Exception &e) {
640  // boom, we failed, at least one thread was already in the state of being prepared
641  // for finalization, rollback the hold for the threads were we already set it
642  for (iterator j = begin(); j != i; ++j) {
643  (*j)->set_prepfin_hold(false);
644  }
645  throw;
646  }
647 }
648 
649 /** Force stop of all threads.
650  * This will call prepare_finalize(), finalize(), cancel() and join() on the
651  * list without caring about the return values in the prepare_finalize() step.
652  * @param finalizer thread finalizer to use to finalize the threads.
653  */
654 void
656 {
657  bool caught_exception = false;
658  Exception exc("Forced thread finalization failed");
659  ;
660  try {
661  prepare_finalize(finalizer);
662  } catch (Exception &e) {
663  caught_exception = true;
664  exc.append(e);
665  }
666  try {
667  stop();
668  } catch (Exception &e) {
669  caught_exception = true;
670  exc.append(e);
671  }
672  try {
673  finalize(finalizer);
674  } catch (Exception &e) {
675  caught_exception = true;
676  exc.append(e);
677  }
678 
679  if (caught_exception) {
680  throw exc;
681  }
682 }
683 
684 /** Name of the thread list.
685  * This can be used for better log output to identify the list that causes
686  * problems.
687  * @return name of thread list
688  */
689 const char *
691 {
692  return name_;
693 }
694 
695 /** Set name of thread.
696  * Use parameters similar to printf().
697  * @param format format string
698  */
699 void
700 ThreadList::set_name(const char *format, ...)
701 {
702  va_list va;
703  va_start(va, format);
704 
705  char *tmpname;
706  if (vasprintf(&tmpname, format, va) != -1) {
707  free(name_);
708  name_ = tmpname;
709  } else {
710  throw OutOfMemoryException("ThreadList::set_name(): vasprintf() failed");
711  }
712  va_end(va);
713 }
714 
715 /** Check if list is sealed.
716  * If the list is sealed, no more writing operations are allowed and will trigger
717  * an exception.
718  * @return true, if list is sealed, false otherwise
719  */
720 bool
722 {
723  return sealed_;
724 }
725 
726 /** Seal the list. */
727 void
729 {
730  sealed_ = true;
731 }
732 
733 /** Add thread to the front.
734  * Add thread to the beginning of the list.
735  * @param thread thread to add
736  */
737 void
739 {
740  if (sealed_)
741  throw ThreadListSealedException("push_front");
742 
744  if (wnw_barrier_)
745  update_barrier();
746 }
747 
748 /** Add thread to the front with lock protection.
749  * Add thread to the beginning of the list. The operation is protected
750  * by the thread list lock.
751  * The operation will succeed without blocking even
752  * if the list is currently locked. It will push the thread to an internal temporary
753  * list and will add the thread finally when the list is unlocked.
754  * @param thread thread to add
755  */
756 void
758 {
759  if (sealed_)
760  throw ThreadListSealedException("push_front_locked");
761 
764  if (wnw_barrier_)
765  update_barrier();
766 }
767 
768 /** Add thread to the end.
769  * Add thread to the end of the list.
770  * @param thread thread to add
771  */
772 void
774 {
775  if (sealed_)
776  throw ThreadListSealedException("push_back");
777 
779  if (wnw_barrier_)
780  update_barrier();
781 }
782 
783 /** Add thread to the end with lock protection.
784  * Add thread to the end of the list. The operation is protected
785  * by the thread list lock.
786  * The operation will succeed without blocking even
787  * if the list is currently locked. It will push the thread to an internal temporary
788  * list and will add the thread finally when the list is unlocked.
789  * @param thread thread to add
790  */
791 void
793 {
794  if (sealed_)
795  throw ThreadListSealedException("push_back_locked");
796 
799  if (wnw_barrier_)
800  update_barrier();
801 }
802 
803 /** Clear the list.
804  * Removes all elements.
805  */
806 void
808 {
809  if (sealed_)
810  throw ThreadListSealedException("clear");
811 
813  if (wnw_barrier_)
814  update_barrier();
815 }
816 
817 /** Remove with lock protection.
818  * @param thread thread to remove.
819  */
820 void
822 {
823  if (sealed_)
824  throw ThreadListSealedException("remove_locked");
825 
827  if (wnw_barrier_)
828  update_barrier();
829 }
830 
831 /** Remove with lock protection.
832  * @param thread thread to remove.
833  */
834 void
836 {
837  if (sealed_)
838  throw ThreadListSealedException("remove_locked");
839 
842  if (wnw_barrier_)
843  update_barrier();
844 }
845 
846 /** Remove first element. */
847 void
849 {
850  if (sealed_)
851  throw ThreadListSealedException("pop_front");
852 
854  if (wnw_barrier_)
855  update_barrier();
856 }
857 
858 /** Remove last element. */
859 void
861 {
862  if (sealed_)
863  throw ThreadListSealedException("pop_back");
864 
866  if (wnw_barrier_)
867  update_barrier();
868 }
869 
870 /** Erase element at given position.
871  * @param pos iterator marking the element to remove.
872  * @return iterator to element that follows pos
873  */
874 ThreadList::iterator
875 ThreadList::erase(iterator pos)
876 {
877  if (sealed_)
878  throw ThreadListSealedException("erase");
879 
880  ThreadList::iterator rv = LockList<Thread *>::erase(pos);
881  if (wnw_barrier_)
882  update_barrier();
883  return rv;
884 }
885 
886 /** Update internal barrier. */
887 void
888 ThreadList::update_barrier()
889 {
890  unsigned int num = 1;
891  for (iterator i = begin(); i != end(); ++i) {
892  if (!(*i)->flagged_bad())
893  ++num;
894  }
895  if (wnw_barrier_ == NULL || wnw_barrier_->no_threads_in_wait()) {
896  delete wnw_barrier_;
897  } else {
898  //delete the barrier later in try_recover
899  ThreadList empty_list;
900  wnw_bad_barriers_.push_back(make_pair(wnw_barrier_, empty_list));
901  }
902  wnw_barrier_ = new InterruptibleBarrier(num);
903 }
904 
905 /** Notify all threads of failed init. */
906 void
907 ThreadList::notify_of_failed_init()
908 {
909  for (ThreadList::iterator i = begin(); i != end(); ++i) {
910  (*i)->notify_of_failed_init();
911  }
912 }
913 
914 } // end namespace fawkes
fawkes::ThreadList::sealed
bool sealed()
Check if list is sealed.
Definition: thread_list.cpp:721
fawkes::LockList::operator=
LockList< Type > & operator=(const LockList< Type > &ll)
Copy values from another LockList.
Definition: lock_list.h:179
fawkes::LockList< Thread * >::lock
virtual void lock() const
Lock list.
Definition: lock_list.h:124
fawkes::ThreadList::force_stop
void force_stop(ThreadFinalizer *finalizer)
Force stop of all threads.
Definition: thread_list.cpp:655
fawkes::ThreadList::wakeup
void wakeup()
Wakeup all threads in list.
Definition: thread_list.cpp:159
fawkes::ThreadList::clear
void clear()
Clear the list.
Definition: thread_list.cpp:807
fawkes::Exception::append_va
void append_va(const char *format, va_list va)
Append messages to the message list.
Definition: exception.cpp:353
fawkes::ThreadList::set_name
void set_name(const char *format,...)
Set name of thread.
Definition: thread_list.cpp:700
fawkes::ThreadList::remove
void remove(Thread *thread)
Remove with lock protection.
Definition: thread_list.cpp:821
fawkes::Mutex
Mutex mutual exclusion lock.
Definition: mutex.h:33
fawkes::ThreadList::set_maintain_barrier
void set_maintain_barrier(bool maintain_barrier)
Set if this thread list should maintain a barrier.
Definition: thread_list.cpp:305
fawkes::ThreadList::~ThreadList
~ThreadList()
Destructor.
Definition: thread_list.cpp:132
fawkes::InterruptibleBarrier::wait
bool wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
Wait for other threads.
Definition: interruptible_barrier.cpp:231
fawkes::ThreadList::erase
ThreadList::iterator erase(iterator pos)
Erase element at given position.
Definition: thread_list.cpp:875
fawkes::ThreadList::push_back
void push_back(Thread *thread)
Add thread to the end.
Definition: thread_list.cpp:773
fawkes::RefPtr
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:50
fawkes::ThreadListSealedException::ThreadListSealedException
ThreadListSealedException(const char *operation)
Constructor.
Definition: thread_list.cpp:53
fawkes::ThreadListNotSealedException::ThreadListNotSealedException
ThreadListNotSealedException(const char *format,...)
Constructor.
Definition: thread_list.cpp:71
fawkes::MutexLocker
Mutex locking helper.
Definition: mutex_locker.h:34
fawkes::LockList
List with a lock.
Definition: lock_list.h:45
fawkes::ThreadInitializer::init
virtual void init(Thread *thread)=0
This method is called by the ThreadManager for each newly added Thread.
fawkes::ThreadListSealedException
Thread list sealed exception.
Definition: thread_list.h:44
fawkes::CannotInitializeThreadException
Thread cannot be initialized.
Definition: thread_initializer.h:34
fawkes::ThreadList::set_prepfin_hold
void set_prepfin_hold(bool hold)
Set prepfin hold on all threads.
Definition: thread_list.cpp:632
fawkes::Exception::append
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
fawkes::ThreadList::cancel
void cancel()
Cancel threads.
Definition: thread_list.cpp:472
fawkes::LockList< Thread * >::mutex
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
Definition: lock_list.h:172
fawkes::ThreadList::push_front_locked
void push_front_locked(Thread *thread)
Add thread to the front with lock protection.
Definition: thread_list.cpp:757
fawkes::InterruptibleBarrier::passed_threads
RefPtr< ThreadList > passed_threads()
Get a list of threads that passed the barrier.
Definition: interruptible_barrier.cpp:177
fawkes::ThreadList::name
const char * name()
Name of the thread list.
Definition: thread_list.cpp:690
fawkes
Fawkes library namespace.
fawkes::ThreadList::operator=
ThreadList & operator=(const ThreadList &tl)
Assignment operator.
Definition: thread_list.cpp:144
fawkes::ThreadList::finalize
void finalize(ThreadFinalizer *finalizer)
Finalize Threads.
Definition: thread_list.cpp:580
fawkes::ThreadList::pop_front
void pop_front()
Remove first element.
Definition: thread_list.cpp:848
fawkes::ThreadList::prepare_finalize
bool prepare_finalize(ThreadFinalizer *finalizer)
Prepare finalize.
Definition: thread_list.cpp:532
fawkes::InterruptibleBarrier::no_threads_in_wait
bool no_threads_in_wait()
Checks if there are no more threads in the wait() function.
Definition: interruptible_barrier.cpp:321
fawkes::ThreadList::remove_locked
void remove_locked(Thread *thread)
Remove with lock protection.
Definition: thread_list.cpp:835
fawkes::ThreadList::join
void join()
Join threads.
Definition: thread_list.cpp:497
fawkes::ThreadFinalizer
Thread finalizer interface.
Definition: thread_finalizer.h:41
fawkes::Thread
Thread class encapsulation of pthreads.
Definition: thread.h:46
fawkes::ThreadList::pop_back
void pop_back()
Remove last element.
Definition: thread_list.cpp:860
fawkes::ThreadFinalizer::finalize
virtual void finalize(Thread *thread)=0
Finalize a thread.
fawkes::ThreadList::stop
void stop()
Stop threads.
Definition: thread_list.cpp:511
fawkes::Barrier::count
unsigned int count()
Get number of threads this barrier will wait for.
Definition: barrier.cpp:176
fawkes::NullPointerException
A NULL pointer was supplied where not allowed.
Definition: software.h:32
fawkes::ThreadList::init
void init(ThreadInitializer *initializer, ThreadFinalizer *finalizer)
Initialize threads.
Definition: thread_list.cpp:374
fawkes::OutOfMemoryException
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:32
fawkes::Barrier
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
Definition: barrier.h:32
fawkes::ThreadInitializer
Thread initializer interface.
Definition: thread_initializer.h:42
fawkes::CannotFinalizeThreadException
Thread cannot be finalized.
Definition: thread_finalizer.h:34
fawkes::ThreadList::try_recover
void try_recover(std::list< std::string > &recovered_threads)
Check if any of the bad barriers recovered.
Definition: thread_list.cpp:327
fawkes::ThreadFinalizer::prepare_finalize
virtual bool prepare_finalize(Thread *thread)=0
Prepare finalization of a thread.
fawkes::ThreadList::start
void start()
Start threads.
Definition: thread_list.cpp:447
fawkes::ThreadList::push_front
void push_front(Thread *thread)
Add thread to the front.
Definition: thread_list.cpp:738
fawkes::ThreadList::ThreadList
ThreadList(const char *tlname="")
Constructor.
Definition: thread_list.cpp:92
fawkes::ThreadList::push_back_locked
void push_back_locked(Thread *thread)
Add thread to the end with lock protection.
Definition: thread_list.cpp:792
fawkes::ThreadList
List of threads.
Definition: thread_list.h:56
fawkes::ThreadList::wakeup_unlocked
void wakeup_unlocked()
Wakeup all threads in list.
Definition: thread_list.cpp:173
fawkes::Thread::FLAG_BAD
static const unsigned int FLAG_BAD
Standard thread flag: "thread is bad".
Definition: thread.h:69
fawkes::ThreadList::cancel_finalize
void cancel_finalize()
Cancel finalization on all threads.
Definition: thread_list.cpp:615
fawkes::ThreadList::seal
void seal()
Seal the list.
Definition: thread_list.cpp:728
fawkes::ThreadList::wakeup_and_wait
void wakeup_and_wait(unsigned int timeout_sec=0, unsigned int timeout_nanosec=0)
Wakeup threads and wait for them to finish.
Definition: thread_list.cpp:241
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36