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.
17 #include "PosixThreadSupport.h"
22 #include "SpuCollisionTaskProcess.h"
23 #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
25 #define checkPThreadFunction(returnValue) \
26 if(0 != returnValue) { \
27 printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \
30 // The number of threads should be equal to the number of available cores
31 // Todo: each worker should be linked to a single core, using SetThreadIdealProcessor.
33 // PosixThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
34 // Setup and initialize SPU/CELL/Libspe2
35 PosixThreadSupport::PosixThreadSupport(ThreadConstructionInfo& threadConstructionInfo)
37 startThreads(threadConstructionInfo);
40 // cleanup/shutdown Libspe2
41 PosixThreadSupport::~PosixThreadSupport()
46 #if (defined (__APPLE__))
47 #define NAMED_SEMAPHORES
50 // this semaphore will signal, if and how many threads are finished with their work
51 static sem_t* mainSemaphore=0;
53 static sem_t* createSem(const char* baseName)
55 static int semCount = 0;
56 #ifdef NAMED_SEMAPHORES
57 /// Named semaphore begin
59 snprintf(name, 32, "/%s-%d-%4.4d", baseName, getpid(), semCount++);
60 sem_t* tempSem = sem_open(name, O_CREAT, 0600, 0);
62 if (tempSem != reinterpret_cast<sem_t *>(SEM_FAILED))
64 // printf("Created \"%s\" Semaphore %p\n", name, tempSem);
68 //printf("Error creating Semaphore %d\n", errno);
71 /// Named semaphore end
73 sem_t* tempSem = new sem_t;
74 checkPThreadFunction(sem_init(tempSem, 0, 0));
79 static void destroySem(sem_t* semaphore)
81 #ifdef NAMED_SEMAPHORES
82 checkPThreadFunction(sem_close(semaphore));
84 checkPThreadFunction(sem_destroy(semaphore));
89 static void *threadFunction(void *argument)
92 PosixThreadSupport::btSpuStatus* status = (PosixThreadSupport::btSpuStatus*)argument;
97 checkPThreadFunction(sem_wait(status->startSemaphore));
99 void* userPtr = status->m_userPtr;
103 btAssert(status->m_status);
104 status->m_userThreadFunc(userPtr,status->m_lsMemory);
105 status->m_status = 2;
106 checkPThreadFunction(sem_post(mainSemaphore));
107 status->threadUsed++;
110 status->m_status = 3;
111 checkPThreadFunction(sem_post(mainSemaphore));
112 printf("Thread with taskId %i exiting\n",status->m_taskId);
118 printf("Thread TERMINATED\n");
123 ///send messages to SPUs
124 void PosixThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId)
126 /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc);
128 ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
134 case CMD_GATHER_AND_PROCESS_PAIRLIST:
136 btSpuStatus& spuStatus = m_activeSpuStatus[taskId];
137 btAssert(taskId >= 0);
138 btAssert(taskId < m_activeSpuStatus.size());
140 spuStatus.m_commandId = uiCommand;
141 spuStatus.m_status = 1;
142 spuStatus.m_userPtr = (void*)uiArgument0;
144 // fire event to start new task
145 checkPThreadFunction(sem_post(spuStatus.startSemaphore));
160 ///check for messages from SPUs
161 void PosixThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
163 ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
165 ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
168 btAssert(m_activeSpuStatus.size());
170 // wait for any of the threads to finish
171 checkPThreadFunction(sem_wait(mainSemaphore));
173 // get at least one thread which has finished
176 for(size_t t=0; t < size_t(m_activeSpuStatus.size()); ++t) {
177 if(2 == m_activeSpuStatus[t].m_status) {
183 btSpuStatus& spuStatus = m_activeSpuStatus[last];
185 btAssert(spuStatus.m_status > 1);
186 spuStatus.m_status = 0;
188 // need to find an active spu
191 *puiArgument0 = spuStatus.m_taskId;
192 *puiArgument1 = spuStatus.m_status;
197 void PosixThreadSupport::startThreads(ThreadConstructionInfo& threadConstructionInfo)
199 printf("%s creating %i threads.\n", __FUNCTION__, threadConstructionInfo.m_numThreads);
200 m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
202 mainSemaphore = createSem("main");
203 //checkPThreadFunction(sem_wait(mainSemaphore));
205 for (int i=0;i < threadConstructionInfo.m_numThreads;i++)
207 printf("starting thread %d\n",i);
209 btSpuStatus& spuStatus = m_activeSpuStatus[i];
211 spuStatus.startSemaphore = createSem("threadLocal");
213 checkPThreadFunction(pthread_create(&spuStatus.thread, NULL, &threadFunction, (void*)&spuStatus));
215 spuStatus.m_userPtr=0;
217 spuStatus.m_taskId = i;
218 spuStatus.m_commandId = 0;
219 spuStatus.m_status = 0;
220 spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
221 spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
222 spuStatus.threadUsed = 0;
224 printf("started thread %d \n",i);
230 void PosixThreadSupport::startSPU()
235 ///tell the task scheduler we are done with the SPU tasks
236 void PosixThreadSupport::stopSPU()
238 for(size_t t=0; t < size_t(m_activeSpuStatus.size()); ++t)
240 btSpuStatus& spuStatus = m_activeSpuStatus[t];
241 printf("%s: Thread %i used: %ld\n", __FUNCTION__, int(t), spuStatus.threadUsed);
243 spuStatus.m_userPtr = 0;
244 checkPThreadFunction(sem_post(spuStatus.startSemaphore));
245 checkPThreadFunction(sem_wait(mainSemaphore));
247 printf("destroy semaphore\n");
248 destroySem(spuStatus.startSemaphore);
249 printf("semaphore destroyed\n");
250 checkPThreadFunction(pthread_join(spuStatus.thread,0));
253 printf("destroy main semaphore\n");
254 destroySem(mainSemaphore);
255 printf("main semaphore destroyed\n");
256 m_activeSpuStatus.clear();
259 class PosixCriticalSection : public btCriticalSection
261 pthread_mutex_t m_mutex;
264 PosixCriticalSection()
266 pthread_mutex_init(&m_mutex, NULL);
268 virtual ~PosixCriticalSection()
270 pthread_mutex_destroy(&m_mutex);
273 ATTRIBUTE_ALIGNED16(unsigned int mCommonBuff[32]);
275 virtual unsigned int getSharedParam(int i)
277 return mCommonBuff[i];
279 virtual void setSharedParam(int i,unsigned int p)
286 pthread_mutex_lock(&m_mutex);
288 virtual void unlock()
290 pthread_mutex_unlock(&m_mutex);
295 #if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS - 20012L) >= 0
296 /* OK to use barriers on this platform */
297 class PosixBarrier : public btBarrier
299 pthread_barrier_t m_barr;
304 virtual ~PosixBarrier() {
305 pthread_barrier_destroy(&m_barr);
310 int rc = pthread_barrier_wait(&m_barr);
311 if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD)
313 printf("Could not wait on barrier\n");
317 virtual void setMaxCount(int numThreads)
319 int result = pthread_barrier_init(&m_barr, NULL, numThreads);
320 m_numThreads = numThreads;
323 virtual int getMaxCount()
329 /* Not OK to use barriers on this platform - insert alternate code here */
330 class PosixBarrier : public btBarrier
332 pthread_mutex_t m_mutex;
333 pthread_cond_t m_cond;
343 virtual ~PosixBarrier()
347 pthread_mutex_destroy(&m_mutex);
348 pthread_cond_destroy(&m_cond);
354 pthread_mutex_lock(&m_mutex);
356 if (m_called == m_numThreads) {
358 pthread_cond_broadcast(&m_cond);
360 pthread_cond_wait(&m_cond,&m_mutex);
362 pthread_mutex_unlock(&m_mutex);
365 virtual void setMaxCount(int numThreads)
369 pthread_mutex_destroy(&m_mutex);
370 pthread_cond_destroy(&m_cond);
373 pthread_mutex_init(&m_mutex,NULL);
374 pthread_cond_init(&m_cond,NULL);
375 m_numThreads = numThreads;
377 virtual int getMaxCount()
383 #endif//_POSIX_BARRIERS
387 btBarrier* PosixThreadSupport::createBarrier()
389 PosixBarrier* barrier = new PosixBarrier();
390 barrier->setMaxCount(getNumTasks());
394 btCriticalSection* PosixThreadSupport::createCriticalSection()
396 return new PosixCriticalSection();
399 void PosixThreadSupport::deleteBarrier(btBarrier* barrier)
404 void PosixThreadSupport::deleteCriticalSection(btCriticalSection* cs)
408 #endif // USE_PTHREADS