Win32ThreadSupport.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #include "Win32ThreadSupport.h"
00017 
00018 #ifdef USE_WIN32_THREADING
00019 
00020 #include <windows.h>
00021 
00022 #include "SpuCollisionTaskProcess.h"
00023 
00024 #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
00025 
00026 
00027 
00030 
00033 Win32ThreadSupport::Win32ThreadSupport(const Win32ThreadConstructionInfo & threadConstructionInfo)
00034 {
00035         m_maxNumTasks = threadConstructionInfo.m_numThreads;
00036         startThreads(threadConstructionInfo);
00037 }
00038 
00040 Win32ThreadSupport::~Win32ThreadSupport()
00041 {
00042         stopSPU();
00043 }
00044 
00045 
00046 
00047 
00048 #include <stdio.h>
00049 
00050 DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
00051 {
00052 
00053         Win32ThreadSupport::btSpuStatus* status = (Win32ThreadSupport::btSpuStatus*)lpParam;
00054 
00055         
00056         while (1)
00057         {
00058                 WaitForSingleObject(status->m_eventStartHandle,INFINITE);
00059                 
00060                 void* userPtr = status->m_userPtr;
00061 
00062                 if (userPtr)
00063                 {
00064                         btAssert(status->m_status);
00065                         status->m_userThreadFunc(userPtr,status->m_lsMemory);
00066                         status->m_status = 2;
00067                         SetEvent(status->m_eventCompletetHandle);
00068                 } else
00069                 {
00070                         //exit Thread
00071                         status->m_status = 3;
00072                         printf("Thread with taskId %i with handle %p exiting\n",status->m_taskId, status->m_threadHandle);
00073                         SetEvent(status->m_eventCompletetHandle);
00074                         break;
00075                 }
00076                 
00077         }
00078 
00079         printf("Thread TERMINATED\n");
00080         return 0;
00081 
00082 }
00083 
00085 void Win32ThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId)
00086 {
00088         
00090         
00091 
00092 
00093         switch (uiCommand)
00094         {
00095         case    CMD_GATHER_AND_PROCESS_PAIRLIST:
00096                 {
00097 
00098 
00099 //#define SINGLE_THREADED 1
00100 #ifdef SINGLE_THREADED
00101 
00102                         btSpuStatus&    spuStatus = m_activeSpuStatus[0];
00103                         spuStatus.m_userPtr=(void*)uiArgument0;
00104                         spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory);
00105                         HANDLE handle =0;
00106 #else
00107 
00108 
00109                         btSpuStatus&    spuStatus = m_activeSpuStatus[taskId];
00110                         btAssert(taskId>=0);
00111                         btAssert(int(taskId)<m_activeSpuStatus.size());
00112 
00113                         spuStatus.m_commandId = uiCommand;
00114                         spuStatus.m_status = 1;
00115                         spuStatus.m_userPtr = (void*)uiArgument0;
00116 
00118                         SetEvent(spuStatus.m_eventStartHandle);
00119 
00120 #endif //CollisionTask_LocalStoreMemory
00121 
00122                         
00123 
00124                         break;
00125                 }
00126         default:
00127                 {
00129                         btAssert(0);
00130                 }
00131 
00132         };
00133 
00134 
00135 }
00136 
00137 
00139 void Win32ThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
00140 {
00142         
00144 
00145 
00146         btAssert(m_activeSpuStatus.size());
00147 
00148         int last = -1;
00149 #ifndef SINGLE_THREADED
00150         DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, INFINITE);
00151         btAssert(res != WAIT_FAILED);
00152         last = res - WAIT_OBJECT_0;
00153 
00154         btSpuStatus& spuStatus = m_activeSpuStatus[last];
00155         btAssert(spuStatus.m_threadHandle);
00156         btAssert(spuStatus.m_eventCompletetHandle);
00157 
00158         //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
00159         btAssert(spuStatus.m_status > 1);
00160         spuStatus.m_status = 0;
00161 
00163         btAssert(last>=0);
00164 
00165 #else
00166         last=0;
00167         btSpuStatus& spuStatus = m_activeSpuStatus[last];
00168 #endif //SINGLE_THREADED
00169 
00170         
00171 
00172         *puiArgument0 = spuStatus.m_taskId;
00173         *puiArgument1 = spuStatus.m_status;
00174 
00175 
00176 }
00177 
00178 
00180 bool Win32ThreadSupport::isTaskCompleted(unsigned int *puiArgument0, unsigned int *puiArgument1, int timeOutInMilliseconds)
00181 {
00183         
00185 
00186 
00187         btAssert(m_activeSpuStatus.size());
00188 
00189         int last = -1;
00190 #ifndef SINGLE_THREADED
00191         DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, timeOutInMilliseconds);
00192         
00193         if ((res != STATUS_TIMEOUT) && (res != WAIT_FAILED))
00194         {
00195                 
00196                 btAssert(res != WAIT_FAILED);
00197                 last = res - WAIT_OBJECT_0;
00198 
00199                 btSpuStatus& spuStatus = m_activeSpuStatus[last];
00200                 btAssert(spuStatus.m_threadHandle);
00201                 btAssert(spuStatus.m_eventCompletetHandle);
00202 
00203                 //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
00204                 btAssert(spuStatus.m_status > 1);
00205                 spuStatus.m_status = 0;
00206 
00208                 btAssert(last>=0);
00209 
00210         #else
00211                 last=0;
00212                 btSpuStatus& spuStatus = m_activeSpuStatus[last];
00213         #endif //SINGLE_THREADED
00214 
00215                 
00216 
00217                 *puiArgument0 = spuStatus.m_taskId;
00218                 *puiArgument1 = spuStatus.m_status;
00219 
00220                 return true;
00221         } 
00222 
00223         return false;
00224 }
00225 
00226 
00227 void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadConstructionInfo)
00228 {
00229 
00230         m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
00231         m_completeHandles.resize(threadConstructionInfo.m_numThreads);
00232 
00233         m_maxNumTasks = threadConstructionInfo.m_numThreads;
00234 
00235         for (int i=0;i<threadConstructionInfo.m_numThreads;i++)
00236         {
00237                 printf("starting thread %d\n",i);
00238 
00239                 btSpuStatus&    spuStatus = m_activeSpuStatus[i];
00240 
00241                 LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL;
00242                 SIZE_T dwStackSize=threadConstructionInfo.m_threadStackSize;
00243                 LPTHREAD_START_ROUTINE lpStartAddress=&Thread_no_1;
00244                 LPVOID lpParameter=&spuStatus;
00245                 DWORD dwCreationFlags=0;
00246                 LPDWORD lpThreadId=0;
00247 
00248                 spuStatus.m_userPtr=0;
00249 
00250                 sprintf(spuStatus.m_eventStartHandleName,"eventStart%s%d",threadConstructionInfo.m_uniqueName,i);
00251                 spuStatus.m_eventStartHandle = CreateEventA (0,false,false,spuStatus.m_eventStartHandleName);
00252 
00253                 sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%s%d",threadConstructionInfo.m_uniqueName,i);
00254                 spuStatus.m_eventCompletetHandle = CreateEventA (0,false,false,spuStatus.m_eventCompletetHandleName);
00255 
00256                 m_completeHandles[i] = spuStatus.m_eventCompletetHandle;
00257 
00258                 HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
00259                 SetThreadPriority(handle,THREAD_PRIORITY_HIGHEST);
00260                 //SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
00261 
00262                 SetThreadAffinityMask(handle, 1<<i);
00263 
00264                 spuStatus.m_taskId = i;
00265                 spuStatus.m_commandId = 0;
00266                 spuStatus.m_status = 0;
00267                 spuStatus.m_threadHandle = handle;
00268                 spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
00269                 spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
00270 
00271                 printf("started thread %d with threadHandle %p\n",i,handle);
00272                 
00273         }
00274 
00275 }
00276 
00277 void Win32ThreadSupport::startSPU()
00278 {
00279 }
00280 
00281 
00283 void Win32ThreadSupport::stopSPU()
00284 {
00285         int i;
00286         for (i=0;i<m_activeSpuStatus.size();i++)
00287         {
00288                 btSpuStatus& spuStatus = m_activeSpuStatus[i];
00289                 if (spuStatus.m_status>0)
00290                 {
00291                         WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
00292                 }
00293                 
00294 
00295                 spuStatus.m_userPtr = 0;
00296                 SetEvent(spuStatus.m_eventStartHandle);
00297                 WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
00298 
00299                 CloseHandle(spuStatus.m_eventCompletetHandle);
00300                 CloseHandle(spuStatus.m_eventStartHandle);
00301                 CloseHandle(spuStatus.m_threadHandle);
00302 
00303         }
00304 
00305         m_activeSpuStatus.clear();
00306         m_completeHandles.clear();
00307 
00308 }
00309 
00310 
00311 
00312 class btWin32Barrier : public btBarrier
00313 {
00314 private:
00315         CRITICAL_SECTION mExternalCriticalSection;
00316         CRITICAL_SECTION mLocalCriticalSection;
00317         HANDLE mRunEvent,mNotifyEvent;
00318         int mCounter,mEnableCounter;
00319         int mMaxCount;
00320 
00321 public:
00322         btWin32Barrier()
00323         {
00324                 mCounter = 0;
00325                 mMaxCount = 1;
00326                 mEnableCounter = 0;
00327                 InitializeCriticalSection(&mExternalCriticalSection);
00328                 InitializeCriticalSection(&mLocalCriticalSection);
00329                 mRunEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
00330                 mNotifyEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
00331         }
00332 
00333         virtual ~btWin32Barrier()
00334         {
00335                 DeleteCriticalSection(&mExternalCriticalSection);
00336                 DeleteCriticalSection(&mLocalCriticalSection);
00337                 CloseHandle(mRunEvent);
00338                 CloseHandle(mNotifyEvent);
00339         }
00340 
00341         void sync()
00342         {
00343                 int eventId;
00344 
00345                 EnterCriticalSection(&mExternalCriticalSection);
00346 
00347                 //PFX_PRINTF("enter taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
00348 
00349                 if(mEnableCounter > 0) {
00350                         ResetEvent(mNotifyEvent);
00351                         LeaveCriticalSection(&mExternalCriticalSection);
00352                         WaitForSingleObject(mNotifyEvent,INFINITE); 
00353                         EnterCriticalSection(&mExternalCriticalSection);
00354                 }
00355 
00356                 eventId = mCounter;
00357                 mCounter++;
00358 
00359                 if(eventId == mMaxCount-1) {
00360                         SetEvent(mRunEvent);
00361 
00362                         mEnableCounter = mCounter-1;
00363                         mCounter = 0;
00364                 }
00365                 else {
00366                         ResetEvent(mRunEvent);
00367                         LeaveCriticalSection(&mExternalCriticalSection);
00368                         WaitForSingleObject(mRunEvent,INFINITE); 
00369                         EnterCriticalSection(&mExternalCriticalSection);
00370                         mEnableCounter--;
00371                 }
00372 
00373                 if(mEnableCounter == 0) {
00374                         SetEvent(mNotifyEvent);
00375                 }
00376 
00377                 //PFX_PRINTF("leave taskId %d count %d stage %d phase %d mEnableCounter %d\n",taskId,mCounter,debug&0xff,debug>>16,mEnableCounter);
00378 
00379                 LeaveCriticalSection(&mExternalCriticalSection);
00380         }
00381 
00382         virtual void setMaxCount(int n) {mMaxCount = n;}
00383         virtual int  getMaxCount() {return mMaxCount;}
00384 };
00385 
00386 class btWin32CriticalSection : public btCriticalSection
00387 {
00388 private:
00389         CRITICAL_SECTION mCriticalSection;
00390 
00391 public:
00392         btWin32CriticalSection()
00393         {
00394                 InitializeCriticalSection(&mCriticalSection);
00395         }
00396 
00397         ~btWin32CriticalSection()
00398         {
00399                 DeleteCriticalSection(&mCriticalSection);
00400         }
00401 
00402         unsigned int getSharedParam(int i)
00403         {
00404                 btAssert(i>=0&&i<31);
00405                 return mCommonBuff[i+1];
00406         }
00407 
00408         void setSharedParam(int i,unsigned int p)
00409         {
00410                 btAssert(i>=0&&i<31);
00411                 mCommonBuff[i+1] = p;
00412         }
00413 
00414         void lock()
00415         {
00416                 EnterCriticalSection(&mCriticalSection);
00417                 mCommonBuff[0] = 1;
00418         }
00419 
00420         void unlock()
00421         {
00422                 mCommonBuff[0] = 0;
00423                 LeaveCriticalSection(&mCriticalSection);
00424         }
00425 };
00426 
00427 
00428 btBarrier*      Win32ThreadSupport::createBarrier()
00429 {
00430         unsigned char* mem = (unsigned char*)btAlignedAlloc(sizeof(btWin32Barrier),16);
00431         btWin32Barrier* barrier = new(mem) btWin32Barrier();
00432         barrier->setMaxCount(getNumTasks());
00433         return barrier;
00434 }
00435 
00436 btCriticalSection* Win32ThreadSupport::createCriticalSection()
00437 {
00438         unsigned char* mem = (unsigned char*) btAlignedAlloc(sizeof(btWin32CriticalSection),16);
00439         btWin32CriticalSection* cs = new(mem) btWin32CriticalSection();
00440         return cs;
00441 }
00442 
00443 void Win32ThreadSupport::deleteBarrier(btBarrier* barrier)
00444 {
00445         barrier->~btBarrier();
00446         btAlignedFree(barrier);
00447 }
00448 
00449 void Win32ThreadSupport::deleteCriticalSection(btCriticalSection* criticalSection)
00450 {
00451         criticalSection->~btCriticalSection();
00452         btAlignedFree(criticalSection);
00453 }
00454 
00455 
00456 #endif //USE_WIN32_THREADING
00457 
00458