Imported Upstream version 2.81
[platform/upstream/libbullet.git] / src / BulletMultiThreaded / Win32ThreadSupport.cpp
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
16 #include "Win32ThreadSupport.h"
17
18 #ifdef USE_WIN32_THREADING
19
20 #include <windows.h>
21
22 #include "SpuCollisionTaskProcess.h"
23
24 #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
25
26
27
28 ///The number of threads should be equal to the number of available cores
29 ///@todo: each worker should be linked to a single core, using SetThreadIdealProcessor.
30
31 ///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
32 ///Setup and initialize SPU/CELL/Libspe2
33 Win32ThreadSupport::Win32ThreadSupport(const Win32ThreadConstructionInfo & threadConstructionInfo)
34 {
35         m_maxNumTasks = threadConstructionInfo.m_numThreads;
36         startThreads(threadConstructionInfo);
37 }
38
39 ///cleanup/shutdown Libspe2
40 Win32ThreadSupport::~Win32ThreadSupport()
41 {
42         stopSPU();
43 }
44
45
46
47
48 #include <stdio.h>
49
50 DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
51 {
52
53         Win32ThreadSupport::btSpuStatus* status = (Win32ThreadSupport::btSpuStatus*)lpParam;
54
55         
56         while (1)
57         {
58                 WaitForSingleObject(status->m_eventStartHandle,INFINITE);
59                 
60                 void* userPtr = status->m_userPtr;
61
62                 if (userPtr)
63                 {
64                         btAssert(status->m_status);
65                         status->m_userThreadFunc(userPtr,status->m_lsMemory);
66                         status->m_status = 2;
67                         SetEvent(status->m_eventCompletetHandle);
68                 } else
69                 {
70                         //exit Thread
71                         status->m_status = 3;
72                         printf("Thread with taskId %i with handle %p exiting\n",status->m_taskId, status->m_threadHandle);
73                         SetEvent(status->m_eventCompletetHandle);
74                         break;
75                 }
76                 
77         }
78
79         printf("Thread TERMINATED\n");
80         return 0;
81
82 }
83
84 ///send messages to SPUs
85 void Win32ThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId)
86 {
87         ///     gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc);
88         
89         ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
90         
91
92
93         switch (uiCommand)
94         {
95         case    CMD_GATHER_AND_PROCESS_PAIRLIST:
96                 {
97
98
99 //#define SINGLE_THREADED 1
100 #ifdef SINGLE_THREADED
101
102                         btSpuStatus&    spuStatus = m_activeSpuStatus[0];
103                         spuStatus.m_userPtr=(void*)uiArgument0;
104                         spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory);
105                         HANDLE handle =0;
106 #else
107
108
109                         btSpuStatus&    spuStatus = m_activeSpuStatus[taskId];
110                         btAssert(taskId>=0);
111                         btAssert(int(taskId)<m_activeSpuStatus.size());
112
113                         spuStatus.m_commandId = uiCommand;
114                         spuStatus.m_status = 1;
115                         spuStatus.m_userPtr = (void*)uiArgument0;
116
117                         ///fire event to start new task
118                         SetEvent(spuStatus.m_eventStartHandle);
119
120 #endif //CollisionTask_LocalStoreMemory
121
122                         
123
124                         break;
125                 }
126         default:
127                 {
128                         ///not implemented
129                         btAssert(0);
130                 }
131
132         };
133
134
135 }
136
137
138 ///check for messages from SPUs
139 void Win32ThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
140 {
141         ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
142         
143         ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
144
145
146         btAssert(m_activeSpuStatus.size());
147
148         int last = -1;
149 #ifndef SINGLE_THREADED
150         DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, INFINITE);
151         btAssert(res != WAIT_FAILED);
152         last = res - WAIT_OBJECT_0;
153
154         btSpuStatus& spuStatus = m_activeSpuStatus[last];
155         btAssert(spuStatus.m_threadHandle);
156         btAssert(spuStatus.m_eventCompletetHandle);
157
158         //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
159         btAssert(spuStatus.m_status > 1);
160         spuStatus.m_status = 0;
161
162         ///need to find an active spu
163         btAssert(last>=0);
164
165 #else
166         last=0;
167         btSpuStatus& spuStatus = m_activeSpuStatus[last];
168 #endif //SINGLE_THREADED
169
170         
171
172         *puiArgument0 = spuStatus.m_taskId;
173         *puiArgument1 = spuStatus.m_status;
174
175
176 }
177
178
179 ///check for messages from SPUs
180 bool Win32ThreadSupport::isTaskCompleted(unsigned int *puiArgument0, unsigned int *puiArgument1, int timeOutInMilliseconds)
181 {
182         ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
183         
184         ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
185
186
187         btAssert(m_activeSpuStatus.size());
188
189         int last = -1;
190 #ifndef SINGLE_THREADED
191         DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, timeOutInMilliseconds);
192         
193         if ((res != STATUS_TIMEOUT) && (res != WAIT_FAILED))
194         {
195                 
196                 btAssert(res != WAIT_FAILED);
197                 last = res - WAIT_OBJECT_0;
198
199                 btSpuStatus& spuStatus = m_activeSpuStatus[last];
200                 btAssert(spuStatus.m_threadHandle);
201                 btAssert(spuStatus.m_eventCompletetHandle);
202
203                 //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
204                 btAssert(spuStatus.m_status > 1);
205                 spuStatus.m_status = 0;
206
207                 ///need to find an active spu
208                 btAssert(last>=0);
209
210         #else
211                 last=0;
212                 btSpuStatus& spuStatus = m_activeSpuStatus[last];
213         #endif //SINGLE_THREADED
214
215                 
216
217                 *puiArgument0 = spuStatus.m_taskId;
218                 *puiArgument1 = spuStatus.m_status;
219
220                 return true;
221         } 
222
223         return false;
224 }
225
226
227 void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadConstructionInfo)
228 {
229
230         m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
231         m_completeHandles.resize(threadConstructionInfo.m_numThreads);
232
233         m_maxNumTasks = threadConstructionInfo.m_numThreads;
234
235         for (int i=0;i<threadConstructionInfo.m_numThreads;i++)
236         {
237                 printf("starting thread %d\n",i);
238
239                 btSpuStatus&    spuStatus = m_activeSpuStatus[i];
240
241                 LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL;
242                 SIZE_T dwStackSize=threadConstructionInfo.m_threadStackSize;
243                 LPTHREAD_START_ROUTINE lpStartAddress=&Thread_no_1;
244                 LPVOID lpParameter=&spuStatus;
245                 DWORD dwCreationFlags=0;
246                 LPDWORD lpThreadId=0;
247
248                 spuStatus.m_userPtr=0;
249
250                 sprintf(spuStatus.m_eventStartHandleName,"eventStart%s%d",threadConstructionInfo.m_uniqueName,i);
251                 spuStatus.m_eventStartHandle = CreateEventA (0,false,false,spuStatus.m_eventStartHandleName);
252
253                 sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%s%d",threadConstructionInfo.m_uniqueName,i);
254                 spuStatus.m_eventCompletetHandle = CreateEventA (0,false,false,spuStatus.m_eventCompletetHandleName);
255
256                 m_completeHandles[i] = spuStatus.m_eventCompletetHandle;
257
258                 HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
259                 SetThreadPriority(handle,THREAD_PRIORITY_HIGHEST);
260                 //SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
261
262                 SetThreadAffinityMask(handle, 1<<i);
263
264                 spuStatus.m_taskId = i;
265                 spuStatus.m_commandId = 0;
266                 spuStatus.m_status = 0;
267                 spuStatus.m_threadHandle = handle;
268                 spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
269                 spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
270
271                 printf("started thread %d with threadHandle %p\n",i,handle);
272                 
273         }
274
275 }
276
277 void Win32ThreadSupport::startSPU()
278 {
279 }
280
281
282 ///tell the task scheduler we are done with the SPU tasks
283 void Win32ThreadSupport::stopSPU()
284 {
285         int i;
286         for (i=0;i<m_activeSpuStatus.size();i++)
287         {
288                 btSpuStatus& spuStatus = m_activeSpuStatus[i];
289                 if (spuStatus.m_status>0)
290                 {
291                         WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
292                 }
293                 
294
295                 spuStatus.m_userPtr = 0;
296                 SetEvent(spuStatus.m_eventStartHandle);
297                 WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
298
299                 CloseHandle(spuStatus.m_eventCompletetHandle);
300                 CloseHandle(spuStatus.m_eventStartHandle);
301                 CloseHandle(spuStatus.m_threadHandle);
302
303         }
304
305         m_activeSpuStatus.clear();
306         m_completeHandles.clear();
307
308 }
309
310
311
312 class btWin32Barrier : public btBarrier
313 {
314 private:
315         CRITICAL_SECTION mExternalCriticalSection;
316         CRITICAL_SECTION mLocalCriticalSection;
317         HANDLE mRunEvent,mNotifyEvent;
318         int mCounter,mEnableCounter;
319         int mMaxCount;
320
321 public:
322         btWin32Barrier()
323         {
324                 mCounter = 0;
325                 mMaxCount = 1;
326                 mEnableCounter = 0;
327                 InitializeCriticalSection(&mExternalCriticalSection);
328                 InitializeCriticalSection(&mLocalCriticalSection);
329                 mRunEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
330                 mNotifyEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
331         }
332
333         virtual ~btWin32Barrier()
334         {
335                 DeleteCriticalSection(&mExternalCriticalSection);
336                 DeleteCriticalSection(&mLocalCriticalSection);
337                 CloseHandle(mRunEvent);
338                 CloseHandle(mNotifyEvent);
339         }
340
341         void sync()
342         {
343                 int eventId;
344
345                 EnterCriticalSection(&mExternalCriticalSection);
346
347                 //PFX_PRINTF("enter taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
348
349                 if(mEnableCounter > 0) {
350                         ResetEvent(mNotifyEvent);
351                         LeaveCriticalSection(&mExternalCriticalSection);
352                         WaitForSingleObject(mNotifyEvent,INFINITE); 
353                         EnterCriticalSection(&mExternalCriticalSection);
354                 }
355
356                 eventId = mCounter;
357                 mCounter++;
358
359                 if(eventId == mMaxCount-1) {
360                         SetEvent(mRunEvent);
361
362                         mEnableCounter = mCounter-1;
363                         mCounter = 0;
364                 }
365                 else {
366                         ResetEvent(mRunEvent);
367                         LeaveCriticalSection(&mExternalCriticalSection);
368                         WaitForSingleObject(mRunEvent,INFINITE); 
369                         EnterCriticalSection(&mExternalCriticalSection);
370                         mEnableCounter--;
371                 }
372
373                 if(mEnableCounter == 0) {
374                         SetEvent(mNotifyEvent);
375                 }
376
377                 //PFX_PRINTF("leave taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
378
379                 LeaveCriticalSection(&mExternalCriticalSection);
380         }
381
382         virtual void setMaxCount(int n) {mMaxCount = n;}
383         virtual int  getMaxCount() {return mMaxCount;}
384 };
385
386 class btWin32CriticalSection : public btCriticalSection
387 {
388 private:
389         CRITICAL_SECTION mCriticalSection;
390
391 public:
392         btWin32CriticalSection()
393         {
394                 InitializeCriticalSection(&mCriticalSection);
395         }
396
397         ~btWin32CriticalSection()
398         {
399                 DeleteCriticalSection(&mCriticalSection);
400         }
401
402         unsigned int getSharedParam(int i)
403         {
404                 btAssert(i>=0&&i<31);
405                 return mCommonBuff[i+1];
406         }
407
408         void setSharedParam(int i,unsigned int p)
409         {
410                 btAssert(i>=0&&i<31);
411                 mCommonBuff[i+1] = p;
412         }
413
414         void lock()
415         {
416                 EnterCriticalSection(&mCriticalSection);
417                 mCommonBuff[0] = 1;
418         }
419
420         void unlock()
421         {
422                 mCommonBuff[0] = 0;
423                 LeaveCriticalSection(&mCriticalSection);
424         }
425 };
426
427
428 btBarrier*      Win32ThreadSupport::createBarrier()
429 {
430         unsigned char* mem = (unsigned char*)btAlignedAlloc(sizeof(btWin32Barrier),16);
431         btWin32Barrier* barrier = new(mem) btWin32Barrier();
432         barrier->setMaxCount(getNumTasks());
433         return barrier;
434 }
435
436 btCriticalSection* Win32ThreadSupport::createCriticalSection()
437 {
438         unsigned char* mem = (unsigned char*) btAlignedAlloc(sizeof(btWin32CriticalSection),16);
439         btWin32CriticalSection* cs = new(mem) btWin32CriticalSection();
440         return cs;
441 }
442
443 void Win32ThreadSupport::deleteBarrier(btBarrier* barrier)
444 {
445         barrier->~btBarrier();
446         btAlignedFree(barrier);
447 }
448
449 void Win32ThreadSupport::deleteCriticalSection(btCriticalSection* criticalSection)
450 {
451         criticalSection->~btCriticalSection();
452         btAlignedFree(criticalSection);
453 }
454
455
456 #endif //USE_WIN32_THREADING
457
458