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  try {
382  initializer->init(*i);
383  } catch (Exception &e) {
384  cite.append("Initialized failed to initialize thread '%s'", (*i)->name());
385  cite.append(e);
386  success = false;
387  break;
388  }
389  // if the thread's init() method fails, we need to finalize that very
390  // thread only with the finalizer, already initialized threads muts be
391  // fully finalized
392  try {
393  (*i)->init();
394  initialized_threads.push_back(*i);
395  } catch (CannotInitializeThreadException &e) {
396  notify_of_failed_init();
397  cite.append("Initializing thread '%s' in list '%s' failed", (*i)->name(), name_);
398  cite.append(e);
399  finalizer->finalize(*i);
400  success = false;
401  break;
402  } catch (Exception &e) {
403  notify_of_failed_init();
404  cite.append(e);
405  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
406  finalizer->finalize(*i);
407  success = false;
408  break;
409  } catch (std::exception &e) {
410  notify_of_failed_init();
411  cite.append("Caught std::exception: %s", e.what());
412  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
413  finalizer->finalize(*i);
414  success = false;
415  break;
416  } catch (...) {
417  notify_of_failed_init();
418  cite.append("Could not initialize thread '%s' (ThreadList %s)", (*i)->name(), name());
419  cite.append("Unknown exception caught");
420  finalizer->finalize(*i);
421  success = false;
422  break;
423  }
424  }
425 
426  if (!success) {
427  initialized_threads.finalize(finalizer);
428  throw cite;
429  }
430 }
431 
432 /** Start threads.
433  * The threads are started.
434  * This operation is carried out unlocked. Lock it from the outside if needed.
435  * This is done because it is likely that this will be chained with other
436  * actions that require locking, thus you can lock the whole operation.
437  */
438 void
440 {
441  for (iterator i = begin(); i != end(); ++i) {
442  (*i)->start();
443  }
444 }
445 
446 /** Cancel threads.
447  * The threads are canceled.
448  * This operation is carried out unlocked. Lock it from the outside if needed.
449  * This is done because it is likely that this will be chained with other
450  * actions that require locking, thus you can lock the whole operation.
451  *
452  * This is especially handy for detached threads. Since errorneous behavior
453  * has been seen when run inside gdb something like
454  * @code
455  * tl.cancel();
456  * tl.join();
457  * @endcode
458  * shout be avoided. Instead use
459  * @code
460  * tl.stop();
461  * @endcode
462  */
463 void
465 {
466  for (iterator i = begin(); i != end(); ++i) {
467  (*i)->cancel();
468  }
469 }
470 
471 /** Join threads.
472  * The threads are joined.
473  * This operation is carried out unlocked. Lock it from the outside if needed.
474  * This is done because it is likely that this will be chained with other
475  * actions that require locking, thus you can lock the whole operation.
476  *
477  * Since errorneous behavior
478  * has been seen when run inside gdb something like
479  * @code
480  * tl.cancel();
481  * tl.join();
482  * @endcode
483  * shout be avoided. Instead use
484  * @code
485  * tl.stop();
486  * @endcode
487  */
488 void
490 {
491  for (iterator i = begin(); i != end(); ++i) {
492  (*i)->join();
493  }
494 }
495 
496 /** Stop threads.
497  * The threads are canceled and joined.
498  * This operation is carried out unlocked. Lock it from the outside if needed.
499  * This is done because it is likely that this will be chained with other
500  * actions that require locking, thus you can lock the whole operation.
501  */
502 void
504 {
505  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
506  (*i)->cancel();
507  (*i)->join();
508  // Workaround for pthreads annoyance
509  usleep(5000);
510  }
511 }
512 
513 /** Prepare finalize.
514  * The threads are prepared for finalization. If any of the threads return
515  * false the whole list will return false.
516  * This operation is carried out unlocked. Lock it from the outside if needed.
517  * This is done because it is likely that this will be chained with other
518  * actions that require locking, thus you can lock the whole operation.
519  * @param finalizer thread finalizer to use to prepare finalization of the threads
520  * @return true, if prepare_finalize() returned true for all threads in the
521  * list, false if at least one thread returned false.
522  */
523 bool
525 {
526  MutexLocker lock(finalize_mutex_);
527 
528  bool can_finalize = true;
529  CannotFinalizeThreadException cfte("Cannot finalize one or more threads");
530  bool threw_exception = false;
531  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
532  // Note that this loop may NOT be interrupted in the middle by break,
533  // since even if the thread denies finalization it can still be finalized
534  // and we have to ensure that every thread got a call to prepare_finalize()!
535  try {
536  if (!finalizer->prepare_finalize(*i)) {
537  can_finalize = false;
538  }
539  if (!(*i)->prepare_finalize()) {
540  can_finalize = false;
541  }
542  } catch (CannotFinalizeThreadException &e) {
543  cfte.append("Thread '%s' threw an exception while preparing finalization of "
544  "ThreadList '%s' (IGNORED)",
545  (*i)->name(),
546  name_);
547  cfte.append(e);
548  threw_exception = true;
549  } catch (Exception &e) {
550  cfte.append("Thread '%s' threw a generic exception while preparing finalization of "
551  "ThreadList '%s' (IGNORED)",
552  (*i)->name(),
553  name_);
554  cfte.append(e);
555  threw_exception = true;
556  }
557  }
558  if (threw_exception) {
559  throw cfte;
560  }
561  return can_finalize;
562 }
563 
564 /** Finalize Threads.
565  * The threads are finalized.
566  * This operation is carried out unlocked. Lock it from the outside if needed.
567  * This is done because it is likely that this will be chained with other
568  * actions that require locking, thus you can lock the whole operation.
569  * @param finalizer thread finalizer to use to finalize the threads
570  */
571 void
573 {
574  bool error = false;
575  Exception me("One or more threads failed to finalize");
576  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
577  try {
578  (*i)->finalize();
579  } catch (CannotFinalizeThreadException &e) {
580  error = true;
581  me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name());
582  me.append(e);
583  } catch (Exception &e) {
584  error = true;
585  me.append("AspectIniFin called Thread[%s]::finalize() which failed", (*i)->name());
586  me.append(e);
587  } catch (...) {
588  error = true;
589  me.append("Thread[%s]::finalize() threw unsupported exception", (*i)->name());
590  }
591  try {
592  finalizer->finalize(*i);
593  } catch (CannotFinalizeThreadException &e) {
594  error = true;
595  me.append("Could not finalize thread '%s' in list '%s'", (*i)->name(), name_);
596  me.append(e);
597  }
598  }
599  if (error) {
600  throw me;
601  }
602 }
603 
604 /** Cancel finalization on all threads.
605  */
606 void
608 {
609  MutexLocker lock(finalize_mutex_);
610 
611  for (reverse_iterator i = rbegin(); i != rend(); ++i) {
612  (*i)->cancel_finalize();
613  }
614 }
615 
616 /** Set prepfin hold on all threads.
617  * This method will call Thread::set_prepfin_hold() for all threads in the list. If
618  * any of the threads fails to set prepfin hold then all thread were it has already
619  * been set are set to prepfin hold false.
620  * @param hold prepfin hold value
621  * @see Thread::set_prepfin_hold()
622  */
623 void
625 {
626  iterator i;
627  try {
628  for (i = begin(); i != end(); ++i) {
629  (*i)->set_prepfin_hold(hold);
630  }
631  } catch (Exception &e) {
632  // boom, we failed, at least one thread was already in the state of being prepared
633  // for finalization, rollback the hold for the threads were we already set it
634  for (iterator j = begin(); j != i; ++j) {
635  (*j)->set_prepfin_hold(false);
636  }
637  throw;
638  }
639 }
640 
641 /** Force stop of all threads.
642  * This will call prepare_finalize(), finalize(), cancel() and join() on the
643  * list without caring about the return values in the prepare_finalize() step.
644  * @param finalizer thread finalizer to use to finalize the threads.
645  */
646 void
648 {
649  bool caught_exception = false;
650  Exception exc("Forced thread finalization failed");
651  ;
652  try {
653  prepare_finalize(finalizer);
654  } catch (Exception &e) {
655  caught_exception = true;
656  exc.append(e);
657  }
658  try {
659  stop();
660  } catch (Exception &e) {
661  caught_exception = true;
662  exc.append(e);
663  }
664  try {
665  finalize(finalizer);
666  } catch (Exception &e) {
667  caught_exception = true;
668  exc.append(e);
669  }
670 
671  if (caught_exception) {
672  throw exc;
673  }
674 }
675 
676 /** Name of the thread list.
677  * This can be used for better log output to identify the list that causes
678  * problems.
679  * @return name of thread list
680  */
681 const char *
683 {
684  return name_;
685 }
686 
687 /** Set name of thread.
688  * Use parameters similar to printf().
689  * @param format format string
690  */
691 void
692 ThreadList::set_name(const char *format, ...)
693 {
694  va_list va;
695  va_start(va, format);
696 
697  char *tmpname;
698  if (vasprintf(&tmpname, format, va) != -1) {
699  free(name_);
700  name_ = tmpname;
701  } else {
702  throw OutOfMemoryException("ThreadList::set_name(): vasprintf() failed");
703  }
704  va_end(va);
705 }
706 
707 /** Check if list is sealed.
708  * If the list is sealed, no more writing operations are allowed and will trigger
709  * an exception.
710  * @return true, if list is sealed, false otherwise
711  */
712 bool
714 {
715  return sealed_;
716 }
717 
718 /** Seal the list. */
719 void
721 {
722  sealed_ = true;
723 }
724 
725 /** Add thread to the front.
726  * Add thread to the beginning of the list.
727  * @param thread thread to add
728  */
729 void
731 {
732  if (sealed_)
733  throw ThreadListSealedException("push_front");
734 
736  if (wnw_barrier_)
737  update_barrier();
738 }
739 
740 /** Add thread to the front with lock protection.
741  * Add thread to the beginning of the list. The operation is protected
742  * by the thread list lock.
743  * The operation will succeed without blocking even
744  * if the list is currently locked. It will push the thread to an internal temporary
745  * list and will add the thread finally when the list is unlocked.
746  * @param thread thread to add
747  */
748 void
750 {
751  if (sealed_)
752  throw ThreadListSealedException("push_front_locked");
753 
756  if (wnw_barrier_)
757  update_barrier();
758 }
759 
760 /** Add thread to the end.
761  * Add thread to the end of the list.
762  * @param thread thread to add
763  */
764 void
766 {
767  if (sealed_)
768  throw ThreadListSealedException("push_back");
769 
771  if (wnw_barrier_)
772  update_barrier();
773 }
774 
775 /** Add thread to the end with lock protection.
776  * Add thread to the end of the list. The operation is protected
777  * by the thread list lock.
778  * The operation will succeed without blocking even
779  * if the list is currently locked. It will push the thread to an internal temporary
780  * list and will add the thread finally when the list is unlocked.
781  * @param thread thread to add
782  */
783 void
785 {
786  if (sealed_)
787  throw ThreadListSealedException("push_back_locked");
788 
791  if (wnw_barrier_)
792  update_barrier();
793 }
794 
795 /** Clear the list.
796  * Removes all elements.
797  */
798 void
800 {
801  if (sealed_)
802  throw ThreadListSealedException("clear");
803 
805  if (wnw_barrier_)
806  update_barrier();
807 }
808 
809 /** Remove with lock protection.
810  * @param thread thread to remove.
811  */
812 void
814 {
815  if (sealed_)
816  throw ThreadListSealedException("remove_locked");
817 
819  if (wnw_barrier_)
820  update_barrier();
821 }
822 
823 /** Remove with lock protection.
824  * @param thread thread to remove.
825  */
826 void
828 {
829  if (sealed_)
830  throw ThreadListSealedException("remove_locked");
831 
834  if (wnw_barrier_)
835  update_barrier();
836 }
837 
838 /** Remove first element. */
839 void
841 {
842  if (sealed_)
843  throw ThreadListSealedException("pop_front");
844 
846  if (wnw_barrier_)
847  update_barrier();
848 }
849 
850 /** Remove last element. */
851 void
853 {
854  if (sealed_)
855  throw ThreadListSealedException("pop_back");
856 
858  if (wnw_barrier_)
859  update_barrier();
860 }
861 
862 /** Erase element at given position.
863  * @param pos iterator marking the element to remove.
864  * @return iterator to element that follows pos
865  */
866 ThreadList::iterator
867 ThreadList::erase(iterator pos)
868 {
869  if (sealed_)
870  throw ThreadListSealedException("erase");
871 
872  ThreadList::iterator rv = LockList<Thread *>::erase(pos);
873  if (wnw_barrier_)
874  update_barrier();
875  return rv;
876 }
877 
878 /** Update internal barrier. */
879 void
880 ThreadList::update_barrier()
881 {
882  unsigned int num = 1;
883  for (iterator i = begin(); i != end(); ++i) {
884  if (!(*i)->flagged_bad())
885  ++num;
886  }
887  if (wnw_barrier_ == NULL || wnw_barrier_->no_threads_in_wait()) {
888  delete wnw_barrier_;
889  } else {
890  //delete the barrier later in try_recover
891  ThreadList empty_list;
892  wnw_bad_barriers_.push_back(make_pair(wnw_barrier_, empty_list));
893  }
894  wnw_barrier_ = new InterruptibleBarrier(num);
895 }
896 
897 /** Notify all threads of failed init. */
898 void
899 ThreadList::notify_of_failed_init()
900 {
901  for (ThreadList::iterator i = begin(); i != end(); ++i) {
902  (*i)->notify_of_failed_init();
903  }
904 }
905 
906 } // end namespace fawkes
bool sealed()
Check if list is sealed.
ThreadListSealedException(const char *operation)
Constructor.
Definition: thread_list.cpp:53
ThreadListNotSealedException(const char *format,...)
Constructor.
Definition: thread_list.cpp:71
LockList< Type > & operator=(const LockList< Type > &ll)
Copy values from another LockList.
Definition: lock_list.h:179
const char * name()
Name of the thread list.
unsigned int count()
Get number of threads this barrier will wait for.
Definition: barrier.cpp:176
virtual void init(Thread *thread)=0
This method is called by the ThreadManager for each newly added Thread.
void clear()
Clear the list.
void start()
Start threads.
bool no_threads_in_wait()
Checks if there are no more threads in the wait() function.
virtual void lock() const
Lock list.
Definition: lock_list.h:124
void cancel_finalize()
Cancel finalization on all threads.
Fawkes library namespace.
void push_back_locked(Thread *thread)
Add thread to the end with lock protection.
Mutex locking helper.
Definition: mutex_locker.h:33
void seal()
Seal the list.
virtual void finalize(Thread *thread)=0
Finalize a thread.
void set_prepfin_hold(bool hold)
Set prepfin hold on all threads.
void force_stop(ThreadFinalizer *finalizer)
Force stop of all threads.
A NULL pointer was supplied where not allowed.
Definition: software.h:31
void join()
Join threads.
Thread class encapsulation of pthreads.
Definition: thread.h:45
void pop_back()
Remove last element.
bool prepare_finalize(ThreadFinalizer *finalizer)
Prepare finalize.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
Definition: lock_list.h:172
bool wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
Wait for other threads.
Thread list sealed exception.
Definition: thread_list.h:43
void push_front_locked(Thread *thread)
Add thread to the front with lock protection.
virtual bool prepare_finalize(Thread *thread)=0
Prepare finalization of a thread.
List of threads.
Definition: thread_list.h:55
ThreadList & operator=(const ThreadList &tl)
Assignment operator.
ThreadList(const char *tlname="")
Constructor.
Definition: thread_list.cpp:92
Base class for exceptions in Fawkes.
Definition: exception.h:35
void remove_locked(Thread *thread)
Remove with lock protection.
ThreadList::iterator erase(iterator pos)
Erase element at given position.
void init(ThreadInitializer *initializer, ThreadFinalizer *finalizer)
Initialize threads.
void stop()
Stop threads.
Thread initializer interface.
List with a lock.
Definition: thread.h:43
void wakeup()
Wakeup all threads in list.
void finalize(ThreadFinalizer *finalizer)
Finalize Threads.
void pop_front()
Remove first element.
void append_va(const char *format, va_list va)
Append messages to the message list.
Definition: exception.cpp:353
static const unsigned int FLAG_BAD
Standard thread flag: "thread is bad".
Definition: thread.h:69
~ThreadList()
Destructor.
void push_back(Thread *thread)
Add thread to the end.
RefPtr< ThreadList > passed_threads()
Get a list of threads that passed the barrier.
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:49
void wakeup_unlocked()
Wakeup all threads in list.
Thread cannot be finalized.
void set_name(const char *format,...)
Set name of thread.
void try_recover(std::list< std::string > &recovered_threads)
Check if any of the bad barriers recovered.
void set_maintain_barrier(bool maintain_barrier)
Set if this thread list should maintain a barrier.
Mutex mutual exclusion lock.
Definition: mutex.h:32
void push_front(Thread *thread)
Add thread to the front.
void wakeup_and_wait(unsigned int timeout_sec=0, unsigned int timeout_nanosec=0)
Wakeup threads and wait for them to finish.
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
Definition: barrier.h:31
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:31
void cancel()
Cancel threads.
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
void remove(Thread *thread)
Remove with lock protection.
Thread finalizer interface.