00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00033 #include <s3fc/s3_thread_base.h>
00034 #include <s3fc/s3_macros.h>
00035 #include <signal.h>
00036 #include <errno.h>
00037 #include <sstream>
00038 #include <iostream>
00039
00040
00041 const pthread_t s3_thread_base::invalid_thread_id = (pthread_t)(-1);
00042
00043
00044 s3_thread_base::s3_thread_base() :
00045 started(false),
00046 detached(false),
00047 thread_id(invalid_thread_id)
00048 {
00049 pthread_attr_init(&thread_attr);
00050 }
00051
00052
00053 s3_thread_base::~s3_thread_base()
00054 {
00055 if (is_running())
00056 {
00057 throw s3_generic_exception("s3_thread_base::~s3_thread_base(): ",
00058 "is_running() == true");
00059 }
00060 pthread_attr_destroy(&thread_attr);
00061 }
00062
00063
00064
00065 void s3_thread_base::start()
00066 {
00067
00068 if ( started )
00069 {
00070 throw s3_generic_exception("s3_thread_base::start()",
00071 "Attempt to start() an already "
00072 "start()'ed thread");
00073 }
00074
00075 if ( thread_id != invalid_thread_id )
00076 {
00077 throw s3_generic_exception("s3_thread_base::start()",
00078 "Attempt to start() an instance "
00079 "that was not joined after last stop.");
00080 }
00081
00082 term_request = false;
00083 started = true;
00084 if (detached)
00085 {
00086 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED)
00087 != 0 )
00088 {
00089 throw s3_generic_exception("s3_thread_base::start()",
00090 "Failed to set DETACHED attribute.");
00091 }
00092 }
00093 else
00094 {
00095
00096 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE)
00097 != 0 )
00098 {
00099 throw s3_generic_exception("s3_thread_base::start()",
00100 "Failed to set JOINABLE attribute.");
00101 }
00102 }
00103
00104 lock_state();
00105 int ptc_val = pthread_create(&thread_id,
00106 &thread_attr,
00107 s3_thread_base::pthread_create_ccpp_wrapper,
00108 this);
00109 unlock_state();
00110
00111 if ( ptc_val != 0 )
00112 {
00113 started = false;
00114 std::stringstream str;
00115 str << "pthread_create() failed. Error: " << strerror(ptc_val);
00116 throw s3_generic_exception("s3_thread_base::start()",
00117 str.str());
00118 }
00119 }
00120
00121
00122 void s3_thread_base::stop()
00123 {
00124 if (!started)
00125 {
00126 return;
00127 }
00128
00129 int rv;
00130 rv = pthread_cancel(thread_id);
00131 if ( rv != 0 )
00132 {
00133 throw s3_generic_exception("s3_thread_base::stop()",
00134 "pthread_cancel failed");
00135 }
00136 }
00137
00138
00139 s3_thread_base::s3_thread_id s3_thread_base::get_thread_id() const
00140 {
00141 return thread_id;
00142 }
00143
00144
00145 void s3_thread_base::set_detached(bool n_detached)
00146 {
00147
00148 if ( is_running() != false )
00149 {
00150 throw s3_generic_exception("s3_thread_base::set_detached()",
00151 "Precondition violation: "
00152 "is_running() != false");
00153 }
00154 detached = n_detached;
00155 }
00156
00157
00158
00159 bool s3_thread_base::is_detached() const
00160 {
00161 return detached;
00162 }
00163
00164
00165 void s3_thread_base::set_sched_round_robin(unsigned int priority)
00166 {
00167 if ( thread_id == invalid_thread_id )
00168 {
00169 throw s3_generic_exception("s3_thread_base::set_sched_robin()",
00170 "Invalid thread id, "
00171 "thread probably not started yet.");
00172 }
00173
00174 struct sched_param s;
00175 int retval;
00176 s.sched_priority = priority;
00177 retval = pthread_setschedparam(thread_id,SCHED_RR,&s);
00178
00179 switch(retval)
00180 {
00181 case 0:
00182 break;
00183 case EINVAL:
00184 throw s3_generic_exception("s3_thread_base::set_sched_round_robin()",
00185 "Prority level invalid.");
00186 break;
00187 case EPERM:
00188 throw s3_generic_exception("s3_thread_base::set_sched_round_robin()",
00189 "Process requires superuser permission");
00190 break;
00191 default:
00192 throw s3_generic_exception("s3_thread_base::set_sched_round_robin()",
00193 "Unknown error setting scheduler policy");
00194 }
00195 }
00196
00197 void s3_thread_base::set_sched_fifo(unsigned int priority)
00198 {
00199 if ( thread_id == invalid_thread_id )
00200 {
00201 throw s3_generic_exception("s3_thread_base::set_sched_fifo()",
00202 "Invalid thread id, "
00203 "thread probably not started yet.");
00204 }
00205
00206 struct sched_param s;
00207 int retval;
00208 s.sched_priority = priority;
00209 retval = pthread_setschedparam(thread_id,SCHED_FIFO,&s);
00210
00211 switch(retval)
00212 {
00213 case 0:
00214 break;
00215 case EINVAL:
00216 throw s3_generic_exception("s3_thread_base::set_sched_fifo()",
00217 "Prority level invalid.");
00218 break;
00219 case EPERM:
00220 throw s3_generic_exception("s3_thread_base::set_sched_fifo()",
00221 "Process requires superuser permission");
00222 break;
00223 default:
00224 throw s3_generic_exception("s3_thread_base::set_sched_fifo()",
00225 "Unknown error setting scheduler policy");
00226 }
00227 }
00228
00229 void s3_thread_base::set_sched_normal(unsigned int priority)
00230 {
00231 if ( thread_id == invalid_thread_id )
00232 {
00233 throw s3_generic_exception("s3_thread_base::set_sched_normal()",
00234 "Invalid thread id, "
00235 "thread probably not started yet.");
00236 }
00237
00238 struct sched_param s;
00239 int retval;
00240 s.sched_priority = priority;
00241 retval = pthread_setschedparam(thread_id,SCHED_OTHER,&s);
00242
00243 switch(retval)
00244 {
00245 case 0:
00246 break;
00247 case EINVAL:
00248 throw s3_generic_exception("s3_thread_base::set_sched_normal()",
00249 "Prority level invalid.");
00250 break;
00251 default:
00252 throw s3_generic_exception("s3_thread_base::set_sched_normal()",
00253 "Unknown error setting scheduler policy");
00254 }
00255 }
00256
00257
00258 bool s3_thread_base::is_running() const
00259 {
00260 return started;
00261 }
00262
00263
00264 void s3_thread_base::wait_on_exit()
00265 {
00266
00267
00268 if (thread_id == invalid_thread_id) return;
00269
00270 if (!detached)
00271 {
00272 void* p;
00273 pthread_join(thread_id, &p);
00274 thread_id = invalid_thread_id;
00275 }
00276 else
00277 {
00278 throw s3_generic_exception("s3_thread_base::wait_on_exit()",
00279 "Attempt to wait on a detached thread.");
00280 }
00281 }
00282
00283
00284 void s3_thread_base::lock_state() const
00285 {
00286 state_lock.lock();
00287 }
00288
00289
00290 void s3_thread_base::unlock_state() const
00291 {
00292 state_lock.unlock();
00293 }
00294
00295
00296 bool s3_thread_base::test_state() const
00297 {
00298 return state_lock.try_lock();
00299 }
00300
00301
00302 void s3_thread_base::wait_on_state_changed() const
00303 {
00304 state_changed.wait();
00305 }
00306
00307
00308 void s3_thread_base::signal_state_changed() const
00309 {
00310 state_changed.post();
00311 }
00312
00313
00314 void s3_thread_base::request_terminate()
00315 {
00316 term_request_lock.lock();
00317 term_request = true;
00318 term_request_lock.unlock();
00319 signal_state_changed();
00320 }
00321
00322
00323 void s3_thread_base::test_cancel()
00324 {
00325 pthread_testcancel();
00326 }
00327
00328 void s3_thread_base::cleanup()
00329 {
00330 }
00331
00332
00333
00334
00335
00336
00337 void* s3_thread_base::pthread_create_ccpp_wrapper(void* obj)
00338 {
00339 void* rv = 0;
00340 s3_thread_base* s3b_obj = static_cast<s3_thread_base*>(obj);
00341
00342 pthread_cleanup_push(s3_thread_base::pthread_cleanup_ccpp_wrapper, obj);
00343
00344 try
00345 {
00346
00347 s3b_obj->lock_state();
00348 s3b_obj->unlock_state();
00349 s3b_obj->main_loop();
00350 }
00351 catch ( const s3_exception &e )
00352 {
00353 std::cerr << "s3_thread_base::pthread_create_ccpp_wrapper() -- " <<
00354 "s3_exception caught: " << e.what() << std::endl << std::flush;
00355 }
00356
00357 catch ( const std::exception &e )
00358 {
00359 std::cerr << "s3_thread_base::pthread_create_ccpp_wrapper() -- " <<
00360 "exception caught: " << e.what() << std::endl << std::flush;
00361 }
00362 catch ( ... )
00363 {
00364 std::cerr << "s3_thread_base::pthread_create_ccpp_wrapper() -- " <<
00365 "(unknown) exception caught." << std::endl << std::flush;
00366 }
00367
00368 pthread_cleanup_pop(1);
00369 return rv;
00370 }
00371
00372
00373
00374 void s3_thread_base::pthread_cleanup_ccpp_wrapper(void* obj)
00375 {
00376 s3_thread_base* s3b_obj = static_cast<s3_thread_base*>(obj);
00377 s3b_obj->cleanup();
00378 s3b_obj->started = false;
00379 }
00380
00381
00382 bool s3_thread_base::test_terminate()
00383 {
00384 bool rv;
00385 term_request_lock.lock();
00386 rv = term_request;
00387 term_request_lock.unlock();
00388 return rv;
00389 }
00390
00391