feisty meow concerns codebase 2.140
thread_cabinet.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : thread_cabinet *
4* Author : Chris Koeritz *
5* *
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\*****************************************************************************/
14
15#include "ethread.h"
16#include "thread_cabinet.h"
17
19#include <structures/amorph.h>
21#include <timely/time_control.h>
22
23#undef LOCKIT
24#define LOCKIT auto_synchronizer l(*_lock)
25 // grabs the mutex for access to the list.
26
27#undef LOG
28#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
29
30//#define DEBUG_THREAD_CABINET
31 // uncomment for noisier version.
32
33using namespace basis;
34using namespace loggers;
35using namespace structures;
36using namespace timely;
37
38namespace processes {
39
40class thread_record
41{
42public:
43 ethread *_thread;
44 unique_int _id;
45
46 thread_record(const unique_int &id, ethread *t)
47 : _thread(t), _id(id) {}
48
49 ~thread_record() {
50 _thread->stop();
51 WHACK(_thread);
52 }
53};
54
56
57class thread_amorph : public amorph<thread_record>
58{
59public:
60};
61
63
65: _lock(new mutex),
66 _threads(new thread_amorph),
67 _next_id(new int_roller(1, MAXINT32 - 1)),
68 _no_additions(0)
69{
70}
71
73{
74 WHACK(_threads);
75 WHACK(_lock);
76 WHACK(_next_id);
77}
78
79int thread_cabinet::threads() const { return _threads->elements(); }
80
82 void *parm)
83{
84#ifdef DEBUG_THREAD_CABINET
85 FUNCDEF("add_thread");
86#endif
87 LOCKIT;
88 if (_no_additions) {
89#ifdef DEBUG_THREAD_CABINET
90 LOG("no additions flag is true; destroying the thread and failing out.");
91#endif
92 // can't just leave it unhooked hanging out in space...
93 WHACK(to_add);
94 return 0;
95 }
96 int use_id = _next_id->next_id();
97 if (start_it) {
98 to_add->start(parm);
99 } else {
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));
104#endif
105 }
106 _threads->append(new thread_record(use_id, to_add));
107 return use_id;
108}
109
111{
112 LOCKIT;
113 for (int i = 0; i < _threads->elements(); i++) {
114 if (_threads->borrow(i)->_thread->thread_started()) return true;
115 }
116 return false;
117}
118
120{
121 LOCKIT;
122 for (int i = 0; i < _threads->elements(); i++) {
123 if (_threads->borrow(i)->_thread->thread_finished()) {
124 _threads->borrow(i)->_thread->start(ptr);
125 }
126 }
127}
128
130{
131 FUNCDEF("cancel_all");
132 {
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();
137 }
138 }
139 LOCKIT;
140 _no_additions--; // allow new threads again.
141 if (_no_additions < 0)
142 continuable_error(class_name(), func, "error in logic regarding "
143 "no additions.");
144}
145
147{
148 FUNCDEF("stop_all");
149 {
150 LOCKIT; // short lock.
151 _no_additions++; // keep people from adding new threads.
152 }
153 cancel_all(); // signal all threads to leave.
154 // pause to give them a little while to leave.
156 while (true) {
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.
161 }
162 LOCKIT;
163 _no_additions--; // allow new threads again.
164 if (_no_additions < 0)
165 continuable_error(class_name(), func, "error in logic regarding "
166 "no additions.");
167}
168
170{
171 LOCKIT;
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.
175 _threads->zap(i, i);
176 return true;
177 }
178 }
179 return false;
180}
181
183{
184 LOCKIT;
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();
189 return true;
190 }
191 }
192 return false;
193}
194
196{
197#ifdef DEBUG_THREAD_CABINET
198 FUNCDEF("clean_debris");
199#endif
200 LOCKIT;
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));
206#endif
207 _threads->zap(i, i);
208 i--; // skip back before the whack.
209 }
210 }
211}
212
214{
215 LOCKIT;
216 int_set to_return;
217 for (int i = 0; i < _threads->elements(); i++)
218 to_return += _threads->borrow(i)->_id.raw_id();
219 return to_return;
220}
221
223{
224 LOCKIT;
225 thread_record *rec = _threads->borrow(index);
226 if (rec) return rec->_thread;
227 return NULL_POINTER;
228}
229
230} //namespace.
231
#define LOG(s)
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Provides a platform-independent object for adding threads to a program.
Definition ethread.h:36
bool cancel_thread(const structures::unique_int &to_cancel)
shuts down the thread "to_cancel" as quickly as possible.
bool any_running() const
returns true if any threads are currently running.
bool zap_thread(const structures::unique_int &to_whack)
removes the thread with the id "to_whack".
structures::unique_int add_thread(ethread *to_add, bool start_it, void *parm)
adds a thread to be managed by the thread_cabinet.
void start_all(void *pointer)
cranks up any threads that are not already running.
structures::int_set thread_ids() const
returns the identifiers of all threads managed by this object.
void cancel_all()
signals to all threads that they should exit as soon as possible.
void clean_debris()
clean out threads that have finished.
int threads() const
number of threads being managed here.
ethread * get_thread(int index)
this returns the thread at "index" in our list.
void stop_all()
makes all of the threads quit.
A roller that's based on integers. This is the most common type so far.
Definition roller.h:79
A simple object that wraps a templated set of ints.
Definition set.h:156
contents next_id()
returns a unique (per instance of this type) id.
Definition roller.h:105
A unique identifier based on integers.
Definition unique_id.h:97
static void sleep_ms(basis::un_int msec)
a system independent name for a forced snooze measured in milliseconds.
#define continuable_error(c, f, i)
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define MAXINT32
Maximum 32-bit integer value.
Definition definitions.h:75
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#include <time.h>
#define LOCKIT