LCOV - code coverage report
Current view: top level - INDI/libcommon - Thread.cpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 40.7 % 226 92
Test Date: 2026-01-03 21:03:39 Functions: 41.9 % 31 13

            Line data    Source code
       1              : /// Thread.cpp
       2              : ///
       3              : /// @author Paul Grenz
       4              : ///
       5              : ////////////////////////////////////////////////////////////////////////////////
       6              : 
       7              : #include <iostream>
       8              : #include "Thread.hpp"
       9              : #ifdef WIN32
      10              : #include <windows.h>
      11              : #else
      12              : #include <errno.h>
      13              : #include <signal.h>
      14              : #include <unistd.h>
      15              : #include <sys/types.h>
      16              : #include <sys/time.h>
      17              : #include <pthread.h>
      18              : #include <string.h>
      19              : #include <sched.h>
      20              : #endif
      21              : 
      22              : using std::string;
      23              : using pcf::Thread;
      24              : using pcf::SystemSocket;
      25              : 
      26              : ////////////////////////////////////////////////////////////////////////////////
      27              : /// pcf::Thread::sm_nStopSignal is the signal sent to ensure that
      28              : /// system calls exit with a 'EINTR' error.
      29              : 
      30              : int pcf::Thread::sm_nStopSignal = SIGQUIT;
      31              : 
      32              : ////////////////////////////////////////////////////////////////////////////////
      33              : /// Standard constructor.
      34              : 
      35           12 : Thread::Thread() : m_idThis(0), m_uiInterval(1000), m_tState(Idle), m_oStop(true),
      36           12 :                     m_oOneShot(false), m_oIsRunning(false), m_oIsPaused(false), m_psocTrigger(NULL)
      37              : {
      38              :   // We are not running in 'execute' yet.
      39           12 :   m_mutReady.lock();
      40              : 
      41           12 :   setupPipe();
      42           12 : }
      43              : 
      44              : ////////////////////////////////////////////////////////////////////////////////
      45              : /// Standard destructor. Will stop any thread automatically.
      46              : 
      47           12 : Thread::~Thread()
      48              : {
      49           12 :   stop();
      50           12 :   join();
      51              : 
      52           12 :   ::close( m_pfdPipe[0] );
      53           12 :   ::close( m_pfdPipe[1] );
      54           12 :   m_pfdPipe[0] = -1;
      55           12 :   m_pfdPipe[1] = -1;
      56           12 : }
      57              : 
      58              : ////////////////////////////////////////////////////////////////////////////////
      59              : /// Assignment operator.
      60              : /// @param copy An existing Thread that is being copied. This one will be
      61              : /// stopped if it is currently running, and once assigned will not initially
      62              : /// be running.
      63              : /// @return A reference to this Thread object.
      64              : 
      65            0 : const Thread &Thread::operator=( const Thread &copy )
      66              : {
      67            0 :   if ( &copy != this )
      68              :   {
      69            0 :     stop();
      70            0 :     join();
      71              : 
      72            0 :     m_uiInterval = copy.m_uiInterval;
      73            0 :     m_oOneShot = copy.m_oOneShot;
      74            0 :     m_idThis = 0;
      75            0 :     m_oStop = true;
      76            0 :     m_oIsRunning = false;
      77            0 :     m_oIsPaused = false;
      78            0 :     m_psocTrigger = NULL;
      79            0 :     m_tState = Idle;
      80              : 
      81              :     // We are not running in 'execute' yet.
      82            0 :     m_mutReady.lock();
      83              :   }
      84            0 :   return *this;
      85              : }
      86              : 
      87              : ////////////////////////////////////////////////////////////////////////////////
      88              : /// Copy constructor.
      89              : /// @param copy An existing Thread that will be used to initialize this one. The
      90              : /// parameters will be copied, but if the original is running, this one will not
      91              : /// be.
      92              : 
      93            0 : Thread::Thread( const Thread &copy ) : m_idThis(0), m_uiInterval(copy.m_uiInterval), m_tState(Idle), m_oStop(true),
      94            0 :                                       m_oOneShot(copy.m_oOneShot), m_oIsRunning(false), m_oIsPaused(false), m_psocTrigger(NULL)
      95              : {
      96              :   // We are not running in 'execute' yet.
      97            0 :   m_mutReady.lock();
      98              : 
      99            0 :   setupPipe();
     100            0 : }
     101              : 
     102              : ////////////////////////////////////////////////////////////////////////////////
     103              : /// Setup the pipe - this is used to kick the thread out of 'select';
     104              : /// (the infamous 'self-pipe' trick)
     105              : 
     106           12 : void Thread::setupPipe()
     107              : {
     108              :   // Set the file descriptors to an invald value.
     109              :   // If we cannot initialize the fd's correctly, we will fail when we try
     110              :   // to pause.
     111           12 :   m_pfdPipe[0] = -1;
     112           12 :   m_pfdPipe[1] = -1;
     113              : 
     114           12 :   if ( ::pipe( m_pfdPipe ) == 0 )
     115              :   {
     116              :     // Set both the read and write ends non-blocking.
     117           36 :     for ( uint64_t ii = 0; ii < 2; ii++ )
     118              :     {
     119           24 :       int iFlags = 0;
     120           24 :       if ( ( iFlags = ::fcntl( m_pfdPipe[ii], F_GETFL ) ) == -1 )
     121              :       {
     122            0 :         ::close( m_pfdPipe[0] );
     123            0 :         ::close( m_pfdPipe[1] );
     124            0 :         m_pfdPipe[0] = -1;
     125            0 :         m_pfdPipe[1] = -1;
     126            0 :         break;
     127              :       }
     128           24 :       iFlags |= O_NONBLOCK;
     129           24 :       if ( ::fcntl( m_pfdPipe[ii], F_SETFL, iFlags ) == -1 )
     130              :       {
     131            0 :         ::close( m_pfdPipe[0] );
     132            0 :         ::close( m_pfdPipe[1] );
     133            0 :         m_pfdPipe[0] = -1;
     134            0 :         m_pfdPipe[1] = -1;
     135            0 :         break;
     136              :       }
     137              :     }
     138              :   }
     139           12 : }
     140              : 
     141              : ////////////////////////////////////////////////////////////////////////////////
     142              : /// @return The interval to wait in between 'execute' calls.
     143              : 
     144            0 : unsigned int Thread::getInterval() const
     145              : {
     146            0 :   return m_uiInterval;
     147              : }
     148              : 
     149              : ////////////////////////////////////////////////////////////////////////////////
     150              : /// @return The current state the running thread is in.
     151              : 
     152            0 : Thread::State Thread::getState() const
     153              : {
     154            0 :   return m_tState;
     155              : }
     156              : 
     157              : ////////////////////////////////////////////////////////////////////////////////
     158              : /// Sets the socket file descriptor which will be used to cause the 'execute'
     159              : /// method to run. If the socket descriptor is valid, the 'runLoop' will
     160              : /// check to see if there is data waiting to be read on the socket and will
     161              : /// not call 'execute' until there is.
     162              : ///
     163            0 : void Thread::setTrigger( pcf::SystemSocket *psocTrigger )
     164              : {
     165            0 :   m_psocTrigger = psocTrigger;
     166            0 : }
     167              : 
     168              : ////////////////////////////////////////////////////////////////////////////////
     169              : /// Sets the interval to wait in between 'execute' calls.
     170              : 
     171           12 : void Thread::setInterval( const unsigned int &uiInterval )
     172              : {
     173           12 :   m_uiInterval = uiInterval;
     174           12 : }
     175              : 
     176              : ////////////////////////////////////////////////////////////////////////////////
     177              : /// Returns true if the 'stop' flag has been set to true. The thread
     178              : /// may still be running its last iteration, though. (see 'isRunning').
     179              : 
     180            0 : bool Thread::isStopping() const
     181              : {
     182            0 :   return m_oStop;
     183              : }
     184              : 
     185              : ////////////////////////////////////////////////////////////////////////////////
     186              : /// Returns whether or not the Thread is running. "isRunning" will still return
     187              : /// true, even if the Thread is paused.
     188              : /// @return True if the Thread is running, false if it is not.
     189              : 
     190           30 : bool Thread::isRunning() const
     191              : {
     192           30 :   return m_oIsRunning;
     193              : }
     194              : 
     195              : ////////////////////////////////////////////////////////////////////////////////
     196              : /// Returns whether or not the Thread is paused. "isRunning" will still return
     197              : /// true, even if the Thread is paused.
     198              : /// @return True if the Thread is paused, false if it is not.
     199              : 
     200            0 : bool Thread::isPaused() const
     201              : {
     202            0 :   return m_oIsPaused;
     203              : }
     204              : 
     205              : ////////////////////////////////////////////////////////////////////////////////
     206              : /// Pauses the Thread. "stop" will still end it. Calling 'pause' twice or more
     207              : /// will have no effect.
     208              : 
     209            0 : void Thread::pause()
     210              : {
     211            0 :   m_oIsPaused = true;
     212            0 : }
     213              : 
     214              : ////////////////////////////////////////////////////////////////////////////////
     215              : /// Resumes the Thread if it is paused. Calling 'resume' twice or more will have
     216              : /// no effect.
     217              : 
     218            0 : void Thread::resume()
     219              : {
     220            0 :   m_oIsPaused = false;
     221              : 
     222              :   // Write a char to the pipe to kick the thread out of the 'select' call.
     223            0 :   int rv = ::write( m_pfdPipe[1], "A", 1 );
     224            0 :   if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
     225            0 : }
     226              : 
     227              : ////////////////////////////////////////////////////////////////////////////////
     228              : /// Resumes the thread if it is paused, but only for one iteration. Calling
     229              : /// 'resumeOnce' twice or more will have no effect.
     230              : 
     231            0 : void Thread::resumeOnce()
     232              : {
     233              :   // Write a char to the pipe to kick the thread out of the 'select' call.
     234            0 :   int rv = ::write( m_pfdPipe[1], "A", 1 );
     235            0 :   if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
     236            0 : }
     237              : 
     238              : ////////////////////////////////////////////////////////////////////////////////
     239              : /// Sets the flag to stop the Thread. This will cause 'afterExecute' to be
     240              : /// called.
     241              : 
     242           15 : void Thread::stop()
     243              : {
     244           15 :   m_oStop = true;
     245              : 
     246              :   // Send a signal to ensure that any system calls return and enable
     247              :   // the checking of the stop flag.
     248           15 :   if ( m_idThis != 0 )
     249            6 :     ::pthread_kill( m_idThis, Thread::sm_nStopSignal );
     250           15 : }
     251              : 
     252              : ////////////////////////////////////////////////////////////////////////////////
     253              : /// Puts the calling thread to sleep for uiSeconds seconds.
     254              : /// @param uiSeconds The number of seconds to go to sleep.
     255              : /// @return An error code. See 'nanosleep' for more details.
     256              : 
     257            0 : int Thread::sleep( const unsigned int &uiSeconds )
     258              : {
     259            0 :   return nanosleep( uiSeconds, 0 );
     260              : }
     261              : 
     262              : ////////////////////////////////////////////////////////////////////////////////
     263              : /// Puts the calling thread to sleep for uiMillis milliseconds.
     264              : /// @param uiMillis The number of milliseconds to go to sleep.
     265              : /// @return An error code. See 'nanosleep' for more details.
     266              : 
     267            3 : int Thread::msleep( const unsigned int &uiMillis )
     268              : {
     269            3 :   return nanosleep( uiMillis / 1000, uiMillis % 1000 * 1000000 );
     270              : }
     271              : 
     272              : ////////////////////////////////////////////////////////////////////////////////
     273              : /// Puts the calling thread to sleep for uiMicros microseconds.
     274              : /// @param uiMicros The number of microseconds to go to sleep.
     275              : /// @return An error code. See 'nanosleep' for more details.
     276              : 
     277            0 : int Thread::usleep( const unsigned int &uiMicros )
     278              : {
     279            0 :   return nanosleep( uiMicros / 1000000, uiMicros % 1000000 * 1000 );
     280              : }
     281              : 
     282              : ////////////////////////////////////////////////////////////////////////////////
     283              : /// Puts the calling thread to sleep for uiNanos nanoseconds.
     284              : /// @param uiNanos The number of nanoseconds to go to sleep.
     285              : /// @return An error code. See 'nanosleep' for more details.
     286              : 
     287            0 : int Thread::nsleep( const unsigned int &uiNanos )
     288              : {
     289            0 :   return nanosleep( uiNanos / 1000000000, uiNanos % 1000000000 );
     290              : }
     291              : 
     292              : ////////////////////////////////////////////////////////////////////////////////
     293              : /// Puts the calling thread to sleep for a specific amount of time. Under
     294              : /// windows, the best we can do is a millisecond resolution without a third
     295              : /// party library, so the other calls will be estimated. This will always
     296              : /// return ErrNone under windows, as no error information is available.
     297              : /// @param uiSeconds The number of seconds to go to sleep.
     298              : /// @param uiNanos An additional number of nanoseconds to sleep.
     299              : /// @return ErrNone The sleep occurred successfully.
     300              : /// @return ErrInterrupted The sleep was interupted by a system call (signal).
     301              : /// @return ErrInvalidParameter Invalid parameter to function call.
     302              : /// @return ErrCopy
     303              : 
     304            3 : int Thread::nanosleep( const unsigned int &uiSeconds,
     305              :                        const unsigned int &uiNanos )
     306              : {
     307            3 :   int nErr = ErrNone;
     308              : 
     309              : #ifdef WIN32
     310              :   DWORD uiMillis = uiSeconds * 1000 + uiNanos / 1000000;
     311              :   Sleep( uiMillis );
     312              : #else
     313              :   timespec ts;
     314            3 :   ts.tv_sec = uiSeconds;
     315            3 :   ts.tv_nsec = uiNanos;
     316              : 
     317              :   // Minus sign to convert to our error code.
     318            3 :   nErr = - ::nanosleep( &ts, NULL );
     319              : 
     320              : #endif
     321              : 
     322            3 :   return nErr;
     323              : }
     324              : 
     325              : ////////////////////////////////////////////////////////////////////////////////
     326              : /// Suspends the calling thread until the thread managed by this object
     327              : /// finishes.
     328              : /// @return ErrNone
     329              : /// @return ErrThreadUnjoinable
     330              : /// @return ErrBadThreadId
     331              : /// @return ErrDeadlock
     332              : 
     333           15 : int Thread::join()
     334              : {
     335              :   // The pthread_join() function shall suspend execution of the calling thread
     336              :   // until the target thread terminates, unless  the  target  thread
     337              :   // has  already  terminated.  On  return from a successful pthread_join()
     338              :   // call  with  a  non-NULL  value_ptr  argument,  the  value  passed   to
     339              :   // pthread_exit()  by  the  terminating thread shall be made available in
     340              :   // the location referenced by value_ptr. When  a  pthread_join()  returns
     341              :   // successfully,  the  target  thread has been terminated. The results of
     342              :   // multiple simultaneous calls to pthread_join() specifying the same target
     343              :   // thread are undefined. If the thread calling pthread_join() is canceled,
     344              :   // then the target thread shall not be detached.
     345              :   // It is unspecified  whether  a  thread  that  has  exited  but  remains
     346              :   // unjoined counts against {PTHREAD_THREADS_MAX}.
     347              : 
     348           15 :   int nErr = ErrNone;
     349              : 
     350           15 :   if ( m_oIsRunning == false )
     351              :   {
     352           12 :     nErr = -EHOSTDOWN;
     353              :   }
     354              : #ifdef WIN32
     355              :   else if ( m_idThis != NULL )
     356              :   {
     357              :     //  throw away the result of the thread.
     358              :     nErr = WaitForSingleObject( m_idThis, INFINITE );
     359              : 
     360              :     switch ( nErr )
     361              :     {
     362              :       case WAIT_ABANDONED:
     363              :         nErr = -EINTR;
     364              :         break;
     365              :       case WAIT_OBJECT_0:
     366              :         nErr = ErrNone;
     367              :         break;
     368              :       case WAIT_TIMEOUT:
     369              :         nErr = -ETIMEDOUT;
     370              :         break;
     371              :       case WAIT_FAILED:
     372              :         nErr = -EINVAL;
     373              :         break;
     374              :       default:
     375              :         nErr = ErrUnknown;
     376              :         break;
     377              :     }
     378              :     Thread::msleep( 1 );
     379              :     // Do not set the thread id back to 0, as this will cause a mem leak!
     380              :     //m_idThis = 0;
     381              :   }
     382              : #else
     383            3 :   else if ( m_idThis != 0 )
     384              :   {
     385              :     // Throw away the result of the thread.
     386              :     void *pResult;
     387              :     // Minus sign to convert to our error code.
     388            3 :     nErr = - ::pthread_join( m_idThis, &pResult );
     389              :     // Do not set the thread id back to 0, as this will cause a mem leak!
     390              :     //m_idThis = 0;
     391              :     // Convert to our error code as necessary.
     392            3 :     nErr = ( nErr == -EINVAL ) ? ( -ENODEV ) : ( nErr );
     393              :   }
     394              : #endif
     395              : 
     396           15 :   return nErr;
     397              : }
     398              : 
     399              : ////////////////////////////////////////////////////////////////////////////////
     400              : /// Override this function to do something before the thread has been told to
     401              : /// start, like allocate memory.
     402              : 
     403            0 : void Thread::beforeExecute()
     404              : {
     405            0 : }
     406              : 
     407              : ////////////////////////////////////////////////////////////////////////////////
     408              : /// Override this function to do something after the thread has been told to
     409              : /// stop, like clean up allocated memory.
     410              : 
     411            0 : void Thread::afterExecute()
     412              : {
     413            0 : }
     414              : 
     415              : ////////////////////////////////////////////////////////////////////////////////
     416              : /// Override in derived class, place the code to do something here.
     417              : 
     418            0 : void Thread::execute()
     419              : {
     420            0 : }
     421              : 
     422              : ////////////////////////////////////////////////////////////////////////////////
     423              : /// Waits for the 'ready' mutex to be unlocked. This indicates that the
     424              : /// 'execute' function is about to be run.
     425              : 
     426            0 : void Thread::waitForReady()
     427              : {
     428              :   // We will wait here until we can get the lock.
     429            0 :   m_mutReady.lock();
     430              :   // unlock it immediately, we can can continue now.
     431            0 :   m_mutReady.unlock();
     432            0 : }
     433              : 
     434              : ////////////////////////////////////////////////////////////////////////////////
     435              : /// Initializes the Thread by calling 'beforeExecute', then loops, calling
     436              : /// 'execute' until 'm_oStop' is true. Then calls 'afterExecute' and ends.
     437              : 
     438            3 : void Thread::runLoop()
     439              : {
     440              :   // Make sure we can handle the signal which will come when we want to stop.
     441              :   // This is signal will ensure that we are not stuck waiting on I/O.
     442              :   // Any system calls in progress should return with an "EINTR" error.
     443            3 :   ::memset( &m_saStop, 0, sizeof( struct sigaction ) );
     444            3 :   m_saStop.sa_handler = Thread::processSignalHandler;
     445            3 :   sigemptyset( &m_saStop.sa_mask );
     446            3 :   ::sigaction( Thread::sm_nStopSignal, &m_saStop, 0 );
     447              : 
     448              :   // Ensure the loop starts.
     449            3 :   m_oStop = false;
     450            3 :   m_oIsRunning = true;
     451              : 
     452              :   // Call function to allow user to set things up before the
     453              :   // main loop starts.
     454            3 :   m_tState = BeforeExecute;
     455            3 :   beforeExecute();
     456              : 
     457              :   // Once we are about to enter the 'execute' method, we are ready to do
     458              :   // whatever this thread needs to do!
     459            3 :   m_mutReady.unlock();
     460              : 
     461              :   // The main loop.
     462            3 :   m_tState = Execute;
     463            6 :   while ( m_oStop == false )
     464              :   {
     465              :     // This is a loop that is entered pausing the polling
     466              :     // and processing. quitting will end it as well.
     467            3 :     if ( m_oIsPaused == true )
     468              :     {
     469              :       // Create and clear out the FD set.
     470              :       fd_set fdsRead;
     471            0 :       FD_ZERO( &fdsRead );
     472            0 :       FD_SET( m_pfdPipe[0], &fdsRead);
     473            0 :       int nHighestNumberedFd = m_pfdPipe[0];
     474              :       // Wait for it....
     475            0 :       ::select( nHighestNumberedFd+1, &fdsRead, NULL, NULL, NULL );
     476              :       // Did we get knocked out of 'select' by something on the pipe?
     477            0 :       if ( FD_ISSET( m_pfdPipe[0], &fdsRead ) )
     478              :       {
     479              :         // Read the single char sent.
     480              :         char ch;
     481            0 :         int rv = ::read( m_pfdPipe[0], &ch, 1 );
     482            0 :         if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
     483              :       }
     484              :     }
     485              : 
     486              :     // Check to see if we should stop looping, since the flag may have
     487              :     // toggled while we were paused, above.
     488            3 :     if ( m_oStop == true )
     489            0 :       break;
     490              : 
     491              :     // Do we have a trigger? In this case, we have a socket which
     492              :     // we will use to signal the "execute" method to run. This will
     493              :     // happen if we have data available to be read on said socket.
     494            3 :     if ( m_psocTrigger != NULL && m_psocTrigger->isValid() == true )
     495              :     {
     496              :       // Create and clear out the FD set.
     497              :       fd_set fdsRead;
     498            0 :       FD_ZERO( &fdsRead );
     499              :       // Watch the to see when we get some input.
     500            0 :       FD_SET( m_psocTrigger->getFd(), &fdsRead );
     501            0 :       int nHighestNumberedFd = m_psocTrigger->getFd();
     502              :       // Wait for it....
     503            0 :       ::select( nHighestNumberedFd+1, &fdsRead, NULL, NULL, NULL );
     504              :     }
     505              : 
     506              :     // Check to see if we should stop looping, since the flag may have
     507              :     // toggled while we were waiting for a trigger, above.
     508            3 :     if ( m_oStop == true )
     509            0 :       break;
     510              : 
     511              :     // Wait for a bit....
     512              :     // If we have set a trigger, above, we may not want to wait here.
     513            3 :     if ( m_uiInterval > 0 )
     514            3 :       msleep( m_uiInterval );
     515              : 
     516              :     // Check to see if we should stop looping, since the flag may have
     517              :     // toggled while we were sleeping, above.
     518            3 :     if ( m_oStop == true )
     519            0 :       break;
     520              : 
     521              :     // Call the function to actually do something.
     522            3 :     execute();
     523              : 
     524              :     // If this is a one-shot Thread, 'stop' will become true here.
     525            3 :     m_oStop = ( m_oOneShot || m_oStop );
     526              :   }
     527              : 
     528              :   // Call function to allow user to clean things up before the
     529              :   // thread exits. There must be nothing done after this.
     530            3 :   m_tState = AfterExecute;
     531            3 :   afterExecute();
     532              : 
     533            3 :   m_oIsRunning = false;
     534              : 
     535            3 :   m_tState = Idle;
     536            3 : }
     537              : 
     538              : ////////////////////////////////////////////////////////////////////////////////
     539              : /// Code to get a new Thread running.
     540              : /// We need a static function for the 'pthread_create' or 'CreateThread'
     541              : /// call - see below. We can also pass in a CPU number to set the affinity
     542              : /// of this thread to a particular CPU.
     543              : /// @param iCpuAffinity The CPU to run this thread on.
     544              : /// @return ErrNone
     545              : /// @return ErrAlreadyRunning
     546              : /// @return ErrCouldNotCreateThread
     547              : /// @return ErrInvalidParameter
     548              : /// @return ErrWrongPermission
     549              : 
     550            3 : int Thread::start( const int &iCpuAffinity,
     551              :                    const ScheduleType &tSchedule )
     552              : {
     553              :   // The   pthread_create()  function  shall  create  a  new  thread,  with
     554              :   // attributes specified by attr, within a process. If attr is  NULL,  the
     555              :   // default  attributes shall be used. If the attributes specified by attr
     556              :   // are modified later, the thread’s attributes  shall  not  be  affected.
     557              :   // Upon successful completion, pthread_create() shall store the ID of the
     558              :   // created thread in the location referenced by thread.
     559              :   //
     560              :   // The thread is created executing start_routine with  arg  as  its  sole
     561              :   // argument.  If  the  start_routine  returns,  the effect shall be as if
     562              :   // there was an implicit call to pthread_exit() using the return value of
     563              :   // start_routine as the exit status. Note that the thread in which main()
     564              :   // was originally invoked differs from this. When it returns from main(),
     565              :   // the  effect  shall be as if there was an implicit call to exit() using
     566              :   // the return value of main() as the exit status.
     567              : 
     568            3 :   int nErr = ErrNone;
     569              : 
     570            3 :   if ( m_oIsRunning != false )
     571              :   {
     572            0 :     nErr = -EALREADY;
     573              :   }
     574              :   else
     575              :   {
     576              : #ifdef WIN32
     577              :     DWORD idDummy;
     578              :     m_idThis  = CreateThread( NULL, 0, Thread::threadFuncWin,
     579              :                               this, 0, &idDummy );
     580              :     nErr = ( m_idThis == 0 ) ? ( -EAGAIN ) : ( ErrNone );
     581              : #else
     582              : #ifndef __APPLE__
     583              : 
     584              :     // We need an attributes object to modify the behavior of the new thread.
     585              :     sched_param param;
     586              :     pthread_attr_t attr;
     587            3 :     ::pthread_attr_init( &attr );
     588              : 
     589              :     // Should we set the affinity of this thread to a particular CPU?
     590            3 :     if ( iCpuAffinity > -1 )
     591              :     {
     592              :       // Get the number of CPU's on this system.
     593            0 :       int iCpuCount = ::sysconf( _SC_NPROCESSORS_ONLN );
     594              : 
     595              :       // Make sure we have chosen a CPU that exists. If it doesn't,
     596              :       // we will fail silently and run on whatever CPU the scheduler decrees.
     597            0 :       if ( iCpuAffinity < iCpuCount )
     598              :       {
     599              :         // Create a CPU set containing the current cpu index.
     600              :         cpu_set_t setCpu;
     601            0 :         CPU_ZERO( &setCpu );
     602            0 :         CPU_SET( iCpuAffinity, &setCpu );
     603            0 :         ::pthread_attr_setaffinity_np( &attr, sizeof( cpu_set_t ), &setCpu );
     604              :       }
     605              :     }
     606              : 
     607              :     // Set the scheduler attributes for the thread we are about to create.
     608            3 :     switch ( tSchedule )
     609              :     {
     610              :       // Nothing special for this thread; just use whatever is set here.
     611            3 :       case Inherit:
     612            3 :         ::pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
     613            3 :         break;
     614              :       // Specifically ask for normal scheduling and priority.
     615            0 :       case Normal:
     616            0 :         ::pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
     617            0 :         param.sched_priority = 0;
     618            0 :         ::pthread_attr_setschedparam( &attr, &param);
     619            0 :         ::pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
     620            0 :         break;
     621              :       // Ask for better scheduling and priority.
     622            0 :       case Turbo:
     623            0 :         ::pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
     624            0 :         param.sched_priority = ::sched_get_priority_max( SCHED_FIFO );
     625            0 :         ::pthread_attr_setschedparam( &attr, &param);
     626            0 :         ::pthread_attr_setschedpolicy( &attr, SCHED_FIFO );
     627              :     }
     628              : 
     629              :     // Minus sign to convert to our error code.
     630            3 :     nErr = - ::pthread_create( &m_idThis, &attr, Thread::pthreadFunc, this );
     631              : 
     632              : #endif
     633              : #endif
     634              :   }
     635            3 :   return nErr;
     636              : }
     637              : 
     638              : #ifdef WIN32
     639              : ////////////////////////////////////////////////////////////////////////////////
     640              : /// 'CreateThread' needs a static function to get the
     641              : /// thread going. Passing a pointer back to the Thread object allows us to
     642              : /// call the 'runLoop' function from within the new thread.
     643              : /// @param A pointer to this class that the thread function can use.
     644              : 
     645              : DWORD WINAPI Thread::threadFuncWin( void *pUnknown )
     646              : {
     647              :   //  do a static cast to get the pointer back to a "Thread" object.
     648              :   Thread *pThis = static_cast<Thread *>( pUnknown );
     649              : 
     650              :   //  we are now within the new thread and up and running.
     651              :   pThis->runLoop();
     652              : 
     653              :   ///  no return is necessary, since it is not examined.
     654              :   return 0;
     655              : }
     656              : 
     657              : #else
     658              : ////////////////////////////////////////////////////////////////////////////////
     659              : /// 'pthread_create' needs a static function to get the
     660              : /// thread going. Passing a pointer back to the Thread object allows us to
     661              : /// call the 'runLoop' function from within the new thread.
     662              : /// @param A pointer to this class that the thread function can use.
     663              : 
     664            3 : void *Thread::pthreadFunc( void *pUnknown )
     665              : {
     666              :   //  do a static cast to get the pointer back to a "Thread" object.
     667            3 :   Thread *pThis = static_cast<Thread *>( pUnknown );
     668              : 
     669              :   //  we are now within the new thread and up and running.
     670              :   try
     671              :   {
     672            3 :     pThis->runLoop();
     673              :   }
     674            0 :   catch ( const std::exception &excep )
     675              :   {
     676            0 :     std::cerr << "Thread exited: " << excep.what() << std::endl;
     677            0 :   }
     678            0 :   catch ( ... )
     679              :   {
     680            0 :     std::cerr << "An exception was thrown, exiting the thread." << std::endl;
     681            0 :   }
     682              : 
     683              :   ///  no return is necessary, since it is not examined.
     684            3 :   return NULL;
     685              : }
     686              : #endif
     687              : 
     688              : ////////////////////////////////////////////////////////////////////////////////
     689              : /// This variable and function are used to trap a signal to tell the thread
     690              : /// to return from any system calls gracefully.
     691              : 
     692            3 : void Thread::processSignalHandler( int nSignal )
     693              : {
     694              :   static_cast<void>(nSignal);
     695              :   // The signal handler is not re-installed, so it will not work again.
     696            3 : }
     697              : 
     698              : ////////////////////////////////////////////////////////////////////////////////
     699              : /// Returns a message associated with an error code.
     700              : /// @param nErr The error code.
     701              : /// @return A message associated with the error.
     702              : 
     703            0 : string Thread::getErrorMsg( const int &nErr )
     704              : {
     705            0 :   switch ( nErr )
     706              :   {
     707            0 :     case ErrNone:
     708            0 :       return string( "No Error." );
     709              :       break;
     710            0 :     case ErrThreadUnjoinable:
     711            0 :       return string( "Thread unjoinable." );
     712              :       break;
     713            0 :     case ErrBadThreadId:
     714            0 :       return string( "Bad thread Id." );
     715              :       break;
     716            0 :     case ErrDeadlock:
     717            0 :       return string( "Operation would deadlock." );
     718              :       break;
     719            0 :     case ErrCouldNotCreateThread:
     720            0 :       return string( "Could not create thread." );
     721              :       break;
     722            0 :     case ErrInvalidParameter:
     723            0 :       return string( "Invalid parameter to function call." );
     724              :       break;
     725            0 :     case ErrWrongPermission:
     726            0 :       return string( "Wrong permission." );
     727              :       break;
     728            0 :     case ErrAlreadyRunning:
     729            0 :       return string( "Thread already running." );
     730              :       break;
     731            0 :     case ErrInterrupted:
     732            0 :       return string( "Sleep was interrupted before it could complete." );
     733              :       break;
     734            0 :     case ErrCopy:
     735            0 :       return string( "Information could not be copied from user space." );
     736              :       break;
     737            0 :     case ErrTimedOut:
     738            0 :       return string( "Timed out waiting for thread." );
     739              :       break;
     740            0 :     case ErrNotRunning:
     741            0 :       return string( "Thread is not running." );
     742              :       break;
     743            0 :     case ErrUnknown:
     744            0 :       return string( "Unknown error." );
     745              :       break;
     746              :   }
     747            0 :   return string( "" );
     748              : }
     749              : 
     750              : ////////////////////////////////////////////////////////////////////////////////
        

Generated by: LCOV version 2.0-1