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
39namespace 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 */
92ThreadList::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 */
107ThreadList::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 */
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. */
158void
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 */
172void
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 */
183void
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 */
198void
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 */
240void
241ThreadList::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 */
304void
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 */
326void
327ThreadList::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 */
373void
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
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 */
446void
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 */
471void
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 */
496void
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 */
510void
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 */
531bool
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 */
579void
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 */
614void
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 */
631void
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 */
654void
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 */
689const char *
691{
692 return name_;
693}
694
695/** Set name of thread.
696 * Use parameters similar to printf().
697 * @param format format string
698 */
699void
700ThreadList::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 */
720bool
722{
723 return sealed_;
724}
725
726/** Seal the list. */
727void
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 */
737void
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 */
756void
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 */
772void
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 */
791void
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 */
806void
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 */
820void
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 */
834void
836{
837 if (sealed_)
838 throw ThreadListSealedException("remove_locked");
839
842 if (wnw_barrier_)
843 update_barrier();
844}
845
846/** Remove first element. */
847void
849{
850 if (sealed_)
851 throw ThreadListSealedException("pop_front");
852
854 if (wnw_barrier_)
855 update_barrier();
856}
857
858/** Remove last element. */
859void
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 */
874ThreadList::iterator
875ThreadList::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. */
887void
888ThreadList::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. */
906void
907ThreadList::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
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
Definition: barrier.h:32
unsigned int count()
Get number of threads this barrier will wait for.
Definition: barrier.cpp:176
Thread cannot be finalized.
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what() const noexcept
Get primary string.
Definition: exception.cpp:639
void append_va(const char *format, va_list va) noexcept
Append messages to the message list.
Definition: exception.cpp:353
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
bool wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
Wait for other threads.
bool no_threads_in_wait()
Checks if there are no more threads in the wait() function.
RefPtr< ThreadList > passed_threads()
Get a list of threads that passed the barrier.
List with a lock.
Definition: lock_list.h:45
LockList< Type > & operator=(const LockList< Type > &ll)
Copy values from another LockList.
Definition: lock_list.h:179
virtual void lock() const
Lock list.
Definition: lock_list.h:124
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
Definition: lock_list.h:172
Mutex locking helper.
Definition: mutex_locker.h:34
Mutex mutual exclusion lock.
Definition: mutex.h:33
A NULL pointer was supplied where not allowed.
Definition: software.h:32
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:32
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:50
Thread finalizer interface.
virtual bool prepare_finalize(Thread *thread)=0
Prepare finalization of a thread.
virtual void finalize(Thread *thread)=0
Finalize a thread.
Thread initializer interface.
virtual void init(Thread *thread)=0
This method is called by the ThreadManager for each newly added Thread.
ThreadListNotSealedException(const char *format,...)
Constructor.
Definition: thread_list.cpp:71
Thread list sealed exception.
Definition: thread_list.h:44
ThreadListSealedException(const char *operation)
Constructor.
Definition: thread_list.cpp:53
List of threads.
Definition: thread_list.h:56
void wakeup_unlocked()
Wakeup all threads in list.
void remove_locked(Thread *thread)
Remove with lock protection.
ThreadList::iterator erase(iterator pos)
Erase element at given position.
void push_front_locked(Thread *thread)
Add thread to the front with lock protection.
void clear()
Clear the list.
bool prepare_finalize(ThreadFinalizer *finalizer)
Prepare finalize.
void set_prepfin_hold(bool hold)
Set prepfin hold on all threads.
void init(ThreadInitializer *initializer, ThreadFinalizer *finalizer)
Initialize threads.
ThreadList & operator=(const ThreadList &tl)
Assignment operator.
void finalize(ThreadFinalizer *finalizer)
Finalize Threads.
void set_name(const char *format,...)
Set name of thread.
void cancel()
Cancel threads.
~ThreadList()
Destructor.
void stop()
Stop threads.
void wakeup()
Wakeup all threads in list.
void pop_front()
Remove first element.
void try_recover(std::list< std::string > &recovered_threads)
Check if any of the bad barriers recovered.
void push_back_locked(Thread *thread)
Add thread to the end with lock protection.
void remove(Thread *thread)
Remove with lock protection.
const char * name()
Name of the thread list.
void force_stop(ThreadFinalizer *finalizer)
Force stop of all threads.
void cancel_finalize()
Cancel finalization on all threads.
void pop_back()
Remove last element.
void push_front(Thread *thread)
Add thread to the front.
ThreadList(const char *tlname="")
Constructor.
Definition: thread_list.cpp:92
void set_maintain_barrier(bool maintain_barrier)
Set if this thread list should maintain a barrier.
bool sealed()
Check if list is sealed.
void join()
Join threads.
void start()
Start threads.
void seal()
Seal the list.
void wakeup_and_wait(unsigned int timeout_sec=0, unsigned int timeout_nanosec=0)
Wakeup threads and wait for them to finish.
void push_back(Thread *thread)
Add thread to the end.
Thread class encapsulation of pthreads.
Definition: thread.h:46
static const unsigned int FLAG_BAD
Standard thread flag: "thread is bad".
Definition: thread.h:69
Fawkes library namespace.