1 //
2 // Thread.h: header file
3 //
4 // Copyright (C) Walter E. Capers.  All rights reserved
5 //
6 // This source is free to use as you like.  If you make
7 // any changes please keep me in the loop.  Email them to
8 // walt.capers@comcast.net.
9 //
10 // PURPOSE:
11 //
12 //  To implement Win32 threading as a C++ object
13 //
14 // REVISIONS
15 // =======================================================
16 // Date: 10.24.07
17 // Name: Walter E. Capers
18 // Description: File creation
19 //
20 // Date: 10.24.07 11:49 am
21 // Name: Walter E. Capers
22 // Description: Added SetIdle function to allow the idle time to be altered
23 //              independent of the SetThreadType member function.
24 // Date: 10.31.07
25 // Name: Walter E. Capers
26 // Description: Added support for beginthreadex
27 //              To use compile with -DUSE_BEGIN_THREAD
28 //
29 //
30 
31 #ifndef THREAD_CLASS
32 #define THREAD_CLASS
33 
34 #ifndef WINDOWS
35 #if defined(_WIN32) || defined(_WIN64)
36 #define WINDOWS
37 #endif
38 #endif
39 #ifdef __APPLE__
40 #define VMS
41 #endif
42 
43 #ifndef WINDOWS
44 #include <stdio.h>
45 #include <string.h>
46 //#include <malloc.h>
47 #include <memory.h>
48 #include <pthread.h>
49 #include <stdlib.h>
50 #include <time.h>
51 #include <errno.h>
52 typedef unsigned char BOOL;
53 #define TRUE 1
54 #define FALSE 0
55 typedef long DWORD;
56 typedef void *LPVOID;
57 #else
58 #include "afx.h"
59 /* #include <windows.h> */
60 #include <stdio.h>
61 #endif
62 
63 #if defined(AS400) || defined(OS400)
64 typedef pthread_id_np_t ThreadId_t;
65 #elif defined(VMS) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
66 typedef pthread_t ThreadId_t;
67 #else
68 #ifdef USE_BEGIN_THREAD
69 typedef unsigned ThreadId_t;
70 #else
71 typedef DWORD ThreadId_t;
72 #endif
73 #endif
74 
75 #include <common/MutexClass.h>
76 #include <common/EventClass.h>
77 
78 #define QUEUE_SIZE 100
79 #define DEFAULT_STACK_SIZE 0
80 #ifndef WINDOWS
81 void Sleep( unsigned int mseconds);
82 #endif
83 
84 #ifndef ASSERT
85 #if defined(DEBUG) || defined(_DEBUG)
86 #define ASSERT(test) if( !(test) ) { \
87 	fprintf(stderr,"\nASSERT(%s) FAILS, %s line %d\n",#test,__FILE__, __LINE__); exit(0);}
88 #else
89 #define ASSERT(test)
90 #endif
91 #endif
92 
93 
94 typedef enum {
95 	ThreadStateBusy,               // thread is currently handling a task
96 	ThreadStateWaiting,            // thread is waiting for something to do
97     ThreadStateDown,               // thread is not running
98     ThreadStateShuttingDown,       // thread is in the process of shutting down
99     ThreadStateFault               // an error has occured and the thread could not
100 	                               // be launched
101 } ThreadState_t;
102 
103 typedef enum {
104 	ThreadTypeHomogeneous,
105 	ThreadTypeSpecialized,
106     ThreadTypeIntervalDriven,
107     ThreadTypeNotDefined } ThreadType_t;
108 
109 
110 typedef enum {
111 	TaskStatusNotSubmitted,
112 	TaskStatusWaitingOnQueue,
113 	TaskStatusBeingProcessed,
114 	TaskStatusCompleted } TaskStatus_t;
115 
116 class CTask
117 {
118 private:
119 	TaskStatus_t m_state;
120 	ThreadId_t m_dwThread;
121 public:
122 	CMutexClass m_mutex;
123 
SetTaskStatus(TaskStatus_t state)124 	void SetTaskStatus(TaskStatus_t state)
125 	{
126 		m_mutex.Lock();
127 			m_state=state;
128 		m_mutex.Unlock();
129 	}
130 
SetId(ThreadId_t * pid)131 	void SetId(ThreadId_t *pid)
132 	{
133 		memcpy(&m_dwThread,pid,sizeof(ThreadId_t));
134 	}
135 
136 	/**
137 	 *
138 	 * Wait
139 	 * waits for upto timeoutSeconds for a task
140 	 * to complete
141 	 *
142 	 **/
Wait(int timeoutSeconds)143 	BOOL Wait(int timeoutSeconds)
144 	{
145         timeoutSeconds = timeoutSeconds * 1000;
146 		if( Status() != TaskStatusCompleted &&
147 			timeoutSeconds > 0 )
148 		{
149 			Sleep(100);
150 			timeoutSeconds = timeoutSeconds - 100;
151 		}
152 		if( Status() == TaskStatusCompleted ) return TRUE;
153 		return FALSE;
154 	}
155 
156 	/**
157 	 *
158 	 * Status
159 	 * returns current state of a task
160 	 *
161 	 **/
Status()162 	TaskStatus_t Status()
163 	{
164 		TaskStatus_t state ;
165 
166 		m_mutex.Lock();
167 		  state = m_state;
168 		m_mutex.Unlock();
169 	    return state;
170 	}
171 
Thread(ThreadId_t * pId)172 	void Thread(ThreadId_t *pId)
173 	{
174 		memcpy(pId,&m_dwThread,sizeof(ThreadId_t));
175 	}
176 
CTask()177 	CTask(){m_state=TaskStatusNotSubmitted; memset(&m_dwThread,0,sizeof(ThreadId_t)); }
~CTask()178 	~CTask(){}
179 	virtual BOOL Task()=0;
180 };
181 
182 
183 class CThread
184 #ifdef WINDOWS
185 	: public CObject // use CObject as a base class so object can be used in lists and
186 	               // object arrays
187 #endif
188 {
189 private:
190 	CEventClass   m_event;         // event controller
191 	int           m_StopTimeout;   // specifies a timeout value for stop
192 	                               // if a thread fails to stop within m_StopTimeout
193 	                               // seconds an exception is thrown
194 
195 	BOOL		  m_bRunning;      // set to TRUE if thread is running
196 #ifdef WINDOWS
197 	HANDLE		  m_thread;		   // thread handle
198 #else
199 	pthread_t     m_thread;        // thread handle
200 #endif
201 	ThreadId_t	  m_dwId;          // id of this thread
202 	LPVOID        *m_lppvQueue;    // task que
203 	unsigned int  m_chQueue;       // que depth
204 	unsigned int  m_queuePos;      // current que possition
205 	LPVOID        m_lpvProcessor;  // data which is currently being processed
206 	ThreadState_t m_state;         // current state of thread see thread state data
207 	                               // structure.
208 	DWORD         m_dwIdle;        // used for Sleep periods
209 	ThreadType_t  m_type;
210 	DWORD		  m_stackSize;     // thread stack size
211 #define NO_ERRORS			       0
212 #define MUTEX_CREATION		       0x01
213 #define EVENT_CREATION		       0x02
214 #define THREAD_CREATION		       0x04
215 #define UNKNOWN					   0x08
216 #define ILLEGAL_USE_OF_EVENT       0x10
217 #define MEMORY_FAULT               0x20
218 #define EVENT_AND_TYPE_DONT_MATCH  0x40
219 #define STACK_OVERFLOW             0x80
220 #define STACK_EMPTY                0x100
221 #define STACK_FULL                 0x200
222 
223 	DWORD         m_dwObjectCondition;
224 	BOOL		  Push(LPVOID lpv);
225 	BOOL		  Pop();
226 	BOOL		  Empty();
227 public:
228 	/**
229 	 *
230 	 * user definable member functions
231 	 *
232 	 **/
233 	CMutexClass	  m_mutex;         // mutex that protects threads internal data
234 
235 	virtual BOOL OnTask(LPVOID lpvData);     // called when an event occurs
236 	virtual BOOL OnTask();                   // called when a time interval has elapsed
237 
238 	CThread(void);
239 	~CThread(void);
240 #ifdef WINDOWS
241 #ifdef USE_BEGIN_THREAD
242 	friend unsigned __stdcall _THKERNEL(LPVOID lpvData);
243 #else
244 	friend DWORD WINAPI _THKERNEL( LPVOID lpvData );
245 #endif
246 #else
247 	friend LPVOID _THKERNEL(LPVOID lpvData);
248 #endif
249 	BOOL        FromSameThread();
250 	float		PercentCapacity();
251 	void        WaitTillExit();
252 	BOOL		KernelProcess();
253 	BOOL		Event(LPVOID lpvData=NULL);
254 	BOOL        Event(CTask *pvTask);
SetOnStopTimeout(int seconds)255 	void		SetOnStopTimeout(int seconds ) { m_StopTimeout = seconds; }
256     BOOL        SetQueueSize( unsigned int ch );
257 	BOOL		Stop();
258 	BOOL		Start();
GetId(ThreadId_t * pId)259 	void		GetId(ThreadId_t *pId) { memcpy(pId,&m_dwId,sizeof(ThreadId_t)); }      // returns thread id
260 	ThreadState_t ThreadState();
261 	BOOL		PingThread(DWORD dwTimeout=0);
262 	BOOL        AtCapacity();
263 #ifdef WINDOWS
264 	void		SetPriority(DWORD dwPriority=THREAD_PRIORITY_NORMAL);
265 #else
266 	void		SetPriority(DWORD dwPriority=0);
267 #endif
GetErrorFlags()268 	DWORD		GetErrorFlags() { return m_dwObjectCondition; } // returns state of object
269 	void		SetThreadType(ThreadType_t typ=ThreadTypeNotDefined,DWORD dwIdle=100);
270 	void		SetIdle(DWORD dwIdle=100);
271     unsigned int GetEventsPending();
ThreadIdsEqual(ThreadId_t * p1,ThreadId_t * p2)272     static BOOL ThreadIdsEqual(ThreadId_t *p1,
273 						       ThreadId_t *p2)
274 	{
275 #if defined(AS400)||defined(OS400)
276 		return(( memcmp(p1,p2,sizeof(ThreadId_t))==0)?TRUE:FALSE);
277 #elif defined(VMS) || defined(__NetBSD__)
278 		return (( pthread_equal(*p1,*p2) )?TRUE:FALSE );
279 #else
280 		return ((*p1 == *p2)?TRUE:FALSE);
281 #endif
282 
283 	}
284 
ThreadId()285 	static ThreadId_t ThreadId()
286 	{
287 		ThreadId_t thisThreadsId ;
288 #if defined(AS400) || defined(OS400)
289 		pthread_t thread;
290 #endif
291 
292 #ifdef WINDOWS
293 		thisThreadsId = (ThreadId_t)GetCurrentThreadId();
294 #else
295 
296 #if defined(AS400) || defined(OS400)
297 		thread = pthread_self();
298 		pthread_getunique_np(&thread,&thisThreadsId);
299 #elif defined(ALPHA) || defined(DEC) || defined(VMS)
300 #ifdef VMS
301 		thisThreadsId = pthread_self();
302 #else
303 		thisThreadsId = pthread_getsequence_np(pthread_self());
304 #endif
305 #else
306 		thisThreadsId = pthread_self();
307 #endif
308 #endif
309 		return thisThreadsId;
310 	}
311 
312 
313 };
314 #endif
315 
316