~hikiko/nux/arb-srgba-shader

« back to all changes in this revision

Viewing changes to NuxCore/NThread.cpp

  • 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
#include "NKernel.h"
 
2
#include "NString.h"
 
3
#include "NThread.h"
 
4
 
 
5
 
 
6
NAMESPACE_BEGIN
 
7
 
 
8
#ifdef _WIN64
 
9
    #define INL_ATOMOP_ITERLOCKED_INCREMENT      InterlockedIncrement64
 
10
    #define INL_ATOMOP_ITERLOCKED_DECREMENT      InterlockedDecrement64
 
11
    #define INL_ATOMOP_ITERLOCKED_EXCHANGED      InterlockedExchange64
 
12
    #define INL_ATOMOP_ITERLOCKED_VALUE
 
13
#elif _WIN32
 
14
    #define INL_ATOMOP_ITERLOCKED_INCREMENT      InterlockedIncrement
 
15
    #define INL_ATOMOP_ITERLOCKED_DECREMENT      InterlockedDecrement
 
16
    #define INL_ATOMOP_ITERLOCKED_EXCHANGED      InterlockedExchange
 
17
    #define INL_ATOMOP_ITERLOCKED_VALUE
 
18
#endif
 
19
 
 
20
t_integer NThreadSafeCounter::Increment()
 
21
{
 
22
    return INL_ATOMOP_ITERLOCKED_INCREMENT( &m_Counter );
 
23
}
 
24
t_integer NThreadSafeCounter::Decrement()
 
25
{
 
26
    return INL_ATOMOP_ITERLOCKED_DECREMENT( &m_Counter );
 
27
}
 
28
t_integer NThreadSafeCounter::Set(t_integer i)
 
29
{
 
30
    return INL_ATOMOP_ITERLOCKED_EXCHANGED( &m_Counter, i );
 
31
}
 
32
 
 
33
t_integer NThreadSafeCounter::GetValue() const
 
34
{
 
35
    return m_Counter;
 
36
}
 
37
 
 
38
t_integer NThreadSafeCounter::operator ++ ()
 
39
{
 
40
    return Increment();
 
41
}
 
42
 
 
43
t_integer NThreadSafeCounter::operator -- ()
 
44
{
 
45
    return Decrement();
 
46
}
 
47
 
 
48
t_bool NThreadSafeCounter::operator == (t_integer i)
 
49
{
 
50
    return (m_Counter == i);
 
51
}
 
52
 
 
53
t_u32  NThreadLocalStorage::m_TLSIndex[NThreadLocalStorage::NbTLS];    
 
54
BOOL NThreadLocalStorage::m_TLSUsed[NThreadLocalStorage::NbTLS];
 
55
NThreadLocalStorage::TLS_ShutdownCallback  NThreadLocalStorage::m_TLSCallbacks[NThreadLocalStorage::NbTLS];
 
56
 
 
57
 
 
58
// http://msdn2.microsoft.com/en-us/library/xcb2z8hs(VS.80).aspx
 
59
//
 
60
// Usage: SetWin32ThreadName (-1, "MainThread");
 
61
//
 
62
#define MS_VC_EXCEPTION 0x406D1388
 
63
 
 
64
typedef struct tagTHREADNAME_INFO
 
65
{
 
66
    DWORD dwType; // Must be 0x1000.
 
67
    LPCSTR szName; // Pointer to name (in user addr space).
 
68
    DWORD dwThreadID; // Thread ID (-1=caller thread).
 
69
    DWORD dwFlags; // Reserved for future use, must be zero.
 
70
} THREADNAME_INFO;
 
71
 
 
72
void SetWin32ThreadName(DWORD dwThreadID, LPCSTR szThreadName)
 
73
{
 
74
    THREADNAME_INFO info;
 
75
    info.dwType = 0x1000;
 
76
    info.szName = szThreadName;
 
77
    info.dwThreadID = dwThreadID;
 
78
    info.dwFlags = 0;
 
79
 
 
80
    __try
 
81
    {
 
82
        RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
 
83
    }
 
84
    __except(EXCEPTION_CONTINUE_EXECUTION)
 
85
    {
 
86
    }
 
87
}
 
88
 
 
89
BOOL NThreadLocalStorage::RegisterTLS(t_u32 index, NThreadLocalStorage::TLS_ShutdownCallback shutdownCallback)
 
90
{
 
91
    nuxAssert(!m_TLSUsed[index]);
 
92
 
 
93
    if (!m_TLSUsed[index])
 
94
    {
 
95
        m_TLSIndex[index] = TlsAlloc();
 
96
        if(m_TLSIndex[index] == TLS_OUT_OF_INDEXES)
 
97
        {
 
98
            nuxAssertMsg(0, TEXT("[NThreadLocalStorage::RegisterTLS] Out of TLS index."));
 
99
        }
 
100
        m_TLSUsed[index]  = TRUE;       
 
101
        m_TLSCallbacks[index] =  shutdownCallback;
 
102
        return TRUE;
 
103
    }
 
104
    else
 
105
    {
 
106
        return FALSE;
 
107
    }
 
108
}
 
109
 
 
110
void NThreadLocalStorage::Initialize()
 
111
{
 
112
    Memset(m_TLSUsed, 0, sizeof(m_TLSUsed));
 
113
 
 
114
    for (t_u32 i = 0; i < NThreadLocalStorage::NbTLS; i++)
 
115
    {
 
116
        // Fill the array with invalid values
 
117
        m_TLSIndex[i] = NThreadLocalStorage::InvalidTLS; // invalid index
 
118
    }
 
119
}
 
120
 
 
121
void NThreadLocalStorage::Shutdown()
 
122
{
 
123
    ThreadShutdown();
 
124
}
 
125
 
 
126
void NThreadLocalStorage::ThreadInit()
 
127
{
 
128
}
 
129
 
 
130
void NThreadLocalStorage::ThreadShutdown()
 
131
{
 
132
    TLS_ShutdownCallback *callback = m_TLSCallbacks;
 
133
    for (t_u32 i = 0; i < NThreadLocalStorage::NbTLS; ++i, ++callback)
 
134
    {
 
135
        if (*callback)
 
136
        {
 
137
            (**callback)();
 
138
        }
 
139
    }
 
140
}
 
141
 
 
142
IMPLEMENT_ROOT_OBJECT_TYPE(NThread);
 
143
 
 
144
NThread::NThread()
 
145
:   m_ThreadState(THREADINIT)
 
146
 
147
    m_pThreadFunc = NThread::EntryPoint; // Can call Detach() also.
 
148
}
 
149
 
 
150
NThread::NThread(LPTHREAD_START_ROUTINE lpExternalRoutine)
 
151
{
 
152
    Attach(lpExternalRoutine);
 
153
}
 
154
 
 
155
NThread::~NThread()
 
156
{
 
157
    CloseHandle(m_ThreadCtx.m_hThread);
 
158
}
 
159
 
 
160
ThreadState NThread::Start( void* arg )
 
161
{
 
162
    if ( m_ThreadCtx.m_hThread == 0)
 
163
    {
 
164
        m_ThreadCtx.m_pUserData = arg;
 
165
        m_ThreadCtx.m_hThread = CreateThread(NULL,
 
166
            0,
 
167
            m_pThreadFunc,
 
168
            this,
 
169
            0 /*CREATE_SUSPENDED*/,
 
170
            (LPDWORD)&m_ThreadCtx.m_dwTID);
 
171
 
 
172
        if(m_ThreadCtx.m_hThread != 0)
 
173
        {
 
174
            //ResumeStart();
 
175
            m_ThreadState = THREADINIT;
 
176
            m_ThreadCtx.m_dwExitCode = (t_u32)-1;
 
177
            return m_ThreadState;
 
178
        }
 
179
        else
 
180
        {
 
181
            nuxDebugMsg(TEXT("[NThread::Start] Cannot start thread: %s"), inlGetSystemErrorMessage());
 
182
            m_ThreadState = THREAD_START_ERROR;
 
183
            return m_ThreadState;
 
184
        }
 
185
        
 
186
    }
 
187
    return m_ThreadState;
 
188
}
 
189
 
 
190
ThreadState NThread::Stop( bool bForceKill )
 
191
{
 
192
// From MSDN
 
193
//    TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.
 
194
//        TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
 
195
//    If the target thread owns a critical section, the critical section will not be released. 
 
196
//        If the target thread is allocating memory from the heap, the heap lock will not be released. 
 
197
//        If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. 
 
198
//        If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL. 
 
199
 
 
200
    // Attention: Calling Stop from another thread is not going to free the stack of this thread. 
 
201
    // the stack is freed only if the thread exits by itself.
 
202
    if ( m_ThreadCtx.m_hThread )
 
203
    {
 
204
        GetExitCodeThread(m_ThreadCtx.m_hThread, (LPDWORD)&m_ThreadCtx.m_dwExitCode);
 
205
 
 
206
        if ( m_ThreadCtx.m_dwExitCode == STILL_ACTIVE && bForceKill )
 
207
        {
 
208
            TerminateThread(m_ThreadCtx.m_hThread, t_u32(-1));
 
209
            CloseHandle(m_ThreadCtx.m_hThread);
 
210
        }
 
211
        m_ThreadCtx.m_hThread = NULL;
 
212
    }
 
213
    m_ThreadState = THREADSTOP;
 
214
    return m_ThreadState;
 
215
}
 
216
 
 
217
ThreadState NThread::Suspend()
 
218
{
 
219
    unsigned int ret = SuspendThread(m_ThreadCtx.m_hThread);
 
220
    if(ret == 0xFFFFFFFF)
 
221
    {
 
222
        nuxDebugMsg(TEXT("[NThread::Suspend] Cannot suspend thread: %s"), inlGetSystemErrorMessage());
 
223
        return THREAD_SUSPEND_ERROR;
 
224
    }
 
225
    m_ThreadState = THREADSUSPENDED;
 
226
    return m_ThreadState;
 
227
}
 
228
 
 
229
ThreadState NThread::Resume()
 
230
{
 
231
    unsigned int ret = ResumeThread(m_ThreadCtx.m_hThread);
 
232
    if(ret == 0xFFFFFFFF)
 
233
    {
 
234
        nuxDebugMsg(TEXT("[NThread::Suspend] Cannot resume thread: %s"), inlGetSystemErrorMessage());
 
235
        return THREAD_RESUME_ERROR;
 
236
    }
 
237
    if(ret == 1)
 
238
    {
 
239
        // If the return value is 1, the specified thread was suspended but was restarted.
 
240
        m_ThreadState = THREADRUNNING;
 
241
    }
 
242
    if(ret > 1)
 
243
    {
 
244
        // If the return value is greater than 1, the specified thread is still suspended.
 
245
        m_ThreadState = THREADSUSPENDED;
 
246
    }
 
247
    return m_ThreadState;
 
248
}
 
249
 
 
250
// go from suspended to thread start
 
251
ThreadState NThread::ResumeStart()
 
252
{
 
253
    m_ThreadState = THREADINIT;
 
254
    unsigned int ret = ResumeThread(m_ThreadCtx.m_hThread);
 
255
    if(ret == 0xFFFFFFFF)
 
256
    {
 
257
        nuxDebugMsg(TEXT("[NThread::ResumeExit] Cannot resume thread: %s"), inlGetSystemErrorMessage());
 
258
        return THREAD_RESUME_ERROR;
 
259
    }
 
260
    if(ret == 1)
 
261
    {
 
262
        // If the return value is 1, the specified thread was suspended but was restarted.
 
263
        m_ThreadState = THREADINIT;
 
264
    }
 
265
    if(ret > 1)
 
266
    {
 
267
        nuxAssert(0); // should not happen
 
268
        // If the return value is greater than 1, the specified thread is still suspended.
 
269
        m_ThreadState = THREADINIT;
 
270
    }
 
271
    return m_ThreadState;
 
272
}
 
273
 
 
274
// go from suspended to thread exit
 
275
ThreadState NThread::ResumeExit()
 
276
{
 
277
    m_ThreadState = THREADSTOP;
 
278
    unsigned int ret = ResumeThread(m_ThreadCtx.m_hThread);
 
279
    if(ret == 0xFFFFFFFF)
 
280
    {
 
281
        nuxDebugMsg(TEXT("[NThread::ResumeExit] Cannot resume thread: %s"), inlGetSystemErrorMessage());
 
282
        return THREAD_RESUME_ERROR;
 
283
    }
 
284
    if(ret == 1)
 
285
    {
 
286
        // If the return value is 1, the specified thread was suspended but was restarted.
 
287
        m_ThreadState = THREADSTOP;
 
288
    }
 
289
    if(ret > 1)
 
290
    {
 
291
        nuxAssert(0); // should not happen
 
292
        // If the return value is greater than 1, the specified thread is still suspended.
 
293
        m_ThreadState = THREADSTOP;
 
294
    }
 
295
    return m_ThreadState;
 
296
}
 
297
 
 
298
DWORD WINAPI NThread::EntryPoint(void* pArg)
 
299
{
 
300
    NThread *pParent = reinterpret_cast<NThread*>(pArg);
 
301
    if(pParent == 0)
 
302
    {
 
303
        nuxDebugMsg(TEXT("[NThread::EntryPoint] Invalid pointer. The thread will exit."));
 
304
        return 0;
 
305
    }
 
306
 
 
307
    if(!pParent->ThreadCtor())
 
308
    {
 
309
        // return another message saying the thread could not execute due to error in ThreadCtor;
 
310
        return 0;
 
311
    }
 
312
 
 
313
    pParent->Run( pParent->m_ThreadCtx.m_pUserData );
 
314
    pParent->ThreadDtor();
 
315
 
 
316
    return 0;
 
317
}
 
318
 
 
319
t_u32 NThread::GetExitCode() const 
 
320
 
321
    if ( m_ThreadCtx.m_hThread )
 
322
        GetExitCodeThread(m_ThreadCtx.m_hThread, (LPDWORD)&m_ThreadCtx.m_dwExitCode);
 
323
    return m_ThreadCtx.m_dwExitCode;
 
324
}
 
325
 
 
326
HANDLE NThread::GetThreadHandle()
 
327
{
 
328
    return m_ThreadCtx.m_hThread;
 
329
}
 
330
 
 
331
t_u32 NThread::GetThreadId()
 
332
{
 
333
    return (t_u32)m_ThreadCtx.m_dwTID;
 
334
}
 
335
 
 
336
ThreadState NThread::GetThreadState() const
 
337
{
 
338
    return m_ThreadState;
 
339
}
 
340
 
 
341
void NThread::SetThreadState(ThreadState state)
 
342
{
 
343
    m_ThreadState = state;
 
344
}
 
345
 
 
346
void NThread::SetThreadName(const TCHAR* ThreadName)
 
347
{
 
348
    SetWin32ThreadName(GetThreadId(), TCHAR_TO_ANSI(ThreadName));
 
349
    m_ThreadName = ThreadName;
 
350
}
 
351
 
 
352
const NString& NThread::GetThreadName() const
 
353
{
 
354
    return m_ThreadName;
 
355
}
 
356
 
 
357
NAMESPACE_END
 
358