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 © );
100 : const Thread &operator =( const Thread © );
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
|