LCOV - code coverage report
Current view: top level - INDI/libcommon - Thread.hpp Coverage Total Hit
Test: MagAOX Lines: 100.0 % 1 1
Test Date: 2026-01-03 21:03:39 Functions: - 0 0

            Line data    Source code
       1              : /// Thread.hpp
       2              : ///
       3              : /// @author Paul Grenz
       4              : ///
       5              : /// The "Thread" class provides the functionality of a recurring
       6              : /// event or task. The way this is implemented is by having a separate thread
       7              : /// carry out the waiting in between events, and when the interval has elapsed,
       8              : /// the "execute" function is called. When the thread is started, the
       9              : /// "beforeExecute" function is called, and this can be used to set up any
      10              : /// variables or objects which the thread uses. In a symmetrical fashon,
      11              : /// "afterExecute" is called after the thread has been told to stop, either by
      12              : /// calling "stop" or the by the object being destroyed. This function can be
      13              : /// used to "clean-up" after the thread is done. To start the thread, call
      14              : /// "start". When stopping, a sigquit is sent to thread, ensuring that it will
      15              : /// not be stuck in a system call, but will return and process the new
      16              : /// 'stopped' condition.
      17              : ///
      18              : /// Thread also supports "pausing". This is accomplished by calling "pause"
      19              : /// and conversly "resume". When the thread is paused, it will still respond
      20              : /// to "stop" being called. While paused, it will be 'sleeping' and only wake
      21              : /// up in response to a 'resume' or 'stop'.
      22              : ///
      23              : /// After calling stop, call "join" to synchronize the main application thread
      24              : /// with this thread. This will ensure that the application does not perform an
      25              : /// operation (such as exiting!) until the thread has cleaned up its worker
      26              : /// thread.
      27              : ///
      28              : /// Another concept this class supports is the idea of a 'trigger'. This can
      29              : /// be used to run the 'execute' method only when a certain event happens, not
      30              : /// only after 'sleeping' for a fixed time interval. With a socket set as a
      31              : /// trigger, for example, (calling 'setTrigger' with a &socket argument) the
      32              : /// 'beforeExecute' method will be run as before, but the 'execute' method
      33              : /// will only run if data is ready to be read on the socket. All other times,
      34              : /// this thread will be asleep, and only wake up if a signal is received to
      35              : /// stop it running. If the socket is closed for any reason, the trigger will
      36              : /// be ignored, and the execute method will be run as if there was no trigger
      37              : /// set.
      38              : ///
      39              : ////////////////////////////////////////////////////////////////////////////////
      40              : 
      41              : #ifndef PCF_THREAD_HPP
      42              : #define PCF_THREAD_HPP
      43              : 
      44              : #include <errno.h>
      45              : #include <pthread.h>
      46              : #include <signal.h>
      47              : #include <stdexcept>
      48              : #include "MutexLock.hpp"
      49              : #include "SystemSocket.hpp"
      50              : #ifdef WIN32
      51              : #include <windows.h>
      52              : #endif
      53              : 
      54              : ////////////////////////////////////////////////////////////////////////////////
      55              : 
      56              : namespace pcf
      57              : {
      58              : class Thread
      59              : {
      60              :   // Constants.
      61              :   public:
      62              :     enum Error
      63              :     {
      64              :       ErrNone =                     0, // This value must stay zero.
      65              :       ErrThreadUnjoinable =        -ENODEV,
      66              :       ErrBadThreadId =             -ESRCH,
      67              :       ErrDeadlock =                -EDEADLK,
      68              :       ErrCouldNotCreateThread =    -EAGAIN,
      69              :       ErrInvalidParameter  =       -EINVAL,
      70              :       ErrWrongPermission =         -EPERM,
      71              :       ErrAlreadyRunning =          -EALREADY,
      72              :       ErrInterrupted =             -EINTR,
      73              :       ErrCopy =                    -EFAULT,
      74              :       ErrTimedOut =                -ETIMEDOUT,
      75              :       ErrNotRunning =              -EHOSTDOWN,
      76              :       ErrCpuNumberOutOfRange =     -ENOENT,
      77              :       ErrUnknown =                 -9999
      78              :     };
      79              : 
      80              :     enum State
      81              :     {
      82              :       Idle =          0,
      83              :       BeforeExecute = 1,
      84              :       Execute =       2,
      85              :       AfterExecute =  3
      86              :     };
      87              : 
      88              :     enum ScheduleType
      89              :     {
      90              :       Inherit    = 0,
      91              :       Normal     = 1,
      92              :       Turbo      = 2,
      93              :     };
      94              : 
      95              :   // Constructor/destructor/operators.
      96              :   public:
      97              :     Thread();
      98              :     virtual ~Thread();
      99              :     Thread( const Thread &copy );
     100              :     const Thread &operator =( const Thread &copy );
     101              : 
     102              :   // Methods.
     103              :   public:
     104              :     /// Return the message concerning the error.
     105              :     static std::string getErrorMsg( const int &nErr );
     106              :     /// Returns the number of milliseconds between the 'execute' firing.
     107              :     unsigned int getInterval() const;
     108              :     /// Returns the current state of the thread.
     109              :     State getState() const;
     110              :     /// Returns true if the 'stop' flag has been set to true. The thread
     111              :     /// may still be running its last iteration, though. (see 'isRunning').
     112              :     bool isStopping() const;
     113              :     /// Is the thread "paused"?
     114              :     bool isPaused() const;
     115              :     /// Is the thread "running"?
     116              :     bool isRunning() const;
     117              :     /// Join the current thread back to the parent thread.
     118              :     int join();
     119              :     /// Pause the execution of the thread. "stop" will still end it.
     120              :     void pause();
     121              :     /// Resumes the Thread if it is paused. Calling 'resume' twice or more
     122              :     /// will have no effect.
     123              :     void resume();
     124              :     /// Resumes the Thread if it is paused, but only for one iteration. Calling
     125              :     /// 'resumeOnce' twice or more will have no effect.
     126              :     void resumeOnce();
     127              :     /// This is the interval between the "execute" functions firing.
     128              :     void setInterval( const unsigned int &nMSecs );
     129              :     /// should this thread only execute once?
     130              :     void setOneShot( const bool &oOneShot );
     131              :     /// Sets the socket file descriptor which will be used to cause the 'execute'
     132              :     /// method to run. If the socket descriptor is valid, the 'runLoop' will
     133              :     /// check to see if there is data waiting to be read on the socket and will
     134              :     /// not call 'execute' until there is.
     135              :     void setTrigger( pcf::SystemSocket *psocTrigger );
     136              :     /// Starts the thread running.
     137              :     int start( const int &iCpuAffinity = -1,
     138            3 :                const ScheduleType &tSchedule = Inherit );
     139              :     /// Stops the 'execute' function from firing by stopping the thread.
     140              :     void stop();
     141              :     /// Waits for the 'ready' mutex to be unlocked. This indicates that the
     142              :     /// 'execute' function is about to be run.
     143              :     void waitForReady();
     144              : 
     145              :    // Sleep and thread id functions.
     146              :   public:
     147              :     /// Put the calling thread to sleep for uiMillis milliseconds.
     148              :     static int msleep( const unsigned int &uiMillis );
     149              :     /// Put the calling thread to sleep for a timespec amount of time.
     150              :     static int nanosleep( const unsigned int &uiSeconds,
     151              :                           const unsigned int &uiNanos );
     152              :     /// Put the calling thread to sleep for uiNanos nanoseconds.
     153              :     static int nsleep( const unsigned int &uiNanos );
     154              :     /// Put the calling thread to sleep for uiSeconds seconds.
     155              :     static int sleep( const unsigned int &uiSeconds );
     156              :     /// Put the calling thread to sleep for uiMicros microseconds.
     157              :     static int usleep( const unsigned int &uiMicros );
     158              :     /// This will handle the signal which forces any system calls to return.
     159              :     static void processSignalHandler( int nSignal );
     160              : 
     161              :   // Overridable methods - these give the thread its personality.
     162              :   public:
     163              :     virtual void afterExecute();
     164              :     virtual void beforeExecute();
     165              :     virtual void execute();
     166              : 
     167              :   // Helper functions.
     168              :   protected:
     169              : #ifdef WIN32
     170              :     static DWORD WINAPI threadFuncWin( void *pUnknown );
     171              : #else
     172              :     static void *pthreadFunc( void *pUnknown );
     173              : #endif
     174              :     void runLoop();
     175              :     // Create and open the pipe for the pause/resume functionality.
     176              :     void setupPipe();
     177              : 
     178              :   // Variables.
     179              :   private:
     180              :     /// id or handle of the thread created.
     181              : #ifdef WIN32
     182              :     HANDLE m_idThis;
     183              : #else
     184              :     pthread_t m_idThis;
     185              : #endif
     186              :     /// the interval between calls of "execute".
     187              :     unsigned int m_uiInterval;
     188              :     /// The state the thread is currently in.
     189              :     State m_tState;
     190              :     /// Should we stop the thread?.
     191              :     bool m_oStop;
     192              :     /// Are we only performing this task ('execute' function) once?
     193              :     bool m_oOneShot;
     194              :     /// Is the thread performing the 'execute' function?
     195              :     bool m_oIsRunning;
     196              :     /// Are we pausing the thread for some amount of time?
     197              :     bool m_oIsPaused;
     198              :     /// The signal to send to make sure the thread returns from system calls.
     199              :     static int sm_nStopSignal;
     200              :     /// A structure to hold information about the signal action.
     201              :     struct sigaction m_saStop;
     202              :     /// This socket will be used to trigger the next iteration of the
     203              :     /// 'execute' loop if it is valid and it has data to read.
     204              :     pcf::SystemSocket *m_psocTrigger;
     205              :     /// This pipe is used as a way to resume the thread after it has
     206              :     /// been paused.
     207              :     int m_pfdPipe[2];
     208              :     /// A mutex that stays locked until this class is running its 'execute'
     209              :     /// method. It is locked on creation, and unlocked when 'execute' is called.
     210              :     mutable pcf::MutexLock m_mutReady;
     211              : 
     212              : }; // Class Thread
     213              : } // Namespace pcf
     214              : 
     215              : ////////////////////////////////////////////////////////////////////////////////
     216              : 
     217              : #endif // PCF_THREAD_HPP
        

Generated by: LCOV version 2.0-1