2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com
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:
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.
16 #include "Win32ThreadSupport.h"
18 #ifdef USE_WIN32_THREADING
22 #include "SpuCollisionTaskProcess.h"
24 #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
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.
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)
35 m_maxNumTasks = threadConstructionInfo.m_numThreads;
36 startThreads(threadConstructionInfo);
39 ///cleanup/shutdown Libspe2
40 Win32ThreadSupport::~Win32ThreadSupport()
50 DWORD WINAPI Thread_no_1( LPVOID lpParam )
53 Win32ThreadSupport::btSpuStatus* status = (Win32ThreadSupport::btSpuStatus*)lpParam;
58 WaitForSingleObject(status->m_eventStartHandle,INFINITE);
60 void* userPtr = status->m_userPtr;
64 btAssert(status->m_status);
65 status->m_userThreadFunc(userPtr,status->m_lsMemory);
67 SetEvent(status->m_eventCompletetHandle);
72 printf("Thread with taskId %i with handle %p exiting\n",status->m_taskId, status->m_threadHandle);
73 SetEvent(status->m_eventCompletetHandle);
79 printf("Thread TERMINATED\n");
84 ///send messages to SPUs
85 void Win32ThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId)
87 /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc);
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
95 case CMD_GATHER_AND_PROCESS_PAIRLIST:
99 //#define SINGLE_THREADED 1
100 #ifdef SINGLE_THREADED
102 btSpuStatus& spuStatus = m_activeSpuStatus[0];
103 spuStatus.m_userPtr=(void*)uiArgument0;
104 spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory);
109 btSpuStatus& spuStatus = m_activeSpuStatus[taskId];
111 btAssert(int(taskId)<m_activeSpuStatus.size());
113 spuStatus.m_commandId = uiCommand;
114 spuStatus.m_status = 1;
115 spuStatus.m_userPtr = (void*)uiArgument0;
117 ///fire event to start new task
118 SetEvent(spuStatus.m_eventStartHandle);
120 #endif //CollisionTask_LocalStoreMemory
138 ///check for messages from SPUs
139 void Win32ThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
141 ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
143 ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
146 btAssert(m_activeSpuStatus.size());
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;
154 btSpuStatus& spuStatus = m_activeSpuStatus[last];
155 btAssert(spuStatus.m_threadHandle);
156 btAssert(spuStatus.m_eventCompletetHandle);
158 //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
159 btAssert(spuStatus.m_status > 1);
160 spuStatus.m_status = 0;
162 ///need to find an active spu
167 btSpuStatus& spuStatus = m_activeSpuStatus[last];
168 #endif //SINGLE_THREADED
172 *puiArgument0 = spuStatus.m_taskId;
173 *puiArgument1 = spuStatus.m_status;
179 ///check for messages from SPUs
180 bool Win32ThreadSupport::isTaskCompleted(unsigned int *puiArgument0, unsigned int *puiArgument1, int timeOutInMilliseconds)
182 ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
184 ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
187 btAssert(m_activeSpuStatus.size());
190 #ifndef SINGLE_THREADED
191 DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, timeOutInMilliseconds);
193 if ((res != STATUS_TIMEOUT) && (res != WAIT_FAILED))
196 btAssert(res != WAIT_FAILED);
197 last = res - WAIT_OBJECT_0;
199 btSpuStatus& spuStatus = m_activeSpuStatus[last];
200 btAssert(spuStatus.m_threadHandle);
201 btAssert(spuStatus.m_eventCompletetHandle);
203 //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
204 btAssert(spuStatus.m_status > 1);
205 spuStatus.m_status = 0;
207 ///need to find an active spu
212 btSpuStatus& spuStatus = m_activeSpuStatus[last];
213 #endif //SINGLE_THREADED
217 *puiArgument0 = spuStatus.m_taskId;
218 *puiArgument1 = spuStatus.m_status;
227 void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadConstructionInfo)
230 m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
231 m_completeHandles.resize(threadConstructionInfo.m_numThreads);
233 m_maxNumTasks = threadConstructionInfo.m_numThreads;
235 for (int i=0;i<threadConstructionInfo.m_numThreads;i++)
237 printf("starting thread %d\n",i);
239 btSpuStatus& spuStatus = m_activeSpuStatus[i];
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;
248 spuStatus.m_userPtr=0;
250 sprintf(spuStatus.m_eventStartHandleName,"eventStart%s%d",threadConstructionInfo.m_uniqueName,i);
251 spuStatus.m_eventStartHandle = CreateEventA (0,false,false,spuStatus.m_eventStartHandleName);
253 sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%s%d",threadConstructionInfo.m_uniqueName,i);
254 spuStatus.m_eventCompletetHandle = CreateEventA (0,false,false,spuStatus.m_eventCompletetHandleName);
256 m_completeHandles[i] = spuStatus.m_eventCompletetHandle;
258 HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
259 SetThreadPriority(handle,THREAD_PRIORITY_HIGHEST);
260 //SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
262 SetThreadAffinityMask(handle, 1<<i);
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;
271 printf("started thread %d with threadHandle %p\n",i,handle);
277 void Win32ThreadSupport::startSPU()
282 ///tell the task scheduler we are done with the SPU tasks
283 void Win32ThreadSupport::stopSPU()
286 for (i=0;i<m_activeSpuStatus.size();i++)
288 btSpuStatus& spuStatus = m_activeSpuStatus[i];
289 if (spuStatus.m_status>0)
291 WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
295 spuStatus.m_userPtr = 0;
296 SetEvent(spuStatus.m_eventStartHandle);
297 WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
299 CloseHandle(spuStatus.m_eventCompletetHandle);
300 CloseHandle(spuStatus.m_eventStartHandle);
301 CloseHandle(spuStatus.m_threadHandle);
305 m_activeSpuStatus.clear();
306 m_completeHandles.clear();
312 class btWin32Barrier : public btBarrier
315 CRITICAL_SECTION mExternalCriticalSection;
316 CRITICAL_SECTION mLocalCriticalSection;
317 HANDLE mRunEvent,mNotifyEvent;
318 int mCounter,mEnableCounter;
327 InitializeCriticalSection(&mExternalCriticalSection);
328 InitializeCriticalSection(&mLocalCriticalSection);
329 mRunEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
330 mNotifyEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
333 virtual ~btWin32Barrier()
335 DeleteCriticalSection(&mExternalCriticalSection);
336 DeleteCriticalSection(&mLocalCriticalSection);
337 CloseHandle(mRunEvent);
338 CloseHandle(mNotifyEvent);
345 EnterCriticalSection(&mExternalCriticalSection);
347 //PFX_PRINTF("enter taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
349 if(mEnableCounter > 0) {
350 ResetEvent(mNotifyEvent);
351 LeaveCriticalSection(&mExternalCriticalSection);
352 WaitForSingleObject(mNotifyEvent,INFINITE);
353 EnterCriticalSection(&mExternalCriticalSection);
359 if(eventId == mMaxCount-1) {
362 mEnableCounter = mCounter-1;
366 ResetEvent(mRunEvent);
367 LeaveCriticalSection(&mExternalCriticalSection);
368 WaitForSingleObject(mRunEvent,INFINITE);
369 EnterCriticalSection(&mExternalCriticalSection);
373 if(mEnableCounter == 0) {
374 SetEvent(mNotifyEvent);
377 //PFX_PRINTF("leave taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
379 LeaveCriticalSection(&mExternalCriticalSection);
382 virtual void setMaxCount(int n) {mMaxCount = n;}
383 virtual int getMaxCount() {return mMaxCount;}
386 class btWin32CriticalSection : public btCriticalSection
389 CRITICAL_SECTION mCriticalSection;
392 btWin32CriticalSection()
394 InitializeCriticalSection(&mCriticalSection);
397 ~btWin32CriticalSection()
399 DeleteCriticalSection(&mCriticalSection);
402 unsigned int getSharedParam(int i)
404 btAssert(i>=0&&i<31);
405 return mCommonBuff[i+1];
408 void setSharedParam(int i,unsigned int p)
410 btAssert(i>=0&&i<31);
411 mCommonBuff[i+1] = p;
416 EnterCriticalSection(&mCriticalSection);
423 LeaveCriticalSection(&mCriticalSection);
428 btBarrier* Win32ThreadSupport::createBarrier()
430 unsigned char* mem = (unsigned char*)btAlignedAlloc(sizeof(btWin32Barrier),16);
431 btWin32Barrier* barrier = new(mem) btWin32Barrier();
432 barrier->setMaxCount(getNumTasks());
436 btCriticalSection* Win32ThreadSupport::createCriticalSection()
438 unsigned char* mem = (unsigned char*) btAlignedAlloc(sizeof(btWin32CriticalSection),16);
439 btWin32CriticalSection* cs = new(mem) btWin32CriticalSection();
443 void Win32ThreadSupport::deleteBarrier(btBarrier* barrier)
445 barrier->~btBarrier();
446 btAlignedFree(barrier);
449 void Win32ThreadSupport::deleteCriticalSection(btCriticalSection* criticalSection)
451 criticalSection->~btCriticalSection();
452 btAlignedFree(criticalSection);
456 #endif //USE_WIN32_THREADING