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