00001 #ifndef ITHREAD_IMPLEMENTATION_FILE
00002 #define ITHREAD_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "ithread.h"
00019 #include "time_stamp.h"
00020
00021 #include <basis/function.h>
00022 #include <basis/guards.h>
00023 #include <basis/istring.h>
00024 #include <basis/log_base.h>
00025 #include <basis/portable.h>
00026 #include <data_struct/static_memory_gremlin.h>
00027
00028 #ifdef __WIN32__
00029 #include <process.h>
00030 #elif defined(__UNIX__)
00031 #include <pthread.h>
00032 #else
00033 #error unknown OS for thread support.
00034 #endif
00035
00036
00037
00038
00039
00040 #undef LOG
00041 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00042
00043 const int MAXIMUM_CREATE_ATTEMPTS = 20;
00044
00045
00046
00047 const int MINIMUM_SLEEP_PERIOD = 10;
00048
00049
00050 const int MAXIMUM_SLEEP_PERIOD = 200;
00051
00052
00053 const int SNOOZE_FOR_RETRY = 100;
00054
00055
00056 #ifdef COUNT_THREADS
00057
00058 class thread_counter : public virtual object_base {
00059 public:
00060 thread_counter() : _count(0) {}
00061 IMPLEMENT_CLASS_NAME("thread_counter");
00062 void increment() {
00063 auto_synchronizer l(_lock);
00064 _count++;
00065 }
00066 void decrement() {
00067 auto_synchronizer l(_lock);
00068 _count--;
00069 }
00070 private:
00071 int _count;
00072 mutex _lock;
00073 };
00074
00075 SAFE_STATIC(thread_counter, _current_threads, )
00076
00077
00078
00079
00080 #endif
00081
00082 ithread::ithread()
00083 : _thread_ready(false),
00084 _thread_active(false),
00085 _stop_thread(false),
00086 _data(NIL),
00087 #ifdef __UNIX__
00088 _handle(new pthread_t),
00089 #elif defined(__WIN32__)
00090 _handle(0),
00091 #endif
00092 _sleep_time(0),
00093 _periodic(false),
00094 _next_activation(new time_stamp),
00095 _how(TIGHT_INTERVAL)
00096 {
00097 FUNCDEF("constructor [one-shot]");
00098 }
00099
00100 ithread::ithread(int sleep_timer, timed_thread_types how)
00101 : _thread_ready(false),
00102 _thread_active(false),
00103 _stop_thread(false),
00104 _data(NIL),
00105 #ifdef __UNIX__
00106 _handle(new pthread_t),
00107 #elif defined(__WIN32__)
00108 _handle(0),
00109 #endif
00110 _sleep_time(sleep_timer),
00111 _periodic(true),
00112 _next_activation(new time_stamp),
00113 _how(how)
00114 {
00115 FUNCDEF("constructor [periodic]");
00116 if (sleep_timer < MINIMUM_SLEEP_PERIOD) {
00117 _sleep_time = MINIMUM_SLEEP_PERIOD;
00118 }
00119 }
00120
00121 ithread::~ithread()
00122 {
00123 stop();
00124 WHACK(_next_activation);
00125 #ifdef __UNIX__
00126 WHACK(_handle);
00127 #endif
00128 }
00129
00130 void ithread::pre_thread() {}
00131
00132 void ithread::post_thread() {}
00133
00134
00135
00136
00137 void ithread::reschedule()
00138 {
00139 reschedule(-1);
00140 }
00141
00142 void ithread::reschedule(int delay)
00143 {
00144 *_next_activation = time_stamp(delay);
00145 }
00146
00147 bool ithread::start(void *thread_data)
00148 {
00149 FUNCDEF("start");
00150 if (!thread_finished()) return false;
00151 _data = thread_data;
00152 _stop_thread = false;
00153 _thread_ready = true;
00154 _next_activation->reset();
00155 bool success = false;
00156 int error = 0;
00157 int attempts = 0;
00158 while (attempts++ < MAXIMUM_CREATE_ATTEMPTS) {
00159 #ifdef __UNIX__
00160 pthread_attr_t attribs;
00161 int aret = pthread_attr_init(&attribs);
00162 if (aret) LOG("failed to init attribs.");
00163 aret = pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED);
00164 if (aret) LOG("failed to set detach state.");
00165 int ret = -1;
00166 if (_periodic)
00167 ret = pthread_create(_handle, &attribs, periodic_thread_driver,
00168 (void *)this);
00169 else
00170 ret = pthread_create(_handle, &attribs, one_shot_thread_driver,
00171 (void *)this);
00172 if (!ret) success = true;
00173 else error = ret;
00174 #elif defined(__WIN32__)
00175 if (_periodic)
00176 _handle = _beginthread(periodic_thread_driver, 0, (void *)this);
00177 else
00178 _handle = _beginthread(one_shot_thread_driver, 0, (void *)this);
00179 if (_handle != -1) success = true;
00180 else error = portable::system_error();
00181 #endif
00182 if (success) break;
00183 LOG("failed to create thread; trying again...");
00184 portable::sleep_ms(SNOOZE_FOR_RETRY);
00185 }
00186 if (!success) {
00187
00188 LOG(istring("failed to create thread, error is ")
00189 + portable::system_error_text(error));
00190 exempt_stop();
00191 return false;
00192 }
00193 return true;
00194 }
00195
00196 void ithread::stop()
00197 {
00198 cancel();
00199 if (!thread_started()) return;
00200 while (!thread_finished()) {
00201 #ifdef __WIN32__
00202 int result = 0;
00203 if (!GetExitCodeThread((HANDLE)_handle, (LPDWORD)&result)
00204 || (result != STILL_ACTIVE)) {
00205 exempt_stop();
00206 break;
00207 }
00208 #endif
00209 portable::sleep_ms(10);
00210 }
00211 }
00212
00213 void ithread::exempt_stop()
00214 {
00215 _thread_active = false;
00216 _thread_ready = false;
00217 #ifdef __WIN32__
00218 _handle = 0;
00219 #endif
00220 }
00221
00222 #ifdef __UNIX__
00223 void *ithread::one_shot_thread_driver(void *hidden_pointer)
00224 #elif defined(__WIN32__)
00225 void ithread::one_shot_thread_driver(void *hidden_pointer)
00226 #else
00227 #error unknown thread signature.
00228 #endif
00229 {
00230 FUNCDEF("one_shot_thread_driver");
00231 ithread *manager = (ithread *)hidden_pointer;
00232 #ifdef __UNIX__
00233 if (!manager) return NIL;
00234 #else
00235 if (!manager) return;
00236 #endif
00237 #ifdef COUNT_THREADS
00238 _current_threads().increment();
00239 #endif
00240 manager->pre_thread();
00241 manager->_thread_active = true;
00242 manager->perform_activity(manager->_data);
00243 manager->post_thread();
00244 manager->exempt_stop();
00245 #ifdef COUNT_THREADS
00246 _current_threads().decrement();
00247 #endif
00248 #ifdef __UNIX__
00249 pthread_exit(NIL);
00250 return NIL;
00251 #else
00252 _endthread();
00253 #endif
00254 }
00255
00256 #ifdef __UNIX__
00257 void *ithread::periodic_thread_driver(void *hidden_pointer)
00258 #elif defined(__WIN32__)
00259 void ithread::periodic_thread_driver(void *hidden_pointer)
00260 #else
00261 #error unknown thread signature.
00262 #endif
00263 {
00264 FUNCDEF("periodic_thread_driver");
00265 ithread *manager = (ithread *)hidden_pointer;
00266 #ifdef __UNIX__
00267 if (!manager) return NIL;
00268 #elif defined(__WIN32__)
00269 if (!manager) return;
00270 #endif
00271 #ifdef COUNT_THREADS
00272 _current_threads().increment();
00273 #endif
00274 manager->pre_thread();
00275
00276 while (!manager->_stop_thread) {
00277
00278
00279
00280
00281
00282 if (manager->_how == TIGHT_INTERVAL)
00283 *manager->_next_activation = time_stamp(manager->_sleep_time);
00284
00285 manager->_thread_active = true;
00286 manager->perform_activity(manager->_data);
00287 manager->_thread_active = false;
00288
00289
00290
00291
00292 if (manager->_how == SLACK_INTERVAL)
00293 *manager->_next_activation = time_stamp(manager->_sleep_time);
00294
00295
00296
00297
00298 while (!manager->_stop_thread) {
00299 int time_diff = int(manager->_next_activation->value()
00300 - time_stamp().value());
00301 if (time_diff < 0) time_diff = 0;
00302
00303 if (manager->_how == SLACK_INTERVAL) {
00304 if (time_diff < MINIMUM_SLEEP_PERIOD)
00305 time_diff = MINIMUM_SLEEP_PERIOD;
00306 }
00307 if (time_diff > MAXIMUM_SLEEP_PERIOD)
00308 time_diff = MAXIMUM_SLEEP_PERIOD;
00309 if (!manager->_stop_thread)
00310 portable::sleep_ms(time_diff);
00311 if (time_stamp() >= *manager->_next_activation)
00312 break;
00313 }
00314 }
00315 manager->post_thread();
00316 manager->exempt_stop();
00317 #ifdef COUNT_THREADS
00318 _current_threads().decrement();
00319 #endif
00320 #ifdef __UNIX__
00321 pthread_exit(NIL);
00322 return NIL;
00323 #elif defined(__WIN32__)
00324 _endthread();
00325 #endif
00326 }
00327
00328
00329 #endif //ITHREAD_IMPLEMENTATION_FILE
00330