123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- /*
- 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();
- }
- void PosixThreadSupport::deleteBarrier(btBarrier* barrier)
- {
- delete barrier;
- }
- void PosixThreadSupport::deleteCriticalSection(btCriticalSection* cs)
- {
- delete cs;
- }
- #endif // USE_PTHREADS
|