~smspillaz/nux/nux.fix_1036521

« back to all changes in this revision

Viewing changes to NuxCore/NThread.h

  • Committer: Neil Jagdish Patel
  • Date: 2010-09-01 19:25:37 UTC
  • Revision ID: neil.patel@canonical.com-20100901192537-mfz7rm6q262pewg6
Import and build NuxCore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef NTHREAD_H
 
2
#define NTHREAD_H
 
3
 
 
4
#include "NObjectType.h"
 
5
 
 
6
NAMESPACE_BEGIN
 
7
 
 
8
class NThreadSafeCounter
 
9
{   
 
10
public:
 
11
    NThreadSafeCounter() {m_Counter = 0;}
 
12
    NThreadSafeCounter(t_integer i) {m_Counter = i;}
 
13
    t_integer Increment();
 
14
    t_integer Decrement();
 
15
    t_integer Set(t_integer i);
 
16
    t_integer GetValue() const;
 
17
    t_integer operator ++ ();
 
18
    t_integer operator -- ();
 
19
    t_bool operator == (t_integer i);
 
20
private:
 
21
    t_integer m_Counter;
 
22
};
 
23
 
 
24
class NCriticalSection
 
25
{
 
26
public:
 
27
    //! Initialize critical section.
 
28
    /*!
 
29
        Initialize critical section.
 
30
    */
 
31
    NCriticalSection() { InitializeCriticalSection(&m_lock); }
 
32
 
 
33
    //! Destroy critical section.
 
34
    /*!
 
35
        Destroy critical section.
 
36
    */
 
37
    ~NCriticalSection() { DeleteCriticalSection(&m_lock); }
 
38
 
 
39
    //! Enter critical section.
 
40
    /*!
 
41
        Enter critical section. This function is made const so it can be used without restriction.
 
42
        For that matter, m_lock is made mutable.
 
43
    */
 
44
    void Lock() const
 
45
    {
 
46
        EnterCriticalSection(&m_lock);
 
47
    }
 
48
 
 
49
    //! Leave critical section.
 
50
    /*!
 
51
        Leave critical section. This function is made const so it can be used without restriction.
 
52
        For that matter, m_lock is made mutable.
 
53
    */
 
54
    void Unlock() const
 
55
    {
 
56
        LeaveCriticalSection(&m_lock);
 
57
    }
 
58
 
 
59
private:
 
60
    //! Prohibit copy constructor.
 
61
    /*!
 
62
        Prohibit copy constructor.
 
63
    */
 
64
    NCriticalSection(const NCriticalSection&);
 
65
    //! Prohibit assignment operator.
 
66
    /*!
 
67
        Prohibit assignment operator.
 
68
    */
 
69
    NCriticalSection& operator=(const NCriticalSection&);
 
70
 
 
71
    mutable CRITICAL_SECTION m_lock;
 
72
};
 
73
 
 
74
//! Scope Lock class
 
75
/*!
 
76
    Takes a critical section object as parameter of the constructor.
 
77
    The constructor locks the critical section.
 
78
    The destructor unlocks the critical section.
 
79
*/
 
80
class NScopeLock
 
81
{
 
82
public:
 
83
    //! The constructor locks the critical section object.
 
84
    /*!
 
85
        The constructor locks the critical section object.
 
86
        @param  LockObject      Critical section object.
 
87
    */
 
88
    NScopeLock(NCriticalSection* CriticalSectionObject)
 
89
        : m_CriticalSectionObject(CriticalSectionObject)
 
90
    {
 
91
        nuxAssert(m_CriticalSectionObject);
 
92
        m_CriticalSectionObject->Lock();
 
93
    }
 
94
 
 
95
    //! The destructor unlocks the critical section object.
 
96
    /*!
 
97
        The destructor unlocks the critical section object.
 
98
    */
 
99
    ~NScopeLock(void)
 
100
    {
 
101
        nuxAssert(m_CriticalSectionObject);
 
102
        m_CriticalSectionObject->Unlock();
 
103
    }
 
104
 
 
105
private:
 
106
    //! Prohibit default constructor.
 
107
    /*!
 
108
        Prohibit default constructor.
 
109
    */
 
110
    NScopeLock(void);
 
111
 
 
112
    //! Prohibit copy constructor.
 
113
    /*!
 
114
        Prohibit copy constructor.
 
115
    */
 
116
    NScopeLock(const NScopeLock& ScopeLockObject);
 
117
 
 
118
    //! Prohibit assignment operator.
 
119
    /*!
 
120
        Prohibit assignment operator.
 
121
    */
 
122
    NScopeLock& operator=(const NScopeLock& ScopeLockObject) { return *this; }
 
123
 
 
124
    //! Critical section Object.
 
125
    /*!
 
126
        Critical section Object.
 
127
    */
 
128
    NCriticalSection* m_CriticalSectionObject;
 
129
};
 
130
 
 
131
class NThreadLocalStorage
 
132
{
 
133
public:
 
134
    enum
 
135
    {
 
136
        NbTLS = 128,
 
137
        InvalidTLS = 0xFFFFFFFF
 
138
    };
 
139
 
 
140
    typedef void (*TLS_ShutdownCallback)();
 
141
    
 
142
    static BOOL                     m_TLSUsed[NbTLS];
 
143
    static t_u32                     m_TLSIndex[NbTLS];
 
144
    static TLS_ShutdownCallback     m_TLSCallbacks[NbTLS];
 
145
    
 
146
    static void Initialize();
 
147
    static void Shutdown();
 
148
    static BOOL RegisterTLS(t_u32 index, TLS_ShutdownCallback shutdownCallback);
 
149
    static void ThreadInit();
 
150
    static void ThreadShutdown();
 
151
 
 
152
public:
 
153
 
 
154
    template<class T> static inline T GetData(t_u32 index)
 
155
    {
 
156
        nuxAssert(sizeof(T) <= sizeof(size_t));                         
 
157
        nuxAssert(index < NbTLS);
 
158
        nuxAssert(m_TLSUsed[index]);
 
159
 
 
160
        // T and (unsigned long) can be of different sizes
 
161
        // but this limits the use of GetData to classes without copy constructors
 
162
        union
 
163
        {
 
164
            T               t;
 
165
            void*           v;
 
166
        } temp;
 
167
        temp.v = TlsGetValue(m_TLSIndex[index]);
 
168
        return temp.t;
 
169
    }
 
170
 
 
171
    template<class T> static inline void SetData(t_u32 index, T value)
 
172
    {
 
173
        nuxAssert(sizeof(T) <= sizeof(size_t));                         
 
174
        nuxAssert(index < NbTLS);
 
175
        nuxAssert(m_TLSUsed[index]);
 
176
 
 
177
        // T and (unsigned long) can be of different sizes
 
178
        // but this limits the use of GetData to classes without copy constructors
 
179
        union{
 
180
            T               t;
 
181
            void*           v;
 
182
        } temp;
 
183
        temp.t = value;
 
184
        BOOL b = TlsSetValue(m_TLSIndex[index], temp.v);
 
185
        nuxAssertMsg(b, TEXT("[NThreadLocalStorage::SetData] TlsSetValue returned FALSE."));
 
186
    }
 
187
};
 
188
 
 
189
#define inlDeclareThreadLocalStorage(type, index, name) \
 
190
struct          ThreadLocalStorageDef##name { enum Const { Index = index}; };\
 
191
inline          type GetTLS_##name() { return nux::NThreadLocalStorage::GetData<type>(ThreadLocalStorageDef##name::Index); }\
 
192
inline          void SetTLS_##name(type value) { nux::NThreadLocalStorage::SetData<type>(ThreadLocalStorageDef##name::Index, value); }
 
193
 
 
194
#define inlRegisterThreadLocalIndex(index, name, shutdownCallback) \
 
195
    nuxVerifyExpr(index == ThreadLocalStorageDef##name::Index); \
 
196
    nuxVerifyExpr(nux::NThreadLocalStorage::RegisterTLS(index, shutdownCallback)) 
 
197
 
 
198
#define inlGetThreadLocalStorage(name)                  GetTLS_##name()
 
199
#define inlSetThreadLocalStorage(name, value)  SetTLS_##name(value)
 
200
 
 
201
#ifdef POP_CHECK_THREADS
 
202
#define nuxAssertInsideThread(threadtype)                    nuxAssert( inlGetThreadLocalStorage(ThreadType) == threadtype)
 
203
#define nuxAssertInsideThread2(threadtype1, threadtype2) nuxAssert( inlGetThreadLocalStorage(ThreadType) == threadtype1 || popGetThreadLocalData(ThreadType) == threadtype2)
 
204
#define nuxAssertNotInsideThread(threadtype)             nuxAssert( inlGetThreadLocalStorage(ThreadType) != threadtype)
 
205
#else
 
206
#define nuxAssertInsideThread(threadtype)       ((void) 0)
 
207
#define nuxAssertInsideThread2(threadtype1, threadtype2)        ((void) 0)
 
208
#define nuxAssertNotInsideThread(threadtype) ((void) 0)
 
209
#endif
 
210
 
 
211
void SetWin32ThreadName(DWORD dwThreadID, LPCSTR szThreadName);
 
212
 
 
213
 
 
214
typedef enum
 
215
{
 
216
    THREADINIT,
 
217
    THREADRUNNING,
 
218
    THREADSUSPENDED,
 
219
    THREADSTOP,
 
220
    THREAD_START_ERROR,
 
221
    THREAD_STOP_ERROR,
 
222
    THREAD_SUSPEND_ERROR,
 
223
    THREAD_RESUME_ERROR,
 
224
} ThreadState;
 
225
 
 
226
// http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c3793/
 
227
class NThread
 
228
{
 
229
    DECLARE_ROOT_OBJECT_TYPE(NThread);
 
230
public:
 
231
    /*!
 
232
        Info: Default Constructor
 
233
    */
 
234
    NThread();
 
235
 
 
236
    /*!
 
237
        Info: Plug Constructor
 
238
 
 
239
        Use this to migrate/port existing worker threads to objects immediately
 
240
        Although you lose the benefits of ThreadCTOR and ThreadDTOR.
 
241
    */
 
242
    NThread(LPTHREAD_START_ROUTINE lpExternalRoutine);
 
243
 
 
244
    /*!
 
245
        Info: Default Destructor
 
246
 
 
247
        I think it is wise to destroy the thread even if it is running,
 
248
        when the main thread reaches here.
 
249
    */
 
250
    virtual ~NThread();
 
251
 
 
252
    /*!
 
253
        Info: Starts the thread.
 
254
 
 
255
        This function starts the thread pointed by m_pThreadFunc with default attributes
 
256
    */
 
257
    virtual ThreadState Start( void* arg = NULL );
 
258
 
 
259
    /*!
 
260
        Info: Stops the thread.
 
261
 
 
262
        This function stops the current thread. 
 
263
        We can force kill a thread which results in a TerminateThread.
 
264
    */
 
265
    virtual ThreadState Stop ( bool bForceKill = false );
 
266
 
 
267
    ThreadState Suspend();
 
268
    ThreadState Resume();
 
269
    ThreadState ResumeStart();
 
270
    ThreadState ResumeExit();
 
271
 
 
272
    /*!
 
273
        Info: Starts the thread.
 
274
 
 
275
        This function starts the thread pointed by m_pThreadFunc with default attributes
 
276
    */
 
277
    t_u32 GetExitCode() const;
 
278
 
 
279
    /*!
 
280
        Info: Attaches a Thread Function
 
281
 
 
282
        Used primarily for porting but can serve in developing generic thread objects
 
283
    */
 
284
    void Attach( LPTHREAD_START_ROUTINE lpThreadFunc ){
 
285
        m_pThreadFunc = lpThreadFunc;
 
286
    }
 
287
 
 
288
    /*!
 
289
        Info: Detaches the Attached Thread Function
 
290
 
 
291
        Detaches the Attached Thread Function, If any.
 
292
        by resetting the thread function pointer to EntryPoint1
 
293
    */
 
294
    void  Detach( void )
 
295
    {
 
296
        m_pThreadFunc = NThread::EntryPoint; 
 
297
    }
 
298
 
 
299
    HANDLE GetThreadHandle();
 
300
    t_u32 GetThreadId();
 
301
 
 
302
 
 
303
    ThreadState GetThreadState() const;
 
304
    void SetThreadState(ThreadState state);
 
305
 
 
306
    void SetThreadName(const TCHAR* ThreadName);
 
307
    const NString& GetThreadName() const;
 
308
 
 
309
protected:
 
310
    NString m_ThreadName;
 
311
 
 
312
    volatile ThreadState m_ThreadState;
 
313
 
 
314
    /*!
 
315
        Info: DONT override this method.
 
316
        
 
317
        This function is like a standard template. 
 
318
        Override if you are sure of what you are doing.
 
319
        
 
320
        In C++ the entry function of a thread cannot be a normal member function of a class. 
 
321
        However, it can be a static member function of a class. This is what we will use as the entry point.
 
322
        There is a gotcha here though. Static member functions do not have access to the this pointer of a C++ object.
 
323
        They can only access static data. Fortunately, there is way to do it. Thread entry point functions take a void * as
 
324
        a parameter so that the caller can typecast any data and pass in to the thread. We will use this to pass this to
 
325
        the static function. The static function will then typecast the void * and use it to call a non static member function
 
326
    */
 
327
    static DWORD WINAPI EntryPoint(void* pArg);
 
328
 
 
329
    /*!
 
330
        Info: Override this method.
 
331
 
 
332
        This function should contain the body/code of your thread.
 
333
        Notice the signature is similar to that of any worker thread function
 
334
        except for the calling convention.
 
335
    */
 
336
    virtual t_u32 Run(void* /* arg */ )
 
337
    { return m_ThreadCtx.m_dwExitCode; }
 
338
 
 
339
    /*!
 
340
        Info: Constructor-like function. 
 
341
 
 
342
        Will be called by EntryPoint before executing the thread body.
 
343
        Override this function to provide your extra initialization.
 
344
 
 
345
        NOTE: do not confuse it with the classes constructor
 
346
        @return TRUE if the thread can continue running the program. If FALSE is returned, the thread won't execute the main body Run() and will exit without calling ThreadDtor.
 
347
    */
 
348
    virtual bool ThreadCtor(){return true;}
 
349
 
 
350
    /*!
 
351
        Info: Destructor-like function. 
 
352
 
 
353
        Will be called by EntryPoint after executing the thread body.
 
354
        Override this function to provide your extra destruction.
 
355
 
 
356
        NOTE: do not confuse it with the classes constructor
 
357
        @return TRUE if this function executed without problems.
 
358
    */
 
359
    virtual bool ThreadDtor(){return true;}
 
360
 
 
361
private:
 
362
    /*!
 
363
        Info: Thread Context Inner Class
 
364
 
 
365
        Every thread object needs to be associated with a set of values.
 
366
        like UserData Pointer, Handle, Thread ID etc.
 
367
 
 
368
        NOTE: This class can be enhanced to varying functionalities
 
369
        eg.,
 
370
            * Members to hold StackSize
 
371
            * SECURITY_ATTRIBUTES member.
 
372
    */
 
373
    class NThreadContext
 
374
    {
 
375
    public:
 
376
        NThreadContext(){
 
377
            memset(this, 0, sizeof(this));
 
378
        }
 
379
 
 
380
        /*
 
381
        *       Attributes Section
 
382
        */
 
383
    public:
 
384
        HANDLE m_hThread;                                       //      The Thread Handle
 
385
        volatile t_u32  m_dwTID;                                                //      The Thread ID
 
386
        void* m_pUserData;                                              //      The user data pointer
 
387
        void* m_pParent;                                        //      The this pointer of the parent NThread object
 
388
        t_u32  m_dwExitCode;                            //      The Exit Code of the thread
 
389
    };
 
390
 
 
391
    /*!
 
392
        Attributes Section
 
393
    */
 
394
protected:
 
395
    /*!
 
396
        Info: Members of NThread
 
397
    */
 
398
    NThreadContext                      m_ThreadCtx;    //      The Thread Context member
 
399
    LPTHREAD_START_ROUTINE      m_pThreadFunc;  //      The Worker Thread Function Pointer
 
400
};
 
401
 
 
402
//  USAGE:
 
403
//    DWORD WINAPI Threaded(void* lpData);
 
404
//
 
405
//    class CDemoThread : public CThread
 
406
//    {
 
407
//        virtual t_u32 Run( void* /* arg */ )
 
408
//        { 
 
409
//            for(;;)
 
410
//            {
 
411
//                printf("Threaded Object Code \n");
 
412
//                Sleep(1000);
 
413
//            }
 
414
//        }
 
415
//    };
 
416
//
 
417
//    void main( void )
 
418
//    {
 
419
//        CDemoThread dmt;
 
420
//        dmt.Start(NULL);
 
421
//        SleepEx(15 * 1000, FALSE);
 
422
//        dmt.Stop(true);
 
423
//
 
424
//        //    A Sample Code for porting existent code of Threaded function
 
425
//        CThread t1(Threaded), t2;
 
426
//        t2.Attach(Threaded);
 
427
//        t1.Start();
 
428
//        t2.Start();
 
429
//        SleepEx(15 * 1000, FALSE);
 
430
//        t2.Stop();
 
431
//        t1.Stop();
 
432
//    }
 
433
//
 
434
//    DWORD WINAPI Threaded( void* /* lpData */ )
 
435
//    {
 
436
//        for(;;)
 
437
//        {
 
438
//            printf("worker threaded code");
 
439
//            Sleep(1000);
 
440
//        }
 
441
//    }
 
442
 
 
443
NAMESPACE_END
 
444
 
 
445
#endif // NTHREAD_H
 
446