~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvilib/system/KviThread.h

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

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