KVIrc 5.2.4
Developer APIs
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
34class 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
49inline 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)
56inline 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
63inline 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)
85inline 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
95inline 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)
123inline 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
133inline 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{
148private:
149 kvi_mutex_t m_mutex;
150#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
151 bool m_bLocked;
152#endif
153public:
154 KviMutex() { kvi_threadMutexInit(&m_mutex); };
155 virtual ~KviMutex() { kvi_threadMutexDestroy(&m_mutex); };
156public:
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{
184public:
185 KviThread();
186 virtual ~KviThread();
187
188private:
189 kvi_thread_t m_thread;
194
195public:
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
219protected:
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 virtual void postEvent(QObject * o, QEvent * e);
230
231private:
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
276class KVILIB_API KviThreadEvent : public QEvent, public KviHeapObject
277{
278protected:
281
282public:
283 KviThreadEvent(int evId, KviThread * sender = nullptr)
284 : QEvent((QEvent::Type)KVI_THREAD_EVENT), m_eventId(evId), m_pSender(sender){};
286
287public:
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
294template <class TData>
296{
297protected:
298 TData * m_pData;
299
300public:
301 KviThreadDataEvent(int evId, TData * pData = nullptr, KviThread * sender = nullptr)
302 : KviThreadEvent(evId, sender) { m_pData = pData; };
304 {
305 if(m_pData)
306 delete m_pData;
307 };
308
309public:
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 = nullptr;
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{
335public:
337 virtual ~KviSensitiveThread();
338
339protected:
342
343public:
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
352protected:
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;
367};
368
369class KVILIB_API KviThreadManager : public QObject
370{
371 friend class KviApplication;
372 friend class KviThread;
373 Q_OBJECT
374protected:
375 // These should be private...but we don't want anyone to complain
376 // Treat as private plz.
379
380public:
381 static void killPendingEvents(QObject * receiver);
382
383private:
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
395protected:
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();
408private slots:
409 void eventsPending(int fd);
410};
411
412#endif
Heap Object.
C++ Template based double linked pointer list class.
#define KVI_THREAD_EVENT
Definition KviThread.h:237
Definition KviApplication.h:106
Definition KviHeapObject.h:119
Definition KviThread.h:147
void unlock()
Definition KviThread.h:174
void lock()
Definition KviThread.h:170
virtual ~KviMutex()
Definition KviThread.h:155
kvi_mutex_t m_mutex
Definition KviThread.h:149
KviMutex()
Definition KviThread.h:154
A template double linked list of pointers.
Definition KviPointerList.h:371
Definition KviThread.h:334
KviPointerList< KviThreadEvent > * m_pLocalEventQueue
Definition KviThread.h:341
KviMutex * m_pLocalEventQueueMutex
Definition KviThread.h:340
Definition KviThread.h:296
TData * data()
Definition KviThread.h:322
TData * m_pData
Definition KviThread.h:298
~KviThreadDataEvent()
Definition KviThread.h:303
TData * getData()
Definition KviThread.h:316
KviThreadDataEvent(int evId, TData *pData=nullptr, KviThread *sender=nullptr)
Definition KviThread.h:301
void setData(TData *d)
Definition KviThread.h:310
Definition KviThread.h:277
KviThreadEvent(int evId, KviThread *sender=nullptr)
Definition KviThread.h:283
KviThread * m_pSender
Definition KviThread.h:280
int m_eventId
Definition KviThread.h:279
KviThread * sender()
Definition KviThread.h:290
~KviThreadEvent()
Definition KviThread.h:285
int id()
Definition KviThread.h:291
Definition KviThread.h:370
int m_iWaitingThreads
Definition KviThread.h:389
KviPointerList< KviThread > * m_pThreadList
Definition KviThread.h:388
KviMutex * m_pMutex
Definition KviThread.h:387
QSocketNotifier * m_pSn
Definition KviThread.h:385
int m_iTriggerCount
Definition KviThread.h:393
KviPointerList< KviThreadPendingEvent > * m_pEventQueue
Definition KviThread.h:391
Definition KviThread.h:183
kvi_thread_t m_thread
Definition KviThread.h:189
bool m_bRunning
Definition KviThread.h:190
bool m_bStartingUp
Definition KviThread.h:191
virtual void run()
Definition KviThread.h:224
KviPointerList< QEvent > * m_pLocalEventQueue
Definition KviThread.h:193
KviMutex * m_pRunningMutex
Definition KviThread.h:192
#define t
Definition detector.cpp:85
#define d
Definition detector.cpp:69
#define e
Definition detector.cpp:70
#define a
Definition detector.cpp:92
#define o
Definition detector.cpp:80
This file contains compile time settings.
#define KVILIB_API
Definition kvi_settings.h:124
Definition KviThread.h:364
QEvent * e
Definition KviThread.h:366
QObject * o
Definition KviThread.h:365