S3FC project page S3FC home page

Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

s3_thread_base.cc

Go to the documentation of this file.
00001 /*
00002  * Stone Three Foundation Class (s3fc) provides a number of utility classes.
00003  * Copyright (C) 2001 by Stone Three Signal Processing (Pty) Ltd.
00004  *
00005  * Authored by Stone Three Signal Processing (Pty) Ltd.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  * 
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  * 
00021  * Please see the file 'COPYING' in the source root directory.
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 // dflt ctor - zero init and default init thread variables
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 // dtor - clean thread variables
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 // start through static wrapper, passing arg to main_loop and returning
00064 //  immediately with pthread_create return value
00065 void s3_thread_base::start()
00066 {
00067     // check that start() is only called ONCE
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    // check that previous invocation was joined after termination
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    // clear pending term requests
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       // Reset thread attribute so that a new start will be joinable.
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 // stop by calling pthread_cancel with id thread_id
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 // return thread id
00139 s3_thread_base::s3_thread_id s3_thread_base::get_thread_id() const
00140 {
00141    return thread_id;
00142 }
00143 
00144 // set detached
00145 void s3_thread_base::set_detached(bool n_detached)
00146 {
00147    // check precondition - may not be running
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 // return detached
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: // Success
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: // Success
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: // Success
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 // return started
00258 bool s3_thread_base::is_running() const
00259 {
00260    return started;
00261 }
00262 
00263 // join and wait
00264 void s3_thread_base::wait_on_exit()
00265 {
00266    // check to ensure that we don't join twice or join on a thread
00267    // that never executed
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 // lock state mutex
00284 void s3_thread_base::lock_state() const
00285 {
00286    state_lock.lock();
00287 }
00288 
00289 // unlock state mutex
00290 void s3_thread_base::unlock_state() const
00291 {
00292    state_lock.unlock();
00293 }
00294 
00295 // Test state mutex to see if someone is holding it.
00296 bool s3_thread_base::test_state() const
00297 {
00298    return state_lock.try_lock();
00299 }
00300 
00301 // wait on semaphore - use locking wait
00302 void s3_thread_base::wait_on_state_changed() const
00303 {
00304    state_changed.wait();
00305 }
00306 
00307 // up semaphore
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 // call pthread_testcancel()
00323 void s3_thread_base::test_cancel()
00324 {
00325    pthread_testcancel();
00326 }
00327 
00328 void s3_thread_base::cleanup()
00329 {
00330 }
00331 
00332 // invoked by pthread_create as the thread start_routine
00333 // invoke the @c main_loop of an @c s3_thread_base instance
00334 // and return with it
00335 // obj is the @c this pointer of the @c s3_thread_base instance
00336 // wrap the forwarding call in a push/pop pair
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       // invoke main loop
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    // remove AND execute cleanup handler
00368    pthread_cleanup_pop(1);
00369    return rv;
00370 }
00371 
00372 // invoked by the thread mechanism when pthread_exit() exits 
00373 // the thread. forward to obj->cleanup()
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 

Send comments to: s3fc@stonethree.com SourceForge Logo