3
//=============================================================================
6
// Creation date : Mon May 17 1999 04:26:41 CEST by Szymon Stefanek
8
// This file is part of the KVirc irc client distribution
9
// Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
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 opinion) any later version.
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.
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.
25
//=============================================================================
27
#include "kvi_settings.h"
28
#include "kvi_heapobject.h"
29
#include "kvi_string.h"
32
#include <QSocketNotifier>
33
#include "kvi_pointerlist.h"
38
// Simple thread implementation
39
// This is enough for KVIrc needs
46
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
48
#include <winsock2.h> // this will pull in windows.h and will avoid windock.h inclusion
49
//#include <windows.h>
50
// Windoze thread abstraction layer
51
#define kvi_mutex_t HANDLE
52
inline void kvi_threadMutexInit(kvi_mutex_t * _pMutex_t)
54
*_pMutex_t = CreateMutex(0,0,NULL);
56
#define kvi_threadMutexLock(_pMutex_t) WaitForSingleObject(*_pMutex_t,INFINITE)
57
#define kvi_threadMutexUnlock(_pMutex_t) ReleaseMutex(*_pMutex_t)
58
#define kvi_threadMutexDestroy(_pMutex_t) CloseHandle(*_pMutex_t)
59
inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
61
return (WaitForSingleObject(*_pMutex_t,0) == WAIT_OBJECT_0);
64
#define kvi_thread_t HANDLE
66
inline bool kvi_threadCreate(kvi_thread_t *t,LPTHREAD_START_ROUTINE start_routine,void * arg)
69
*t = CreateThread(NULL,0,start_routine,arg,0,&dwThreadId);
73
#define kvi_threadExit() ExitThread(0)
76
#ifdef COMPILE_THREADS_USE_POSIX
77
// Glibc pthread implementation
80
#include <errno.h> // for EBUSY
83
#define kvi_mutex_t pthread_mutex_t
84
#define kvi_threadMutexInit(_pMutex_t) pthread_mutex_init(_pMutex_t,0)
85
#define kvi_threadMutexLock(_pMutex_t) pthread_mutex_lock(_pMutex_t)
86
#define kvi_threadMutexUnlock(_pMutex_t) pthread_mutex_unlock(_pMutex_t)
87
#define kvi_threadMutexDestroy(_pMutex_t) pthread_mutex_destroy(_pMutex_t)
88
inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
90
return (pthread_mutex_trylock(_pMutex_t) != EBUSY);
93
// #define kvi_threadMutexTryLock(_pMutex_t) pthread_mutex_trylock(_pMutex_t)
96
#define kvi_thread_t pthread_t
98
inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void * arg)
101
pthread_attr_init(&a);
102
pthread_attr_setinheritsched(&a,PTHREAD_INHERIT_SCHED);
103
pthread_attr_setdetachstate(&a,PTHREAD_CREATE_DETACHED);
105
int ret = pthread_create(t,&a,start_routine,arg);
107
pthread_attr_destroy(&a);
111
// We don't care about exit codes at all
112
#define kvi_threadExit() pthread_exit(0)
114
#ifdef COMPILE_THREADS_USE_SOLARIS_LIBTHREAD
115
// Native solaris implementation
121
#define kvi_mutex_t mutex_t
122
#define kvi_threadMutexInit(_pMutex_t) mutex_init(_pMutex_t,0,0)
123
#define kvi_threadMutexLock(_pMutex_t) mutex_lock(_pMutex_t)
124
#define kvi_threadMutexUnlock(_pMutex_t) mutex_unlock(_pMutex_t)
125
#define kvi_threadMutexDestroy(_pMutex_t) mutex_destroy(_pMutex_t)
126
inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
128
return (mutex_trylock(_pMutex_t) != EBUSY);
131
// #define kvi_threadMutexTryLock(_pMutex_t) mutex_trylock(_pMutex_t)
134
#define kvi_thread_t thread_t
136
inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void *arg)
138
return (thr_create(0,0,start_routine,arg,THR_DETACHED,t) == 0);
141
// We don't care about exit codes at all
142
#define kvi_threadExit() thr_exit(0)
144
// FIXME: #warning "Missing a decent thread implementation: we're going to fail , sorry!"
149
class KVILIB_API KviMutex : public KviHeapObject
153
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
157
KviMutex(){ kvi_threadMutexInit(&m_mutex); };
158
virtual ~KviMutex(){ kvi_threadMutexDestroy(&m_mutex); };
160
#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
161
void lock(){ kvi_threadMutexLock(&m_mutex); m_bLocked = true; };
162
void unlock(){ m_bLocked = false; kvi_threadMutexUnlock(&m_mutex); };
163
bool locked(){ return m_bLocked; };
165
void lock(){ kvi_threadMutexLock(&m_mutex); };
166
void unlock(){ kvi_threadMutexUnlock(&m_mutex); };
172
// simple thread class implementation
173
// this is also called "Blind" thread class
175
class KVILIB_API KviThread : public KviHeapObject
179
virtual ~KviThread();
181
kvi_thread_t m_thread;
184
KviMutex * m_pRunningMutex;
185
KviPointerList<QEvent> * m_pLocalEventQueue;
187
// public KviThread interface
190
// Runs the thread...call only from external threads!!! :)
191
// This function returns true if the child thread has been successfully created
192
// this des not mean that run() is being already executed...
193
// isStartingUp() will return true from this moment until
194
// the child thread jumps into run() where it will be set to running state (isRunning() == true)
195
// and removed from startingUp state.
197
// Returns the state of the thread...safe to call from anywhere
199
// Returns the state of the thread...safe to call from anywhere
200
bool isStartingUp(); // start() called , but not in run() yet...
201
// Waits for the termination of this thread: call only from external threads!!! :)
203
// DO NOT TOUCH THIS ONE!
204
void internalThreadRun_doNotTouchThis();
206
static void sleep(unsigned long sec);
207
static void msleep(unsigned long msec);
208
static void usleep(unsigned long usec);
210
// protected KviThread interface
211
// HANDLE WITH CARE TOO!
213
// Reimplement this with your job
214
virtual void run(){};
215
// Terminates the execution of the calling thread
217
// The tricky part: threadsafe event dispatching
218
// Slave thread -> main thread objects
219
void postEvent(QObject *o,QEvent *e);
221
void setRunning(bool bRunning);
222
void setStartingUp(bool bStartingUp);
225
// QEvent::Type for Thread events
226
#define KVI_THREAD_EVENT (((int)QEvent::User) + 2000)
228
// CONSTANTS FOR KviThreadEvent::eventId();
230
///////////////////////////////////////////////////////////////
231
// extern -> slave thread
233
// Your reimplementation of KviSensitiveThread MUST handle this
234
// and exit when this event is received
236
// Terminate is a plain KviThreadEvent
237
#define KVI_THREAD_EVENT_TERMINATE 0
239
///////////////////////////////////////////////////////////////
240
// slave thread -> master object
242
// The following standard events are sent from the thread to the master object
244
// The following are plain KviThreadEvent objects
245
#define KVI_THREAD_EVENT_SUCCESS 100
247
// The following are KviThreadDataEvent<int>
248
#define KVI_THREAD_EVENT_STATECHANGE 150
250
// The following are KviThreadDataEvent<KviStr>
251
#define KVI_THREAD_EVENT_MESSAGE 200
252
#define KVI_THREAD_EVENT_WARNING 201
253
#define KVI_THREAD_EVENT_ERROR 202
254
#define KVI_THREAD_EVENT_DATA 203
256
// The following is KviThreadDataEvent<KviDataBuffer>
257
#define KVI_THREAD_EVENT_BINARYDATA 300
260
#define KVI_THREAD_USER_EVENT_BASE 1000
262
// #warning "Get rid of the m_szMessage member of KviThreadEvent : eventual data should be passed with a KviThreadDataEvent"
264
// Base class for all thread events
265
class KVILIB_API KviThreadEvent : public QEvent, public KviHeapObject
269
KviThread * m_pSender;
271
KviThreadEvent(int evId,KviThread * sender = 0)
272
: QEvent((QEvent::Type)KVI_THREAD_EVENT) , m_eventId(evId) , m_pSender(sender) {};
273
virtual ~KviThreadEvent(){};
275
// This is the sender of the event
276
// WARNING : this MAY be null , threads CAN send anonymous events
277
KviThread * sender(){ return m_pSender; };
278
int id(){ return m_eventId; };
281
template<class TData> class KviThreadDataEvent : public KviThreadEvent
286
KviThreadDataEvent(int evId,TData * pData = 0,KviThread * sender = 0)
287
: KviThreadEvent(evId,sender){ m_pData = pData; };
288
virtual ~KviThreadDataEvent(){ if(m_pData)delete m_pData; };
290
void setData(TData * d){ if(m_pData)delete m_pData; m_pData = d; };
291
TData * getData(){ TData * aux = m_pData; m_pData = 0; return aux; };
292
TData * data(){ return m_pData; };
295
// A thread that has also an internal event queue
296
// so events can be posted from the master side to the slave one
297
// Reimplementations of this class should periodically check
298
// dequeueEvent() and eventually process the incoming events (and then DELETE it)
300
// KVI_THREAD_EVENT_TERMINATE should be always handled by the reimplementation
301
// and it should always exit (cleanly) when this event is received
304
class KVILIB_API KviSensitiveThread : public KviThread
307
KviSensitiveThread();
308
virtual ~KviSensitiveThread();
310
KviMutex * m_pLocalEventQueueMutex;
311
KviPointerList<KviThreadEvent> * m_pLocalEventQueue;
313
// enqueues an event directed to THIS thread
314
// the event must be allocated with NEW and
315
// will be destroyed on the slave side
316
void enqueueEvent(KviThreadEvent *e);
317
// enqueues a terminate event and waits() for the slave thread
318
// the slave thread MUST handle KVI_THREAD_EVENT_TERMINATE
322
// returns the first event in the local queue
323
// the event MUST BE DELETED after processing
324
KviThreadEvent * dequeueEvent();
327
// =============================================================================================//
328
// This is private stuff...only KviThread and KviApp may use it
329
// and may call only specific functions...don't touch.
331
typedef struct _KviThreadPendingEvent
335
} KviThreadPendingEvent;
337
class KVILIB_API KviThreadManager : public QObject
340
friend class KviThread;
343
// These should be private...but we don't want anyone to complain
344
// Treat as private plz.
348
static void killPendingEvents(QObject * receiver);
350
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
351
QSocketNotifier * m_pSn;
353
KviMutex * m_pMutex; // This class performs only atomic operations
354
KviPointerList<KviThread> * m_pThreadList;
355
int m_iWaitingThreads;
356
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
357
KviPointerList<KviThreadPendingEvent> * m_pEventQueue;
362
// Public to KviThread only
363
void registerSlaveThread(KviThread *t);
364
void unregisterSlaveThread(KviThread *t);
366
void threadEnteredWaitState();
367
void threadLeftWaitState();
369
void postSlaveEvent(QObject *o,QEvent *e);
370
void killPendingEventsByReceiver(QObject * receiver);
371
// Public to KviApp only
372
static void globalInit();
373
static void globalDestroy();
375
void eventsPending(int fd);
379
#endif //!_KVI_THREAD_H_