3 Bullet Continuous Collision Detection and Physics Library
4 Copyright (c) 2003-2018 Erwin Coumans http://bulletphysics.com
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it freely,
10 subject to the following restrictions:
12 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.
13 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14 3. This notice may not be removed or altered from any source distribution.
17 #if BT_THREADSAFE && !defined(_WIN32)
19 #include "LinearMath/btScalar.h"
20 #include "LinearMath/btAlignedObjectArray.h"
21 #include "LinearMath/btThreads.h"
22 #include "LinearMath/btMinMax.h"
23 #include "btThreadSupportInterface.h"
30 #define _XOPEN_SOURCE 600 //for definition of pthread_barrier_t, see http://pages.cs.wisc.edu/~travitch/pthreads_primer.html
31 #endif //_XOPEN_SOURCE
33 #include <semaphore.h>
34 #include <unistd.h> //for sysconf
37 /// getNumHardwareThreads()
40 /// https://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
42 #if __cplusplus >= 201103L
46 int btGetNumHardwareThreads()
48 return btMax(1u, btMin(BT_MAX_THREAD_COUNT, std::thread::hardware_concurrency()));
53 int btGetNumHardwareThreads()
55 return btMax(1, btMin<int>(BT_MAX_THREAD_COUNT, sysconf(_SC_NPROCESSORS_ONLN)));
60 // btThreadSupportPosix helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
61 class btThreadSupportPosix : public btThreadSupportInterface
70 ThreadFunc m_userThreadFunc;
71 void* m_userPtr; //for taskDesc etc
74 //each tread will wait until this signal to start its work
75 sem_t* startSemaphore;
76 btCriticalSection* m_cs;
77 // this is a copy of m_mainSemaphore,
78 //each tread will signal once it is finished with its work
79 sem_t* m_mainSemaphore;
80 unsigned long threadUsed;
84 typedef unsigned long long UINT64;
86 btAlignedObjectArray<btThreadStatus> m_activeThreadStatus;
87 // m_mainSemaphoresemaphore will signal, if and how many threads are finished with their work
88 sem_t* m_mainSemaphore;
90 UINT64 m_startedThreadsMask;
91 void startThreads(const ConstructionInfo& threadInfo);
93 int waitForResponse();
94 btCriticalSection* m_cs;
96 btThreadSupportPosix(const ConstructionInfo& threadConstructionInfo);
97 virtual ~btThreadSupportPosix();
99 virtual int getNumWorkerThreads() const BT_OVERRIDE { return m_numThreads; }
100 // TODO: return the number of logical processors sharing the first L3 cache
101 virtual int getCacheFriendlyNumThreads() const BT_OVERRIDE { return m_numThreads + 1; }
102 // TODO: detect if CPU has hyperthreading enabled
103 virtual int getLogicalToPhysicalCoreRatio() const BT_OVERRIDE { return 1; }
105 virtual void runTask(int threadIndex, void* userData) BT_OVERRIDE;
106 virtual void waitForAllTasks() BT_OVERRIDE;
108 virtual btCriticalSection* createCriticalSection() BT_OVERRIDE;
109 virtual void deleteCriticalSection(btCriticalSection* criticalSection) BT_OVERRIDE;
112 #define checkPThreadFunction(returnValue) \
113 if (0 != returnValue) \
115 printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \
118 // The number of threads should be equal to the number of available cores
119 // Todo: each worker should be linked to a single core, using SetThreadIdealProcessor.
121 btThreadSupportPosix::btThreadSupportPosix(const ConstructionInfo& threadConstructionInfo)
123 m_cs = createCriticalSection();
124 startThreads(threadConstructionInfo);
127 // cleanup/shutdown Libspe2
128 btThreadSupportPosix::~btThreadSupportPosix()
131 deleteCriticalSection(m_cs);
135 #if (defined(__APPLE__))
136 #define NAMED_SEMAPHORES
139 static sem_t* createSem(const char* baseName)
141 static int semCount = 0;
142 #ifdef NAMED_SEMAPHORES
143 /// Named semaphore begin
145 snprintf(name, 32, "/%8.s-%4.d-%4.4d", baseName, getpid(), semCount++);
146 sem_t* tempSem = sem_open(name, O_CREAT, 0600, 0);
148 if (tempSem != reinterpret_cast<sem_t*>(SEM_FAILED))
150 // printf("Created \"%s\" Semaphore %p\n", name, tempSem);
154 //printf("Error creating Semaphore %d\n", errno);
157 /// Named semaphore end
159 sem_t* tempSem = new sem_t;
160 checkPThreadFunction(sem_init(tempSem, 0, 0));
165 static void destroySem(sem_t* semaphore)
167 #ifdef NAMED_SEMAPHORES
168 checkPThreadFunction(sem_close(semaphore));
170 checkPThreadFunction(sem_destroy(semaphore));
175 static void* threadFunction(void* argument)
177 btThreadSupportPosix::btThreadStatus* status = (btThreadSupportPosix::btThreadStatus*)argument;
181 checkPThreadFunction(sem_wait(status->startSemaphore));
182 void* userPtr = status->m_userPtr;
186 btAssert(status->m_status);
187 status->m_userThreadFunc(userPtr);
188 status->m_cs->lock();
189 status->m_status = 2;
190 status->m_cs->unlock();
191 checkPThreadFunction(sem_post(status->m_mainSemaphore));
192 status->threadUsed++;
197 status->m_cs->lock();
198 status->m_status = 3;
199 status->m_cs->unlock();
200 checkPThreadFunction(sem_post(status->m_mainSemaphore));
208 ///send messages to SPUs
209 void btThreadSupportPosix::runTask(int threadIndex, void* userData)
211 ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
212 btThreadStatus& threadStatus = m_activeThreadStatus[threadIndex];
213 btAssert(threadIndex >= 0);
214 btAssert(threadIndex < m_activeThreadStatus.size());
215 threadStatus.m_cs = m_cs;
216 threadStatus.m_commandId = 1;
217 threadStatus.m_status = 1;
218 threadStatus.m_userPtr = userData;
219 m_startedThreadsMask |= UINT64(1) << threadIndex;
221 // fire event to start new task
222 checkPThreadFunction(sem_post(threadStatus.startSemaphore));
225 ///check for messages from SPUs
226 int btThreadSupportPosix::waitForResponse()
228 ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
229 ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
231 btAssert(m_activeThreadStatus.size());
233 // wait for any of the threads to finish
234 checkPThreadFunction(sem_wait(m_mainSemaphore));
235 // get at least one thread which has finished
238 for (size_t t = 0; t < size_t(m_activeThreadStatus.size()); ++t)
241 bool hasFinished = (2 == m_activeThreadStatus[t].m_status);
250 btThreadStatus& threadStatus = m_activeThreadStatus[last];
252 btAssert(threadStatus.m_status > 1);
253 threadStatus.m_status = 0;
255 // need to find an active spu
257 m_startedThreadsMask &= ~(UINT64(1) << last);
262 void btThreadSupportPosix::waitForAllTasks()
264 while (m_startedThreadsMask)
270 void btThreadSupportPosix::startThreads(const ConstructionInfo& threadConstructionInfo)
272 m_numThreads = btGetNumHardwareThreads() - 1; // main thread exists already
273 m_activeThreadStatus.resize(m_numThreads);
274 m_startedThreadsMask = 0;
276 m_mainSemaphore = createSem("main");
277 //checkPThreadFunction(sem_wait(mainSemaphore));
279 for (int i = 0; i < m_numThreads; i++)
281 btThreadStatus& threadStatus = m_activeThreadStatus[i];
282 threadStatus.startSemaphore = createSem("threadLocal");
283 threadStatus.m_userPtr = 0;
284 threadStatus.m_cs = m_cs;
285 threadStatus.m_taskId = i;
286 threadStatus.m_commandId = 0;
287 threadStatus.m_status = 0;
288 threadStatus.m_mainSemaphore = m_mainSemaphore;
289 threadStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
290 threadStatus.threadUsed = 0;
291 checkPThreadFunction(pthread_create(&threadStatus.thread, NULL, &threadFunction, (void*)&threadStatus));
296 ///tell the task scheduler we are done with the SPU tasks
297 void btThreadSupportPosix::stopThreads()
299 for (size_t t = 0; t < size_t(m_activeThreadStatus.size()); ++t)
301 btThreadStatus& threadStatus = m_activeThreadStatus[t];
303 threadStatus.m_userPtr = 0;
304 checkPThreadFunction(sem_post(threadStatus.startSemaphore));
305 checkPThreadFunction(sem_wait(m_mainSemaphore));
307 checkPThreadFunction(pthread_join(threadStatus.thread, 0));
308 destroySem(threadStatus.startSemaphore);
310 destroySem(m_mainSemaphore);
311 m_activeThreadStatus.clear();
314 class btCriticalSectionPosix : public btCriticalSection
316 pthread_mutex_t m_mutex;
319 btCriticalSectionPosix()
321 pthread_mutex_init(&m_mutex, NULL);
323 virtual ~btCriticalSectionPosix()
325 pthread_mutex_destroy(&m_mutex);
330 pthread_mutex_lock(&m_mutex);
332 virtual void unlock()
334 pthread_mutex_unlock(&m_mutex);
338 btCriticalSection* btThreadSupportPosix::createCriticalSection()
340 return new btCriticalSectionPosix();
343 void btThreadSupportPosix::deleteCriticalSection(btCriticalSection* cs)
348 btThreadSupportInterface* btThreadSupportInterface::create(const ConstructionInfo& info)
350 return new btThreadSupportPosix(info);
353 #endif // BT_THREADSAFE && !defined( _WIN32 )