KVIrc  4.9.2
DeveloperAPIs
KviThread.h
Go to the documentation of this file.
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
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)
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 
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)
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 
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)
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 
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 
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:
154  KviMutex() { kvi_threadMutexInit(&m_mutex); };
155  virtual ~KviMutex() { kvi_threadMutexDestroy(&m_mutex); };
156 public:
157 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
158  void lock()
159  {
160  kvi_threadMutexLock(&m_mutex);
161  m_bLocked = true;
162  };
163  void unlock()
164  {
165  m_bLocked = false;
166  kvi_threadMutexUnlock(&m_mutex);
167  };
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 
183 {
184 public:
185  KviThread();
186  virtual ~KviThread();
187 
188 private:
189  kvi_thread_t m_thread;
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
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  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 
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 
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:
281 
282 public:
283  KviThreadEvent(int evId, KviThread * sender = 0)
284  : QEvent((QEvent::Type)KVI_THREAD_EVENT), m_eventId(evId), m_pSender(sender){};
285  virtual ~KviThreadEvent(){};
286 
287 public:
288  // This is the sender of the event
289  // WARNING : this MAY be null, threads CAN send anonymous events
290  KviThread * sender() { return m_pSender; };
291  int id() { return m_eventId; };
292 };
293 
294 template <class TData>
296 {
297 protected:
298  TData * m_pData;
299 
300 public:
301  KviThreadDataEvent(int evId, TData * pData = 0, KviThread * sender = 0)
302  : KviThreadEvent(evId, sender) { m_pData = pData; };
304  {
305  if(m_pData)
306  delete m_pData;
307  };
308 
309 public:
310  void setData(TData * d)
311  {
312  if(m_pData)
313  delete m_pData;
314  m_pData = d;
315  };
316  TData * getData()
317  {
318  TData * aux = m_pData;
319  m_pData = 0;
320  return aux;
321  };
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 
334 {
335 public:
337  virtual ~KviSensitiveThread();
338 
339 protected:
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 
364 {
365  QObject * o;
366  QEvent * e;
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.
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
390 #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
392  int m_fd[2];
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
QSocketNotifier * m_pSn
Definition: KviThread.h:385
Definition: KviHeapObject.h:124
void setData(TData *d)
Definition: KviThread.h:310
KviMutex * m_pLocalEventQueueMutex
Definition: KviThread.h:340
TData * data()
Definition: KviThread.h:322
KviThreadDataEvent(int evId, TData *pData=0, KviThread *sender=0)
Definition: KviThread.h:301
KviThread * m_pSender
Definition: KviThread.h:280
#define a
Definition: detector.cpp:91
struct _KviThreadPendingEvent KviThreadPendingEvent
char * NULL
Definition: KviIrcNumericCodes.h:391
kvi_mutex_t m_mutex
Definition: KviThread.h:149
TData * m_pData
Definition: KviThread.h:298
KviMutex * m_pRunningMutex
Definition: KviThread.h:192
virtual ~KviThreadEvent()
Definition: KviThread.h:285
QObject * o
Definition: KviThread.h:365
virtual ~KviThreadDataEvent()
Definition: KviThread.h:303
KviPointerList< KviThreadEvent > * m_pLocalEventQueue
Definition: KviThread.h:341
Definition: KviThread.h:146
Definition: KviThread.h:369
#define e
Definition: detector.cpp:69
KviPointerList< QEvent > * m_pLocalEventQueue
Definition: KviThread.h:193
kvi_thread_t m_thread
Definition: KviThread.h:189
KviThread * sender()
Definition: KviThread.h:290
void lock()
Definition: KviThread.h:170
virtual void run()
Definition: KviThread.h:224
char s d
Definition: KviIrcNumericCodes.h:391
Definition: KviThread.h:182
bool m_bStartingUp
Definition: KviThread.h:191
int m_iTriggerCount
Definition: KviThread.h:393
KviMutex * m_pMutex
Definition: KviThread.h:387
TData * getData()
Definition: KviThread.h:316
KviPointerList< KviThreadPendingEvent > * m_pEventQueue
Definition: KviThread.h:391
Definition: KviThread.h:276
int id()
Definition: KviThread.h:291
QHashIterator< int, QFile * > t(getDict)
KviMutex()
Definition: KviThread.h:154
Definition: KviThread.h:295
C++ Template based double linked pointer list class.
virtual ~KviMutex()
Definition: KviThread.h:155
int m_eventId
Definition: KviThread.h:279
Definition: KviApplication.h:102
#define o
Definition: detector.cpp:79
Heap Object.
#define KVI_THREAD_EVENT
Definition: KviThread.h:237
QEvent * e
Definition: KviThread.h:366
KviThreadEvent(int evId, KviThread *sender=0)
Definition: KviThread.h:283
void unlock()
Definition: KviThread.h:174
int m_iWaitingThreads
Definition: KviThread.h:389
KviPointerList< KviThread > * m_pThreadList
Definition: KviThread.h:388
This file contains compile time settings.
Definition: KviThread.h:333
bool m_bRunning
Definition: KviThread.h:190
Definition: KviThread.h:363
#define KVILIB_API
Definition: kvi_settings.h:125