Bullet Collision Detection & Physics Library
btThreadSupportPosix.cpp
Go to the documentation of this file.
1
2/*
3Bullet Continuous Collision Detection and Physics Library
4Copyright (c) 2003-2018 Erwin Coumans http://bulletphysics.com
5
6This software is provided 'as-is', without any express or implied warranty.
7In no event will the authors be held liable for any damages arising from the use of this software.
8Permission is granted to anyone to use this software for any purpose,
9including commercial applications, and to alter it and redistribute it freely,
10subject to the following restrictions:
11
121. 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.
132. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
143. This notice may not be removed or altered from any source distribution.
15*/
16
17#if BT_THREADSAFE && !defined(_WIN32)
18
19#include "LinearMath/btScalar.h"
22#include "LinearMath/btMinMax.h"
24
25#include <stdio.h>
26#include <errno.h>
27#include <unistd.h>
28
29#ifndef _XOPEN_SOURCE
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
32#include <pthread.h>
33#include <semaphore.h>
34#include <unistd.h> //for sysconf
35
42#if __cplusplus >= 201103L
43
44#include <thread>
45
47{
48 return btMax(1u, btMin(BT_MAX_THREAD_COUNT, std::thread::hardware_concurrency()));
49}
50
51#else
52
54{
56}
57
58#endif
59
60// btThreadSupportPosix helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
62{
63public:
64 struct btThreadStatus
65 {
66 int m_taskId;
67 int m_commandId;
68 int m_status;
69
70 ThreadFunc m_userThreadFunc;
71 void* m_userPtr; //for taskDesc etc
72
74 //each tread will wait until this signal to start its work
77 // this is a copy of m_mainSemaphore,
78 //each tread will signal once it is finished with its work
80 unsigned long threadUsed;
81 };
82
83private:
84 typedef unsigned long long UINT64;
85
87 // m_mainSemaphoresemaphore will signal, if and how many threads are finished with their work
89 int m_numThreads;
91 void startThreads(const ConstructionInfo& threadInfo);
92 void stopThreads();
93 int waitForResponse();
95public:
96 btThreadSupportPosix(const ConstructionInfo& threadConstructionInfo);
97 virtual ~btThreadSupportPosix();
98
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; }
104
105 virtual void runTask(int threadIndex, void* userData) BT_OVERRIDE;
106 virtual void waitForAllTasks() BT_OVERRIDE;
107
108 virtual btCriticalSection* createCriticalSection() BT_OVERRIDE;
109 virtual void deleteCriticalSection(btCriticalSection* criticalSection) BT_OVERRIDE;
110};
111
112#define checkPThreadFunction(returnValue) \
113 if (0 != returnValue) \
114 { \
115 printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \
116 }
117
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.
120
121btThreadSupportPosix::btThreadSupportPosix(const ConstructionInfo& threadConstructionInfo)
122{
125}
126
127// cleanup/shutdown Libspe2
128btThreadSupportPosix::~btThreadSupportPosix()
129{
130 stopThreads();
132 m_cs=0;
133}
134
135#if (defined(__APPLE__))
136#define NAMED_SEMAPHORES
137#endif
138
139static sem_t* createSem(const char* baseName)
140{
141 static int semCount = 0;
142#ifdef NAMED_SEMAPHORES
144 char name[32];
145 snprintf(name, 32, "/%8.s-%4.d-%4.4d", baseName, getpid(), semCount++);
146 sem_t* tempSem = sem_open(name, O_CREAT, 0600, 0);
147
148 if (tempSem != reinterpret_cast<sem_t*>(SEM_FAILED))
149 {
150 // printf("Created \"%s\" Semaphore %p\n", name, tempSem);
151 }
152 else
153 {
154 //printf("Error creating Semaphore %d\n", errno);
155 exit(-1);
156 }
158#else
159 sem_t* tempSem = new sem_t;
161#endif
162 return tempSem;
163}
164
165static void destroySem(sem_t* semaphore)
166{
167#ifdef NAMED_SEMAPHORES
169#else
171 delete semaphore;
172#endif
173}
174
175static void* threadFunction(void* argument)
176{
177 btThreadSupportPosix::btThreadStatus* status = (btThreadSupportPosix::btThreadStatus*)argument;
178
179 while (1)
180 {
181 checkPThreadFunction(sem_wait(status->startSemaphore));
182 void* userPtr = status->m_userPtr;
183
184 if (userPtr)
185 {
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++;
193 }
194 else
195 {
196 //exit Thread
197 status->m_cs->lock();
198 status->m_status = 3;
199 status->m_cs->unlock();
200 checkPThreadFunction(sem_post(status->m_mainSemaphore));
201 break;
202 }
203 }
204
205 return 0;
206}
207
209void btThreadSupportPosix::runTask(int threadIndex, void* userData)
210{
213 btAssert(threadIndex >= 0);
215 threadStatus.m_cs = m_cs;
216 threadStatus.m_commandId = 1;
217 threadStatus.m_status = 1;
218 threadStatus.m_userPtr = userData;
220
221 // fire event to start new task
223}
224
226int btThreadSupportPosix::waitForResponse()
227{
230
232
233 // wait for any of the threads to finish
235 // get at least one thread which has finished
236 size_t last = -1;
237
238 for (size_t t = 0; t < size_t(m_activeThreadStatus.size()); ++t)
239 {
240 m_cs->lock();
241 bool hasFinished = (2 == m_activeThreadStatus[t].m_status);
242 m_cs->unlock();
243 if (hasFinished)
244 {
245 last = t;
246 break;
247 }
248 }
249
251
252 btAssert(threadStatus.m_status > 1);
253 threadStatus.m_status = 0;
254
255 // need to find an active spu
256 btAssert(last >= 0);
257 m_startedThreadsMask &= ~(UINT64(1) << last);
258
259 return last;
260}
261
262void btThreadSupportPosix::waitForAllTasks()
263{
265 {
267 }
268}
269
270void btThreadSupportPosix::startThreads(const ConstructionInfo& threadConstructionInfo)
271{
272 m_numThreads = btGetNumHardwareThreads() - 1; // main thread exists already
275
276 m_mainSemaphore = createSem("main");
277 //checkPThreadFunction(sem_wait(mainSemaphore));
278
279 for (int i = 0; i < m_numThreads; i++)
280 {
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;
292
293 }
294}
295
297void btThreadSupportPosix::stopThreads()
298{
299 for (size_t t = 0; t < size_t(m_activeThreadStatus.size()); ++t)
300 {
302
303 threadStatus.m_userPtr = 0;
306
308 destroySem(threadStatus.startSemaphore);
309 }
311 m_activeThreadStatus.clear();
312}
313
315{
316 pthread_mutex_t m_mutex;
317
318public:
320 {
321 pthread_mutex_init(&m_mutex, NULL);
322 }
324 {
325 pthread_mutex_destroy(&m_mutex);
326 }
327
328 virtual void lock()
329 {
330 pthread_mutex_lock(&m_mutex);
331 }
332 virtual void unlock()
333 {
334 pthread_mutex_unlock(&m_mutex);
335 }
336};
337
338btCriticalSection* btThreadSupportPosix::createCriticalSection()
339{
340 return new btCriticalSectionPosix();
341}
342
343void btThreadSupportPosix::deleteCriticalSection(btCriticalSection* cs)
344{
345 delete cs;
346}
347
349{
350 return new btThreadSupportPosix(info);
351}
352
353#endif // BT_THREADSAFE && !defined( _WIN32 )
const T & btMax(const T &a, const T &b)
Definition btMinMax.h:27
const T & btMin(const T &a, const T &b)
Definition btMinMax.h:21
#define btAssert(x)
Definition btScalar.h:153
#define BT_OVERRIDE
Definition btThreads.h:26
const unsigned int BT_MAX_THREAD_COUNT
Definition btThreads.h:31
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
virtual int getCacheFriendlyNumThreads() const =0
virtual int getLogicalToPhysicalCoreRatio() const =0
virtual void waitForAllTasks()=0
static btThreadSupportInterface * create(const ConstructionInfo &info)
virtual void runTask(int threadIndex, void *userData)=0
virtual int getNumWorkerThreads() const =0
virtual void deleteCriticalSection(btCriticalSection *criticalSection)=0
virtual btCriticalSection * createCriticalSection()=0