1 /*****************************************************************************\
3 * Name : thread_cabinet *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
16 #include "thread_cabinet.h"
18 #include <loggers/critical_events.h>
19 #include <structures/amorph.h>
20 #include <structures/unique_id.h>
21 #include <timely/time_control.h>
24 #define LOCKIT auto_synchronizer l(*_lock)
25 // grabs the mutex for access to the list.
28 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
30 //#define DEBUG_THREAD_CABINET
31 // uncomment for noisier version.
33 using namespace basis;
34 using namespace loggers;
35 using namespace structures;
36 using namespace timely;
46 thread_record(const unique_int &id, ethread *t)
47 : _thread(t), _id(id) {}
57 class thread_amorph : public amorph<thread_record>
64 thread_cabinet::thread_cabinet()
66 _threads(new thread_amorph),
67 _next_id(new int_roller(1, MAXINT32 - 1)),
72 thread_cabinet::~thread_cabinet()
79 int thread_cabinet::threads() const { return _threads->elements(); }
81 unique_int thread_cabinet::add_thread(ethread *to_add, bool start_it,
84 #ifdef DEBUG_THREAD_CABINET
85 FUNCDEF("add_thread");
89 #ifdef DEBUG_THREAD_CABINET
90 LOG("no additions flag is true; destroying the thread and failing out.");
92 // can't just leave it unhooked hanging out in space...
96 int use_id = _next_id->next_id();
100 #ifdef DEBUG_THREAD_CABINET
101 if (to_add->thread_finished())
102 LOG(a_sprintf("thread %x is not going to be started and it "
103 "hasn't started yet!", to_add));
106 _threads->append(new thread_record(use_id, to_add));
110 bool thread_cabinet::any_running() const
113 for (int i = 0; i < _threads->elements(); i++) {
114 if (_threads->borrow(i)->_thread->thread_started()) return true;
119 void thread_cabinet::start_all(void *ptr)
122 for (int i = 0; i < _threads->elements(); i++) {
123 if (_threads->borrow(i)->_thread->thread_finished()) {
124 _threads->borrow(i)->_thread->start(ptr);
129 void thread_cabinet::cancel_all()
131 FUNCDEF("cancel_all");
133 LOCKIT; // short lock.
134 _no_additions++; // keep people from adding new threads.
135 for (int i = 0; i < _threads->elements(); i++) {
136 _threads->borrow(i)->_thread->cancel();
140 _no_additions--; // allow new threads again.
141 if (_no_additions < 0)
142 continuable_error(class_name(), func, "error in logic regarding "
146 void thread_cabinet::stop_all()
150 LOCKIT; // short lock.
151 _no_additions++; // keep people from adding new threads.
153 cancel_all(); // signal all threads to leave.
154 // pause to give them a little while to leave.
155 time_control::sleep_ms(20);
157 LOCKIT; // short lock.
158 if (!_threads->elements()) break; // done; nothing left.
159 clean_debris(); // remove any that did stop.
160 time_control::sleep_ms(20); // snooze for a short while.
163 _no_additions--; // allow new threads again.
164 if (_no_additions < 0)
165 continuable_error(class_name(), func, "error in logic regarding "
169 bool thread_cabinet::zap_thread(const unique_int &to_whack)
172 for (int i = 0; i < _threads->elements(); i++) {
173 if (_threads->borrow(i)->_id == to_whack) {
174 // this is the one they want zapped.
182 bool thread_cabinet::cancel_thread(const unique_int &to_cancel)
185 for (int i = 0; i < _threads->elements(); i++) {
186 if (_threads->borrow(i)->_id == to_cancel) {
187 // this is the one to signal regarding its own demise.
188 _threads->borrow(i)->_thread->cancel();
195 void thread_cabinet::clean_debris()
197 #ifdef DEBUG_THREAD_CABINET
198 FUNCDEF("clean_debris");
201 for (int i = 0; i < _threads->elements(); i++) {
202 if (_threads->borrow(i)->_thread->thread_finished()) {
203 // this one's no longer doing anything.
204 #ifdef DEBUG_THREAD_CABINET
205 LOG(a_sprintf("clearing thread %x out.", _threads->borrow(i)->_thread));
208 i--; // skip back before the whack.
213 int_set thread_cabinet::thread_ids() const
217 for (int i = 0; i < _threads->elements(); i++)
218 to_return += _threads->borrow(i)->_id.raw_id();
222 ethread *thread_cabinet::get_thread(int index)
225 thread_record *rec = _threads->borrow(index);
226 if (rec) return rec->_thread;