1 #ifndef _KVI_THREAD_H_
2 #define _KVI_THREAD_H_
3 //=============================================================================
4 //
5 //   File : KviThread.h
6 //   Creation date : Mon May 17 1999 04:26:41 CEST by Szymon Stefanek
7 //
8 //   This file is part of the KVIrc IRC client distribution
9 //   Copyright (C) 1999-2010 Szymon Stefanek (pragma at kvirc dot net)
10 //
11 //   This program is FREE software. You can redistribute it and/or
12 //   modify it under the terms of the GNU General Public License
13 //   as published by the Free Software Foundation; either version 2
14 //   of the License, or (at your option) any later version.
15 //
16 //   This program is distributed in the HOPE that it will be USEFUL,
17 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 //   See the GNU General Public License for more details.
20 //
21 //   You should have received a copy of the GNU General Public License
22 //   along with this program. If not, write to the Free Software Foundation,
23 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 //=============================================================================
26 
27 #include "kvi_settings.h"
28 #include "KviHeapObject.h"
29 #include "KviPointerList.h"
30 
31 #include <QObject>
32 #include <QEvent>
33 
34 class QSocketNotifier;
35 
36 //
37 // Simple thread implementation
38 // This is enough for KVIrc needs
39 // HANDLE WITH CARE
40 //
41 
42 // Portability stuff
43 
44 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
45 
46 #include <winsock2.h>
47 // Windoze thread abstraction layer
48 #define kvi_mutex_t HANDLE
kvi_threadMutexInit(kvi_mutex_t * _pMutex_t)49 inline void kvi_threadMutexInit(kvi_mutex_t * _pMutex_t)
50 {
51 	*_pMutex_t = CreateMutex(0, 0, NULL);
52 }
53 #define kvi_threadMutexLock(_pMutex_t) WaitForSingleObject(*_pMutex_t, INFINITE)
54 #define kvi_threadMutexUnlock(_pMutex_t) ReleaseMutex(*_pMutex_t)
55 #define kvi_threadMutexDestroy(_pMutex_t) CloseHandle(*_pMutex_t)
kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)56 inline bool kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)
57 {
58 	return (WaitForSingleObject(*_pMutex_t, 0) == WAIT_OBJECT_0);
59 }
60 
61 #define kvi_thread_t HANDLE
62 
kvi_threadCreate(kvi_thread_t * t,LPTHREAD_START_ROUTINE start_routine,void * arg)63 inline bool kvi_threadCreate(kvi_thread_t * t, LPTHREAD_START_ROUTINE start_routine, void * arg)
64 {
65 	DWORD dwThreadId;
66 	*t = CreateThread(NULL, 0, start_routine, arg, 0, &dwThreadId);
67 	return (*t != NULL);
68 }
69 
70 #define kvi_threadExit() ExitThread(0)
71 
72 #else
73 #ifdef COMPILE_THREADS_USE_POSIX
74 // Glibc pthread implementation
75 
76 #include <pthread.h>
77 #include <errno.h> // for EBUSY
78 
79 // Mutex stuff
80 #define kvi_mutex_t pthread_mutex_t
81 #define kvi_threadMutexInit(_pMutex_t) pthread_mutex_init(_pMutex_t, 0)
82 #define kvi_threadMutexLock(_pMutex_t) pthread_mutex_lock(_pMutex_t)
83 #define kvi_threadMutexUnlock(_pMutex_t) pthread_mutex_unlock(_pMutex_t)
84 #define kvi_threadMutexDestroy(_pMutex_t) pthread_mutex_destroy(_pMutex_t)
kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)85 inline bool kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)
86 {
87 	return (pthread_mutex_trylock(_pMutex_t) != EBUSY);
88 }
89 // Actually unused
90 // #define kvi_threadMutexTryLock(_pMutex_t) pthread_mutex_trylock(_pMutex_t)
91 
92 // Thread stuff
93 #define kvi_thread_t pthread_t
94 
kvi_threadCreate(kvi_thread_t * t,void * (* start_routine)(void *),void * arg)95 inline bool kvi_threadCreate(kvi_thread_t * t, void * (*start_routine)(void *), void * arg)
96 {
97 	pthread_attr_t a;
98 	pthread_attr_init(&a);
99 	pthread_attr_setinheritsched(&a, PTHREAD_INHERIT_SCHED);
100 	pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
101 
102 	int ret = pthread_create(t, &a, start_routine, arg);
103 
104 	pthread_attr_destroy(&a);
105 	return (ret == 0);
106 }
107 
108 // We don't care about exit codes at all
109 #define kvi_threadExit() pthread_exit(0)
110 #else
111 #ifdef COMPILE_THREADS_USE_SOLARIS_LIBTHREAD
112 // Native solaris implementation
113 #include <thread.h>
114 #include <synch.h>
115 #include <errno.h>
116 
117 // Mutex stuff
118 #define kvi_mutex_t mutex_t
119 #define kvi_threadMutexInit(_pMutex_t) mutex_init(_pMutex_t, 0, 0)
120 #define kvi_threadMutexLock(_pMutex_t) mutex_lock(_pMutex_t)
121 #define kvi_threadMutexUnlock(_pMutex_t) mutex_unlock(_pMutex_t)
122 #define kvi_threadMutexDestroy(_pMutex_t) mutex_destroy(_pMutex_t)
kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)123 inline bool kvi_threadMutexTryLock(kvi_mutex_t * _pMutex_t)
124 {
125 	return (mutex_trylock(_pMutex_t) != EBUSY);
126 };
127 // Actually unused
128 // #define kvi_threadMutexTryLock(_pMutex_t) mutex_trylock(_pMutex_t)
129 
130 // Thread stuff
131 #define kvi_thread_t thread_t
132 
kvi_threadCreate(kvi_thread_t * t,void * (* start_routine)(void *),void * arg)133 inline bool kvi_threadCreate(kvi_thread_t * t, void * (*start_routine)(void *), void * arg)
134 {
135 	return (thr_create(0, 0, start_routine, arg, THR_DETACHED, t) == 0);
136 }
137 
138 // We don't care about exit codes at all
139 #define kvi_threadExit() thr_exit(0)
140 #else
141 // FIXME: 			#warning "Missing a decent thread implementation: we're going to fail, sorry!"
142 #endif
143 #endif
144 #endif
145 
146 class KVILIB_API KviMutex : public KviHeapObject
147 {
148 private:
149 	kvi_mutex_t m_mutex;
150 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
151 	bool m_bLocked;
152 #endif
153 public:
KviMutex()154 	KviMutex() { kvi_threadMutexInit(&m_mutex); };
~KviMutex()155 	virtual ~KviMutex() { kvi_threadMutexDestroy(&m_mutex); };
156 public:
157 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
lock()158 	void lock()
159 	{
160 		kvi_threadMutexLock(&m_mutex);
161 		m_bLocked = true;
162 	};
unlock()163 	void unlock()
164 	{
165 		m_bLocked = false;
166 		kvi_threadMutexUnlock(&m_mutex);
167 	};
locked()168 	bool locked() { return m_bLocked; };
169 #else
170 	void lock()
171 	{
172 		kvi_threadMutexLock(&m_mutex);
173 	};
174 	void unlock() { kvi_threadMutexUnlock(&m_mutex); };
175 	bool locked();
176 #endif
177 };
178 
179 // simple thread class implementation
180 // this is also called "Blind" thread class
181 
182 class KVILIB_API KviThread : public KviHeapObject
183 {
184 public:
185 	KviThread();
186 	virtual ~KviThread();
187 
188 private:
189 	kvi_thread_t m_thread;
190 	bool m_bRunning;
191 	bool m_bStartingUp;
192 	KviMutex * m_pRunningMutex;
193 	KviPointerList<QEvent> * m_pLocalEventQueue;
194 
195 public:
196 	// public KviThread interface
197 	// HANDLE WITH CARE
198 
199 	// Runs the thread...call only from external threads!!! :)
200 	// This function returns true if the child thread has been successfully created
201 	// this des not mean that run() is being already executed...
202 	// isStartingUp() will return true from this moment until
203 	// the child thread jumps into run() where it will be set to running state (isRunning() == true)
204 	// and removed from startingUp state.
205 	bool start();
206 	// Returns the state of the thread...safe to call from anywhere
207 	bool isRunning();
208 	// Returns the state of the thread...safe to call from anywhere
209 	bool isStartingUp(); // start() called, but not in run() yet...
210 	// Waits for the termination of this thread: call only from external threads!!! :)
211 	void wait();
212 	// DO NOT TOUCH THIS ONE!
213 	void internalThreadRun_doNotTouchThis();
214 
215 	static void sleep(unsigned long sec);
216 	static void msleep(unsigned long msec);
217 	static void usleep(unsigned long usec);
218 
219 protected:
220 	// protected KviThread interface
221 	// HANDLE WITH CARE TOO!
222 
223 	// Reimplement this with your job
run()224 	virtual void run(){};
225 	// Terminates the execution of the calling thread
226 	void exit();
227 	// The tricky part: threadsafe event dispatching
228 	// Slave thread -> main thread objects
229 	virtual void postEvent(QObject * o, QEvent * e);
230 
231 private:
232 	void setRunning(bool bRunning);
233 	void setStartingUp(bool bStartingUp);
234 };
235 
236 // QEvent::Type for Thread events
237 #define KVI_THREAD_EVENT (((int)QEvent::User) + 2000)
238 
239 // CONSTANTS FOR KviThreadEvent::eventId();
240 
241 ///////////////////////////////////////////////////////////////
242 // extern -> slave thread
243 
244 // Your reimplementation of KviSensitiveThread MUST handle this
245 // and exit when this event is received
246 
247 // Terminate is a plain KviThreadEvent
248 #define KVI_THREAD_EVENT_TERMINATE 0
249 
250 ///////////////////////////////////////////////////////////////
251 // slave thread -> master object
252 
253 // The following standard events are sent from the thread to the master object
254 
255 // The following are plain KviThreadEvent objects
256 #define KVI_THREAD_EVENT_SUCCESS 100
257 
258 // The following are KviThreadDataEvent<int>
259 #define KVI_THREAD_EVENT_STATECHANGE 150
260 
261 // The following are KviThreadDataEvent<KviCString>
262 #define KVI_THREAD_EVENT_MESSAGE 200
263 #define KVI_THREAD_EVENT_WARNING 201
264 #define KVI_THREAD_EVENT_ERROR 202
265 #define KVI_THREAD_EVENT_DATA 203
266 
267 // The following is KviThreadDataEvent<KviDataBuffer>
268 #define KVI_THREAD_EVENT_BINARYDATA 300
269 
270 // The user events
271 #define KVI_THREAD_USER_EVENT_BASE 1000
272 
273 // #warning "Get rid of the m_szMessage member of KviThreadEvent : eventual data should be passed with a KviThreadDataEvent"
274 
275 // Base class for all thread events
276 class KVILIB_API KviThreadEvent : public QEvent, public KviHeapObject
277 {
278 protected:
279 	int m_eventId;
280 	KviThread * m_pSender;
281 
282 public:
283 	KviThreadEvent(int evId, KviThread * sender = nullptr)
284 	    : QEvent((QEvent::Type)KVI_THREAD_EVENT), m_eventId(evId), m_pSender(sender){};
~KviThreadEvent()285 	~KviThreadEvent(){};
286 
287 public:
288 	// This is the sender of the event
289 	// WARNING : this MAY be null, threads CAN send anonymous events
sender()290 	KviThread * sender() { return m_pSender; };
id()291 	int id() { return m_eventId; };
292 };
293 
294 template <class TData>
295 class KviThreadDataEvent : public KviThreadEvent
296 {
297 protected:
298 	TData * m_pData;
299 
300 public:
301 	KviThreadDataEvent(int evId, TData * pData = nullptr, KviThread * sender = nullptr)
KviThreadEvent(evId,sender)302 	    : KviThreadEvent(evId, sender) { m_pData = pData; };
~KviThreadDataEvent()303 	~KviThreadDataEvent()
304 	{
305 		if(m_pData)
306 			delete m_pData;
307 	};
308 
309 public:
setData(TData * d)310 	void setData(TData * d)
311 	{
312 		if(m_pData)
313 			delete m_pData;
314 		m_pData = d;
315 	};
getData()316 	TData * getData()
317 	{
318 		TData * aux = m_pData;
319 		m_pData = nullptr;
320 		return aux;
321 	};
data()322 	TData * data() { return m_pData; };
323 };
324 
325 // A thread that has also an internal event queue
326 // so events can be posted from the master side to the slave one
327 // Reimplementations of this class should periodically check
328 // dequeueEvent() and eventually process the incoming events (and then DELETE it)
329 
330 // KVI_THREAD_EVENT_TERMINATE should be always handled by the reimplementation
331 // and it should always exit (cleanly) when this event is received
332 
333 class KVILIB_API KviSensitiveThread : public KviThread
334 {
335 public:
336 	KviSensitiveThread();
337 	virtual ~KviSensitiveThread();
338 
339 protected:
340 	KviMutex * m_pLocalEventQueueMutex;
341 	KviPointerList<KviThreadEvent> * m_pLocalEventQueue;
342 
343 public:
344 	// enqueues an event directed to THIS thread
345 	// the event must be allocated with NEW and
346 	// will be destroyed on the slave side
347 	void enqueueEvent(KviThreadEvent * e);
348 	// enqueues a terminate event and waits() for the slave thread
349 	// the slave thread MUST handle KVI_THREAD_EVENT_TERMINATE
350 	void terminate();
351 
352 protected:
353 	// slave side:
354 	// returns the first event in the local queue
355 	// the event MUST BE DELETED after processing
356 	KviThreadEvent * dequeueEvent();
357 };
358 
359 // =============================================================================================//
360 // This is private stuff...only KviThread and KviApplication may use it
361 // and may call only specific functions...don't touch.
362 
363 struct KviThreadPendingEvent
364 {
365 	QObject * o;
366 	QEvent * e;
367 };
368 
369 class KVILIB_API KviThreadManager : public QObject
370 {
371 	friend class KviApplication;
372 	friend class KviThread;
373 	Q_OBJECT
374 protected:
375 	// These should be private...but we don't want anyone to complain
376 	// Treat as private plz.
377 	KviThreadManager();
378 	~KviThreadManager();
379 
380 public:
381 	static void killPendingEvents(QObject * receiver);
382 
383 private:
384 #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
385 	QSocketNotifier * m_pSn;
386 #endif
387 	KviMutex * m_pMutex; // This class performs only atomic operations
388 	KviPointerList<KviThread> * m_pThreadList;
389 	int m_iWaitingThreads;
390 #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
391 	KviPointerList<KviThreadPendingEvent> * m_pEventQueue;
392 	int m_fd[2];
393 	int m_iTriggerCount;
394 #endif
395 protected:
396 	// Public to KviThread only
397 	void registerSlaveThread(KviThread * t);
398 	void unregisterSlaveThread(KviThread * t);
399 
400 	void threadEnteredWaitState();
401 	void threadLeftWaitState();
402 
403 	void postSlaveEvent(QObject * o, QEvent * e);
404 	void killPendingEventsByReceiver(QObject * receiver);
405 	// Public to KviApplication only
406 	static void globalInit();
407 	static void globalDestroy();
408 private slots:
409 	void eventsPending(int fd);
410 };
411 
412 #endif //!_KVI_THREAD_H_
413