diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-04-21 17:55:35 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-04-21 17:55:35 -0700 |
commit | 887ce3dde89410d012a708c3ec454f679b2e5b1e (patch) | |
tree | daeadbc86bf721a5d4fff109a1d87a4c69215905 /tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp | |
parent | b3f4022e35b34002f44aacde554cc8b3ea927500 (diff) |
update bullet test to compile from source
Diffstat (limited to 'tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp')
-rw-r--r-- | tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp b/tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp new file mode 100644 index 00000000..c8b49ee3 --- /dev/null +++ b/tests/bullet/src/BulletMultiThreaded/PosixThreadSupport.cpp @@ -0,0 +1,399 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +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. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include <stdio.h> +#include "PosixThreadSupport.h" +#ifdef USE_PTHREADS +#include <errno.h> +#include <unistd.h> + +#include "SpuCollisionTaskProcess.h" +#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" + +#define checkPThreadFunction(returnValue) \ + if(0 != returnValue) { \ + printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \ + } + +// The number of threads should be equal to the number of available cores +// Todo: each worker should be linked to a single core, using SetThreadIdealProcessor. + +// PosixThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication +// Setup and initialize SPU/CELL/Libspe2 +PosixThreadSupport::PosixThreadSupport(ThreadConstructionInfo& threadConstructionInfo) +{ + startThreads(threadConstructionInfo); +} + +// cleanup/shutdown Libspe2 +PosixThreadSupport::~PosixThreadSupport() +{ + stopSPU(); +} + +#if (defined (__APPLE__)) +#define NAMED_SEMAPHORES +#endif + +// this semaphore will signal, if and how many threads are finished with their work +static sem_t* mainSemaphore=0; + +static sem_t* createSem(const char* baseName) +{ + static int semCount = 0; +#ifdef NAMED_SEMAPHORES + /// Named semaphore begin + char name[32]; + snprintf(name, 32, "/%s-%d-%4.4d", baseName, getpid(), semCount++); + sem_t* tempSem = sem_open(name, O_CREAT, 0600, 0); + + if (tempSem != reinterpret_cast<sem_t *>(SEM_FAILED)) + { +// printf("Created \"%s\" Semaphore %p\n", name, tempSem); + } + else + { + //printf("Error creating Semaphore %d\n", errno); + exit(-1); + } + /// Named semaphore end +#else + sem_t* tempSem = new sem_t; + checkPThreadFunction(sem_init(tempSem, 0, 0)); +#endif + return tempSem; +} + +static void destroySem(sem_t* semaphore) +{ +#ifdef NAMED_SEMAPHORES + checkPThreadFunction(sem_close(semaphore)); +#else + checkPThreadFunction(sem_destroy(semaphore)); + delete semaphore; +#endif +} + +static void *threadFunction(void *argument) +{ + + PosixThreadSupport::btSpuStatus* status = (PosixThreadSupport::btSpuStatus*)argument; + + + while (1) + { + checkPThreadFunction(sem_wait(status->startSemaphore)); + + void* userPtr = status->m_userPtr; + + if (userPtr) + { + btAssert(status->m_status); + status->m_userThreadFunc(userPtr,status->m_lsMemory); + status->m_status = 2; + checkPThreadFunction(sem_post(mainSemaphore)); + status->threadUsed++; + } else { + //exit Thread + status->m_status = 3; + checkPThreadFunction(sem_post(mainSemaphore)); + printf("Thread with taskId %i exiting\n",status->m_taskId); + break; + } + + } + + printf("Thread TERMINATED\n"); + return 0; + +} + +///send messages to SPUs +void PosixThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId) +{ + /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc); + + ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished + + + + switch (uiCommand) + { + case CMD_GATHER_AND_PROCESS_PAIRLIST: + { + btSpuStatus& spuStatus = m_activeSpuStatus[taskId]; + btAssert(taskId >= 0); + btAssert(taskId < m_activeSpuStatus.size()); + + spuStatus.m_commandId = uiCommand; + spuStatus.m_status = 1; + spuStatus.m_userPtr = (void*)uiArgument0; + + // fire event to start new task + checkPThreadFunction(sem_post(spuStatus.startSemaphore)); + break; + } + default: + { + ///not implemented + btAssert(0); + } + + }; + + +} + + +///check for messages from SPUs +void PosixThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) +{ + ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response + + ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback' + + + btAssert(m_activeSpuStatus.size()); + + // wait for any of the threads to finish + checkPThreadFunction(sem_wait(mainSemaphore)); + + // get at least one thread which has finished + size_t last = -1; + + for(size_t t=0; t < size_t(m_activeSpuStatus.size()); ++t) { + if(2 == m_activeSpuStatus[t].m_status) { + last = t; + break; + } + } + + btSpuStatus& spuStatus = m_activeSpuStatus[last]; + + btAssert(spuStatus.m_status > 1); + spuStatus.m_status = 0; + + // need to find an active spu + btAssert(last >= 0); + + *puiArgument0 = spuStatus.m_taskId; + *puiArgument1 = spuStatus.m_status; +} + + + +void PosixThreadSupport::startThreads(ThreadConstructionInfo& threadConstructionInfo) +{ + printf("%s creating %i threads.\n", __FUNCTION__, threadConstructionInfo.m_numThreads); + m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads); + + mainSemaphore = createSem("main"); + //checkPThreadFunction(sem_wait(mainSemaphore)); + + for (int i=0;i < threadConstructionInfo.m_numThreads;i++) + { + printf("starting thread %d\n",i); + + btSpuStatus& spuStatus = m_activeSpuStatus[i]; + + spuStatus.startSemaphore = createSem("threadLocal"); + + checkPThreadFunction(pthread_create(&spuStatus.thread, NULL, &threadFunction, (void*)&spuStatus)); + + spuStatus.m_userPtr=0; + + spuStatus.m_taskId = i; + spuStatus.m_commandId = 0; + spuStatus.m_status = 0; + spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc(); + spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc; + spuStatus.threadUsed = 0; + + printf("started thread %d \n",i); + + } + +} + +void PosixThreadSupport::startSPU() +{ +} + + +///tell the task scheduler we are done with the SPU tasks +void PosixThreadSupport::stopSPU() +{ + for(size_t t=0; t < size_t(m_activeSpuStatus.size()); ++t) + { + btSpuStatus& spuStatus = m_activeSpuStatus[t]; + printf("%s: Thread %i used: %ld\n", __FUNCTION__, int(t), spuStatus.threadUsed); + + spuStatus.m_userPtr = 0; + checkPThreadFunction(sem_post(spuStatus.startSemaphore)); + checkPThreadFunction(sem_wait(mainSemaphore)); + + printf("destroy semaphore\n"); + destroySem(spuStatus.startSemaphore); + printf("semaphore destroyed\n"); + checkPThreadFunction(pthread_join(spuStatus.thread,0)); + } + printf("destroy main semaphore\n"); + destroySem(mainSemaphore); + printf("main semaphore destroyed\n"); + m_activeSpuStatus.clear(); +} + +class PosixCriticalSection : public btCriticalSection +{ + pthread_mutex_t m_mutex; + +public: + PosixCriticalSection() + { + pthread_mutex_init(&m_mutex, NULL); + } + virtual ~PosixCriticalSection() + { + pthread_mutex_destroy(&m_mutex); + } + + ATTRIBUTE_ALIGNED16(unsigned int mCommonBuff[32]); + + virtual unsigned int getSharedParam(int i) + { + return mCommonBuff[i]; + } + virtual void setSharedParam(int i,unsigned int p) + { + mCommonBuff[i] = p; + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } +}; + + +#if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS - 20012L) >= 0 +/* OK to use barriers on this platform */ +class PosixBarrier : public btBarrier +{ + pthread_barrier_t m_barr; + int m_numThreads; +public: + PosixBarrier() + :m_numThreads(0) { } + virtual ~PosixBarrier() { + pthread_barrier_destroy(&m_barr); + } + + virtual void sync() + { + int rc = pthread_barrier_wait(&m_barr); + if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf("Could not wait on barrier\n"); + exit(-1); + } + } + virtual void setMaxCount(int numThreads) + { + int result = pthread_barrier_init(&m_barr, NULL, numThreads); + m_numThreads = numThreads; + btAssert(result==0); + } + virtual int getMaxCount() + { + return m_numThreads; + } +}; +#else +/* Not OK to use barriers on this platform - insert alternate code here */ +class PosixBarrier : public btBarrier +{ + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + + int m_numThreads; + int m_called; + +public: + PosixBarrier() + :m_numThreads(0) + { + } + virtual ~PosixBarrier() + { + if (m_numThreads>0) + { + pthread_mutex_destroy(&m_mutex); + pthread_cond_destroy(&m_cond); + } + } + + virtual void sync() + { + pthread_mutex_lock(&m_mutex); + m_called++; + if (m_called == m_numThreads) { + m_called = 0; + pthread_cond_broadcast(&m_cond); + } else { + pthread_cond_wait(&m_cond,&m_mutex); + } + pthread_mutex_unlock(&m_mutex); + + } + virtual void setMaxCount(int numThreads) + { + if (m_numThreads>0) + { + pthread_mutex_destroy(&m_mutex); + pthread_cond_destroy(&m_cond); + } + m_called = 0; + pthread_mutex_init(&m_mutex,NULL); + pthread_cond_init(&m_cond,NULL); + m_numThreads = numThreads; + } + virtual int getMaxCount() + { + return m_numThreads; + } +}; + +#endif//_POSIX_BARRIERS + + + +btBarrier* PosixThreadSupport::createBarrier() +{ + PosixBarrier* barrier = new PosixBarrier(); + barrier->setMaxCount(getNumTasks()); + return barrier; +} + +btCriticalSection* PosixThreadSupport::createCriticalSection() +{ + return new PosixCriticalSection(); +} + +#endif // USE_PTHREADS + |