rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_ThreadsPthread.cpp
|
nuclear@0
|
4 Content :
|
nuclear@0
|
5 Created :
|
nuclear@0
|
6 Notes :
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_Threads.h"
|
nuclear@0
|
28 #include "OVR_Hash.h"
|
nuclear@0
|
29
|
nuclear@0
|
30 #ifdef OVR_ENABLE_THREADS
|
nuclear@0
|
31
|
nuclear@0
|
32 #include "OVR_Timer.h"
|
nuclear@0
|
33 #include "OVR_Log.h"
|
nuclear@0
|
34
|
nuclear@0
|
35 #include <pthread.h>
|
nuclear@0
|
36 #include <sched.h>
|
nuclear@0
|
37 #include <time.h>
|
nuclear@0
|
38 #include <unistd.h>
|
nuclear@0
|
39 #include <sys/time.h>
|
nuclear@0
|
40 #include <errno.h>
|
nuclear@0
|
41
|
nuclear@0
|
42 #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD)
|
nuclear@0
|
43 #include <sys/sysctl.h>
|
nuclear@0
|
44 #include <sys/param.h>
|
nuclear@0
|
45 #if !defined(OVR_OS_MAC)
|
nuclear@0
|
46 #include <pthread_np.h>
|
nuclear@0
|
47 #endif
|
nuclear@0
|
48 #endif
|
nuclear@0
|
49
|
nuclear@0
|
50
|
nuclear@0
|
51
|
nuclear@0
|
52 namespace OVR {
|
nuclear@0
|
53
|
nuclear@0
|
54 // ***** Mutex implementation
|
nuclear@0
|
55
|
nuclear@0
|
56
|
nuclear@0
|
57 // *** Internal Mutex implementation structure
|
nuclear@0
|
58
|
nuclear@0
|
59 class MutexImpl : public NewOverrideBase
|
nuclear@0
|
60 {
|
nuclear@0
|
61 // System mutex or semaphore
|
nuclear@0
|
62 pthread_mutex_t SMutex;
|
nuclear@0
|
63 bool Recursive;
|
nuclear@0
|
64 unsigned LockCount;
|
nuclear@0
|
65 pthread_t LockedBy;
|
nuclear@0
|
66
|
nuclear@0
|
67 friend class WaitConditionImpl;
|
nuclear@0
|
68
|
nuclear@0
|
69 public:
|
nuclear@0
|
70 // Constructor/destructor
|
nuclear@0
|
71 MutexImpl(Mutex* pmutex, bool recursive = 1);
|
nuclear@0
|
72 ~MutexImpl();
|
nuclear@0
|
73
|
nuclear@0
|
74 // Locking functions
|
nuclear@0
|
75 void DoLock();
|
nuclear@0
|
76 bool TryLock();
|
nuclear@0
|
77 void Unlock(Mutex* pmutex);
|
nuclear@0
|
78 // Returns 1 if the mutes is currently locked
|
nuclear@0
|
79 bool IsLockedByAnotherThread(Mutex* pmutex);
|
nuclear@0
|
80 bool IsSignaled() const;
|
nuclear@0
|
81 };
|
nuclear@0
|
82
|
nuclear@0
|
83 pthread_mutexattr_t Lock::RecursiveAttr;
|
nuclear@0
|
84 bool Lock::RecursiveAttrInit = 0;
|
nuclear@0
|
85
|
nuclear@0
|
86 // *** Constructor/destructor
|
nuclear@0
|
87 MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
|
nuclear@0
|
88 {
|
nuclear@0
|
89 OVR_UNUSED(pmutex);
|
nuclear@0
|
90 Recursive = recursive;
|
nuclear@0
|
91 LockCount = 0;
|
nuclear@0
|
92
|
nuclear@0
|
93 if (Recursive)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 if (!Lock::RecursiveAttrInit)
|
nuclear@0
|
96 {
|
nuclear@0
|
97 pthread_mutexattr_init(&Lock::RecursiveAttr);
|
nuclear@0
|
98 pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
|
nuclear@0
|
99 Lock::RecursiveAttrInit = 1;
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
|
nuclear@0
|
103 }
|
nuclear@0
|
104 else
|
nuclear@0
|
105 pthread_mutex_init(&SMutex, 0);
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 MutexImpl::~MutexImpl()
|
nuclear@0
|
109 {
|
nuclear@0
|
110 pthread_mutex_destroy(&SMutex);
|
nuclear@0
|
111 }
|
nuclear@0
|
112
|
nuclear@0
|
113
|
nuclear@0
|
114 // Lock and try lock
|
nuclear@0
|
115 void MutexImpl::DoLock()
|
nuclear@0
|
116 {
|
nuclear@0
|
117 while (pthread_mutex_lock(&SMutex))
|
nuclear@0
|
118 ;
|
nuclear@0
|
119 LockCount++;
|
nuclear@0
|
120 LockedBy = pthread_self();
|
nuclear@0
|
121 }
|
nuclear@0
|
122
|
nuclear@0
|
123 bool MutexImpl::TryLock()
|
nuclear@0
|
124 {
|
nuclear@0
|
125 if (!pthread_mutex_trylock(&SMutex))
|
nuclear@0
|
126 {
|
nuclear@0
|
127 LockCount++;
|
nuclear@0
|
128 LockedBy = pthread_self();
|
nuclear@0
|
129 return 1;
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132 return 0;
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 void MutexImpl::Unlock(Mutex* pmutex)
|
nuclear@0
|
136 {
|
nuclear@0
|
137 OVR_UNUSED(pmutex);
|
nuclear@0
|
138 OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
|
nuclear@0
|
139
|
nuclear@0
|
140 //unsigned lockCount;
|
nuclear@0
|
141 LockCount--;
|
nuclear@0
|
142 //lockCount = LockCount;
|
nuclear@0
|
143
|
nuclear@0
|
144 pthread_mutex_unlock(&SMutex);
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@0
|
147 bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
|
nuclear@0
|
148 {
|
nuclear@0
|
149 OVR_UNUSED(pmutex);
|
nuclear@0
|
150 // There could be multiple interpretations of IsLocked with respect to current thread
|
nuclear@0
|
151 if (LockCount == 0)
|
nuclear@0
|
152 return 0;
|
nuclear@0
|
153 if (pthread_self() != LockedBy)
|
nuclear@0
|
154 return 1;
|
nuclear@0
|
155 return 0;
|
nuclear@0
|
156 }
|
nuclear@0
|
157
|
nuclear@0
|
158 bool MutexImpl::IsSignaled() const
|
nuclear@0
|
159 {
|
nuclear@0
|
160 // An mutex is signaled if it is not locked ANYWHERE
|
nuclear@0
|
161 // Note that this is different from IsLockedByAnotherThread function,
|
nuclear@0
|
162 // that takes current thread into account
|
nuclear@0
|
163 return LockCount == 0;
|
nuclear@0
|
164 }
|
nuclear@0
|
165
|
nuclear@0
|
166
|
nuclear@0
|
167 // *** Actual Mutex class implementation
|
nuclear@0
|
168
|
nuclear@0
|
169 Mutex::Mutex(bool recursive)
|
nuclear@0
|
170 {
|
nuclear@0
|
171 // NOTE: RefCount mode already thread-safe for all waitables.
|
nuclear@0
|
172 pImpl = new MutexImpl(this, recursive);
|
nuclear@0
|
173 }
|
nuclear@0
|
174
|
nuclear@0
|
175 Mutex::~Mutex()
|
nuclear@0
|
176 {
|
nuclear@0
|
177 delete pImpl;
|
nuclear@0
|
178 }
|
nuclear@0
|
179
|
nuclear@0
|
180 // Lock and try lock
|
nuclear@0
|
181 void Mutex::DoLock()
|
nuclear@0
|
182 {
|
nuclear@0
|
183 pImpl->DoLock();
|
nuclear@0
|
184 }
|
nuclear@0
|
185 bool Mutex::TryLock()
|
nuclear@0
|
186 {
|
nuclear@0
|
187 return pImpl->TryLock();
|
nuclear@0
|
188 }
|
nuclear@0
|
189 void Mutex::Unlock()
|
nuclear@0
|
190 {
|
nuclear@0
|
191 pImpl->Unlock(this);
|
nuclear@0
|
192 }
|
nuclear@0
|
193 bool Mutex::IsLockedByAnotherThread()
|
nuclear@0
|
194 {
|
nuclear@0
|
195 return pImpl->IsLockedByAnotherThread(this);
|
nuclear@0
|
196 }
|
nuclear@0
|
197
|
nuclear@0
|
198
|
nuclear@0
|
199
|
nuclear@0
|
200 //-----------------------------------------------------------------------------------
|
nuclear@0
|
201 // ***** Event
|
nuclear@0
|
202
|
nuclear@0
|
203 bool Event::Wait(unsigned delay)
|
nuclear@0
|
204 {
|
nuclear@0
|
205 Mutex::Locker lock(&StateMutex);
|
nuclear@0
|
206
|
nuclear@0
|
207 // Do the correct amount of waiting
|
nuclear@0
|
208 if (delay == OVR_WAIT_INFINITE)
|
nuclear@0
|
209 {
|
nuclear@0
|
210 while(!State)
|
nuclear@0
|
211 StateWaitCondition.Wait(&StateMutex);
|
nuclear@0
|
212 }
|
nuclear@0
|
213 else if (delay)
|
nuclear@0
|
214 {
|
nuclear@0
|
215 if (!State)
|
nuclear@0
|
216 StateWaitCondition.Wait(&StateMutex, delay);
|
nuclear@0
|
217 }
|
nuclear@0
|
218
|
nuclear@0
|
219 bool state = State;
|
nuclear@0
|
220 // Take care of temporary 'pulsing' of a state
|
nuclear@0
|
221 if (Temporary)
|
nuclear@0
|
222 {
|
nuclear@0
|
223 Temporary = false;
|
nuclear@0
|
224 State = false;
|
nuclear@0
|
225 }
|
nuclear@0
|
226 return state;
|
nuclear@0
|
227 }
|
nuclear@0
|
228
|
nuclear@0
|
229 void Event::updateState(bool newState, bool newTemp, bool mustNotify)
|
nuclear@0
|
230 {
|
nuclear@0
|
231 Mutex::Locker lock(&StateMutex);
|
nuclear@0
|
232 State = newState;
|
nuclear@0
|
233 Temporary = newTemp;
|
nuclear@0
|
234 if (mustNotify)
|
nuclear@0
|
235 StateWaitCondition.NotifyAll();
|
nuclear@0
|
236 }
|
nuclear@0
|
237
|
nuclear@0
|
238
|
nuclear@0
|
239
|
nuclear@0
|
240 // ***** Wait Condition Implementation
|
nuclear@0
|
241
|
nuclear@0
|
242 // Internal implementation class
|
nuclear@0
|
243 class WaitConditionImpl : public NewOverrideBase
|
nuclear@0
|
244 {
|
nuclear@0
|
245 pthread_mutex_t SMutex;
|
nuclear@0
|
246 pthread_cond_t Condv;
|
nuclear@0
|
247
|
nuclear@0
|
248 public:
|
nuclear@0
|
249
|
nuclear@0
|
250 // Constructor/destructor
|
nuclear@0
|
251 WaitConditionImpl();
|
nuclear@0
|
252 ~WaitConditionImpl();
|
nuclear@0
|
253
|
nuclear@0
|
254 // Release mutex and wait for condition. The mutex is re-aqured after the wait.
|
nuclear@0
|
255 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
|
nuclear@0
|
256
|
nuclear@0
|
257 // Notify a condition, releasing at one object waiting
|
nuclear@0
|
258 void Notify();
|
nuclear@0
|
259 // Notify a condition, releasing all objects waiting
|
nuclear@0
|
260 void NotifyAll();
|
nuclear@0
|
261 };
|
nuclear@0
|
262
|
nuclear@0
|
263
|
nuclear@0
|
264 WaitConditionImpl::WaitConditionImpl()
|
nuclear@0
|
265 {
|
nuclear@0
|
266 pthread_mutex_init(&SMutex, 0);
|
nuclear@0
|
267 pthread_cond_init(&Condv, 0);
|
nuclear@0
|
268 }
|
nuclear@0
|
269
|
nuclear@0
|
270 WaitConditionImpl::~WaitConditionImpl()
|
nuclear@0
|
271 {
|
nuclear@0
|
272 pthread_mutex_destroy(&SMutex);
|
nuclear@0
|
273 pthread_cond_destroy(&Condv);
|
nuclear@0
|
274 }
|
nuclear@0
|
275
|
nuclear@0
|
276 bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
|
nuclear@0
|
277 {
|
nuclear@0
|
278 bool result = 1;
|
nuclear@0
|
279 unsigned lockCount = pmutex->pImpl->LockCount;
|
nuclear@0
|
280
|
nuclear@0
|
281 // Mutex must have been locked
|
nuclear@0
|
282 if (lockCount == 0)
|
nuclear@0
|
283 return 0;
|
nuclear@0
|
284
|
nuclear@0
|
285 pthread_mutex_lock(&SMutex);
|
nuclear@0
|
286
|
nuclear@0
|
287 // Finally, release a mutex or semaphore
|
nuclear@0
|
288 if (pmutex->pImpl->Recursive)
|
nuclear@0
|
289 {
|
nuclear@0
|
290 // Release the recursive mutex N times
|
nuclear@0
|
291 pmutex->pImpl->LockCount = 0;
|
nuclear@0
|
292 for(unsigned i=0; i<lockCount; i++)
|
nuclear@0
|
293 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
|
nuclear@0
|
294 }
|
nuclear@0
|
295 else
|
nuclear@0
|
296 {
|
nuclear@0
|
297 pmutex->pImpl->LockCount = 0;
|
nuclear@0
|
298 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
|
nuclear@0
|
299 }
|
nuclear@0
|
300
|
nuclear@0
|
301 // Note that there is a gap here between mutex.Unlock() and Wait().
|
nuclear@0
|
302 // The other mutex protects this gap.
|
nuclear@0
|
303
|
nuclear@0
|
304 if (delay == OVR_WAIT_INFINITE)
|
nuclear@0
|
305 pthread_cond_wait(&Condv,&SMutex);
|
nuclear@0
|
306 else
|
nuclear@0
|
307 {
|
nuclear@0
|
308 timespec ts;
|
nuclear@0
|
309
|
nuclear@0
|
310 struct timeval tv;
|
nuclear@0
|
311 gettimeofday(&tv, 0);
|
nuclear@0
|
312
|
nuclear@0
|
313 ts.tv_sec = tv.tv_sec + (delay / 1000);
|
nuclear@0
|
314 ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
|
nuclear@0
|
315
|
nuclear@0
|
316 if (ts.tv_nsec > 999999999)
|
nuclear@0
|
317 {
|
nuclear@0
|
318 ts.tv_sec++;
|
nuclear@0
|
319 ts.tv_nsec -= 1000000000;
|
nuclear@0
|
320 }
|
nuclear@0
|
321 int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
|
nuclear@0
|
322 OVR_ASSERT(r == 0 || r == ETIMEDOUT);
|
nuclear@0
|
323 if (r)
|
nuclear@0
|
324 result = 0;
|
nuclear@0
|
325 }
|
nuclear@0
|
326
|
nuclear@0
|
327 pthread_mutex_unlock(&SMutex);
|
nuclear@0
|
328
|
nuclear@0
|
329 // Re-aquire the mutex
|
nuclear@0
|
330 for(unsigned i=0; i<lockCount; i++)
|
nuclear@0
|
331 pmutex->DoLock();
|
nuclear@0
|
332
|
nuclear@0
|
333 // Return the result
|
nuclear@0
|
334 return result;
|
nuclear@0
|
335 }
|
nuclear@0
|
336
|
nuclear@0
|
337 // Notify a condition, releasing the least object in a queue
|
nuclear@0
|
338 void WaitConditionImpl::Notify()
|
nuclear@0
|
339 {
|
nuclear@0
|
340 pthread_mutex_lock(&SMutex);
|
nuclear@0
|
341 pthread_cond_signal(&Condv);
|
nuclear@0
|
342 pthread_mutex_unlock(&SMutex);
|
nuclear@0
|
343 }
|
nuclear@0
|
344
|
nuclear@0
|
345 // Notify a condition, releasing all objects waiting
|
nuclear@0
|
346 void WaitConditionImpl::NotifyAll()
|
nuclear@0
|
347 {
|
nuclear@0
|
348 pthread_mutex_lock(&SMutex);
|
nuclear@0
|
349 pthread_cond_broadcast(&Condv);
|
nuclear@0
|
350 pthread_mutex_unlock(&SMutex);
|
nuclear@0
|
351 }
|
nuclear@0
|
352
|
nuclear@0
|
353
|
nuclear@0
|
354
|
nuclear@0
|
355 // *** Actual implementation of WaitCondition
|
nuclear@0
|
356
|
nuclear@0
|
357 WaitCondition::WaitCondition()
|
nuclear@0
|
358 {
|
nuclear@0
|
359 pImpl = new WaitConditionImpl;
|
nuclear@0
|
360 }
|
nuclear@0
|
361 WaitCondition::~WaitCondition()
|
nuclear@0
|
362 {
|
nuclear@0
|
363 delete pImpl;
|
nuclear@0
|
364 }
|
nuclear@0
|
365
|
nuclear@0
|
366 bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
|
nuclear@0
|
367 {
|
nuclear@0
|
368 return pImpl->Wait(pmutex, delay);
|
nuclear@0
|
369 }
|
nuclear@0
|
370 // Notification
|
nuclear@0
|
371 void WaitCondition::Notify()
|
nuclear@0
|
372 {
|
nuclear@0
|
373 pImpl->Notify();
|
nuclear@0
|
374 }
|
nuclear@0
|
375 void WaitCondition::NotifyAll()
|
nuclear@0
|
376 {
|
nuclear@0
|
377 pImpl->NotifyAll();
|
nuclear@0
|
378 }
|
nuclear@0
|
379
|
nuclear@0
|
380
|
nuclear@0
|
381 // ***** Current thread
|
nuclear@0
|
382
|
nuclear@0
|
383 // Per-thread variable
|
nuclear@0
|
384 /*
|
nuclear@0
|
385 static __thread Thread* pCurrentThread = 0;
|
nuclear@0
|
386
|
nuclear@0
|
387 // Static function to return a pointer to the current thread
|
nuclear@0
|
388 void Thread::InitCurrentThread(Thread *pthread)
|
nuclear@0
|
389 {
|
nuclear@0
|
390 pCurrentThread = pthread;
|
nuclear@0
|
391 }
|
nuclear@0
|
392
|
nuclear@0
|
393 // Static function to return a pointer to the current thread
|
nuclear@0
|
394 Thread* Thread::GetThread()
|
nuclear@0
|
395 {
|
nuclear@0
|
396 return pCurrentThread;
|
nuclear@0
|
397 }
|
nuclear@0
|
398 */
|
nuclear@0
|
399
|
nuclear@0
|
400
|
nuclear@0
|
401 // *** Thread constructors.
|
nuclear@0
|
402
|
nuclear@0
|
403 Thread::Thread(UPInt stackSize, int processor)
|
nuclear@0
|
404 {
|
nuclear@0
|
405 // NOTE: RefCount mode already thread-safe for all Waitable objects.
|
nuclear@0
|
406 CreateParams params;
|
nuclear@0
|
407 params.stackSize = stackSize;
|
nuclear@0
|
408 params.processor = processor;
|
nuclear@0
|
409 Init(params);
|
nuclear@0
|
410 }
|
nuclear@0
|
411
|
nuclear@0
|
412 Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
|
nuclear@0
|
413 int processor, Thread::ThreadState initialState)
|
nuclear@0
|
414 {
|
nuclear@0
|
415 CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
|
nuclear@0
|
416 Init(params);
|
nuclear@0
|
417 }
|
nuclear@0
|
418
|
nuclear@0
|
419 Thread::Thread(const CreateParams& params)
|
nuclear@0
|
420 {
|
nuclear@0
|
421 Init(params);
|
nuclear@0
|
422 }
|
nuclear@0
|
423
|
nuclear@0
|
424 void Thread::Init(const CreateParams& params)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 // Clear the variables
|
nuclear@0
|
427 ThreadFlags = 0;
|
nuclear@0
|
428 ThreadHandle = 0;
|
nuclear@0
|
429 ExitCode = 0;
|
nuclear@0
|
430 SuspendCount = 0;
|
nuclear@0
|
431 StackSize = params.stackSize;
|
nuclear@0
|
432 Processor = params.processor;
|
nuclear@0
|
433 Priority = params.priority;
|
nuclear@0
|
434
|
nuclear@0
|
435 // Clear Function pointers
|
nuclear@0
|
436 ThreadFunction = params.threadFunction;
|
nuclear@0
|
437 UserHandle = params.userHandle;
|
nuclear@0
|
438 if (params.initialState != NotRunning)
|
nuclear@0
|
439 Start(params.initialState);
|
nuclear@0
|
440 }
|
nuclear@0
|
441
|
nuclear@0
|
442 Thread::~Thread()
|
nuclear@0
|
443 {
|
nuclear@0
|
444 // Thread should not running while object is being destroyed,
|
nuclear@0
|
445 // this would indicate ref-counting issue.
|
nuclear@0
|
446 //OVR_ASSERT(IsRunning() == 0);
|
nuclear@0
|
447
|
nuclear@0
|
448 // Clean up thread.
|
nuclear@0
|
449 ThreadHandle = 0;
|
nuclear@0
|
450 }
|
nuclear@0
|
451
|
nuclear@0
|
452
|
nuclear@0
|
453
|
nuclear@0
|
454 // *** Overridable User functions.
|
nuclear@0
|
455
|
nuclear@0
|
456 // Default Run implementation
|
nuclear@0
|
457 int Thread::Run()
|
nuclear@0
|
458 {
|
nuclear@0
|
459 // Call pointer to function, if available.
|
nuclear@0
|
460 return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
|
nuclear@0
|
461 }
|
nuclear@0
|
462 void Thread::OnExit()
|
nuclear@0
|
463 {
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466
|
nuclear@0
|
467 // Finishes the thread and releases internal reference to it.
|
nuclear@0
|
468 void Thread::FinishAndRelease()
|
nuclear@0
|
469 {
|
nuclear@0
|
470 // Note: thread must be US.
|
nuclear@0
|
471 ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
|
nuclear@0
|
472 ThreadFlags |= OVR_THREAD_FINISHED;
|
nuclear@0
|
473
|
nuclear@0
|
474 // Release our reference; this is equivalent to 'delete this'
|
nuclear@0
|
475 // from the point of view of our thread.
|
nuclear@0
|
476 Release();
|
nuclear@0
|
477 }
|
nuclear@0
|
478
|
nuclear@0
|
479
|
nuclear@0
|
480
|
nuclear@0
|
481 // *** ThreadList - used to track all created threads
|
nuclear@0
|
482
|
nuclear@0
|
483 class ThreadList : public NewOverrideBase
|
nuclear@0
|
484 {
|
nuclear@0
|
485 //------------------------------------------------------------------------
|
nuclear@0
|
486 struct ThreadHashOp
|
nuclear@0
|
487 {
|
nuclear@0
|
488 size_t operator()(const Thread* ptr)
|
nuclear@0
|
489 {
|
nuclear@0
|
490 return (((size_t)ptr) >> 6) ^ (size_t)ptr;
|
nuclear@0
|
491 }
|
nuclear@0
|
492 };
|
nuclear@0
|
493
|
nuclear@0
|
494 HashSet<Thread*, ThreadHashOp> ThreadSet;
|
nuclear@0
|
495 Mutex ThreadMutex;
|
nuclear@0
|
496 WaitCondition ThreadsEmpty;
|
nuclear@0
|
497 // Track the root thread that created us.
|
nuclear@0
|
498 pthread_t RootThreadId;
|
nuclear@0
|
499
|
nuclear@0
|
500 static ThreadList* volatile pRunningThreads;
|
nuclear@0
|
501
|
nuclear@0
|
502 void addThread(Thread *pthread)
|
nuclear@0
|
503 {
|
nuclear@0
|
504 Mutex::Locker lock(&ThreadMutex);
|
nuclear@0
|
505 ThreadSet.Add(pthread);
|
nuclear@0
|
506 }
|
nuclear@0
|
507
|
nuclear@0
|
508 void removeThread(Thread *pthread)
|
nuclear@0
|
509 {
|
nuclear@0
|
510 Mutex::Locker lock(&ThreadMutex);
|
nuclear@0
|
511 ThreadSet.Remove(pthread);
|
nuclear@0
|
512 if (ThreadSet.GetSize() == 0)
|
nuclear@0
|
513 ThreadsEmpty.Notify();
|
nuclear@0
|
514 }
|
nuclear@0
|
515
|
nuclear@0
|
516 void finishAllThreads()
|
nuclear@0
|
517 {
|
nuclear@0
|
518 // Only original root thread can call this.
|
nuclear@0
|
519 OVR_ASSERT(pthread_self() == RootThreadId);
|
nuclear@0
|
520
|
nuclear@0
|
521 Mutex::Locker lock(&ThreadMutex);
|
nuclear@0
|
522 while (ThreadSet.GetSize() != 0)
|
nuclear@0
|
523 ThreadsEmpty.Wait(&ThreadMutex);
|
nuclear@0
|
524 }
|
nuclear@0
|
525
|
nuclear@0
|
526 public:
|
nuclear@0
|
527
|
nuclear@0
|
528 ThreadList()
|
nuclear@0
|
529 {
|
nuclear@0
|
530 RootThreadId = pthread_self();
|
nuclear@0
|
531 }
|
nuclear@0
|
532 ~ThreadList() { }
|
nuclear@0
|
533
|
nuclear@0
|
534
|
nuclear@0
|
535 static void AddRunningThread(Thread *pthread)
|
nuclear@0
|
536 {
|
nuclear@0
|
537 // Non-atomic creation ok since only the root thread
|
nuclear@0
|
538 if (!pRunningThreads)
|
nuclear@0
|
539 {
|
nuclear@0
|
540 pRunningThreads = new ThreadList;
|
nuclear@0
|
541 OVR_ASSERT(pRunningThreads);
|
nuclear@0
|
542 }
|
nuclear@0
|
543 pRunningThreads->addThread(pthread);
|
nuclear@0
|
544 }
|
nuclear@0
|
545
|
nuclear@0
|
546 // NOTE: 'pthread' might be a dead pointer when this is
|
nuclear@0
|
547 // called so it should not be accessed; it is only used
|
nuclear@0
|
548 // for removal.
|
nuclear@0
|
549 static void RemoveRunningThread(Thread *pthread)
|
nuclear@0
|
550 {
|
nuclear@0
|
551 OVR_ASSERT(pRunningThreads);
|
nuclear@0
|
552 pRunningThreads->removeThread(pthread);
|
nuclear@0
|
553 }
|
nuclear@0
|
554
|
nuclear@0
|
555 static void FinishAllThreads()
|
nuclear@0
|
556 {
|
nuclear@0
|
557 // This is ok because only root thread can wait for other thread finish.
|
nuclear@0
|
558 if (pRunningThreads)
|
nuclear@0
|
559 {
|
nuclear@0
|
560 pRunningThreads->finishAllThreads();
|
nuclear@0
|
561 delete pRunningThreads;
|
nuclear@0
|
562 pRunningThreads = 0;
|
nuclear@0
|
563 }
|
nuclear@0
|
564 }
|
nuclear@0
|
565 };
|
nuclear@0
|
566
|
nuclear@0
|
567 // By default, we have no thread list.
|
nuclear@0
|
568 ThreadList* volatile ThreadList::pRunningThreads = 0;
|
nuclear@0
|
569
|
nuclear@0
|
570
|
nuclear@0
|
571 // FinishAllThreads - exposed publicly in Thread.
|
nuclear@0
|
572 void Thread::FinishAllThreads()
|
nuclear@0
|
573 {
|
nuclear@0
|
574 ThreadList::FinishAllThreads();
|
nuclear@0
|
575 }
|
nuclear@0
|
576
|
nuclear@0
|
577 // *** Run override
|
nuclear@0
|
578
|
nuclear@0
|
579 int Thread::PRun()
|
nuclear@0
|
580 {
|
nuclear@0
|
581 // Suspend us on start, if requested
|
nuclear@0
|
582 if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
|
nuclear@0
|
583 {
|
nuclear@0
|
584 Suspend();
|
nuclear@0
|
585 ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
|
nuclear@0
|
586 }
|
nuclear@0
|
587
|
nuclear@0
|
588 // Call the virtual run function
|
nuclear@0
|
589 ExitCode = Run();
|
nuclear@0
|
590 return ExitCode;
|
nuclear@0
|
591 }
|
nuclear@0
|
592
|
nuclear@0
|
593
|
nuclear@0
|
594
|
nuclear@0
|
595
|
nuclear@0
|
596 // *** User overridables
|
nuclear@0
|
597
|
nuclear@0
|
598 bool Thread::GetExitFlag() const
|
nuclear@0
|
599 {
|
nuclear@0
|
600 return (ThreadFlags & OVR_THREAD_EXIT) != 0;
|
nuclear@0
|
601 }
|
nuclear@0
|
602
|
nuclear@0
|
603 void Thread::SetExitFlag(bool exitFlag)
|
nuclear@0
|
604 {
|
nuclear@0
|
605 // The below is atomic since ThreadFlags is AtomicInt.
|
nuclear@0
|
606 if (exitFlag)
|
nuclear@0
|
607 ThreadFlags |= OVR_THREAD_EXIT;
|
nuclear@0
|
608 else
|
nuclear@0
|
609 ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
|
nuclear@0
|
610 }
|
nuclear@0
|
611
|
nuclear@0
|
612
|
nuclear@0
|
613 // Determines whether the thread was running and is now finished
|
nuclear@0
|
614 bool Thread::IsFinished() const
|
nuclear@0
|
615 {
|
nuclear@0
|
616 return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
|
nuclear@0
|
617 }
|
nuclear@0
|
618 // Determines whether the thread is suspended
|
nuclear@0
|
619 bool Thread::IsSuspended() const
|
nuclear@0
|
620 {
|
nuclear@0
|
621 return SuspendCount > 0;
|
nuclear@0
|
622 }
|
nuclear@0
|
623 // Returns current thread state
|
nuclear@0
|
624 Thread::ThreadState Thread::GetThreadState() const
|
nuclear@0
|
625 {
|
nuclear@0
|
626 if (IsSuspended())
|
nuclear@0
|
627 return Suspended;
|
nuclear@0
|
628 if (ThreadFlags & OVR_THREAD_STARTED)
|
nuclear@0
|
629 return Running;
|
nuclear@0
|
630 return NotRunning;
|
nuclear@0
|
631 }
|
nuclear@0
|
632
|
nuclear@0
|
633 // Join thread
|
nuclear@0
|
634 bool Thread::Join(int maxWaitMs) const
|
nuclear@0
|
635 {
|
nuclear@0
|
636 // If polling,
|
nuclear@0
|
637 if (maxWaitMs == 0)
|
nuclear@0
|
638 {
|
nuclear@0
|
639 // Just return if finished
|
nuclear@0
|
640 return IsFinished();
|
nuclear@0
|
641 }
|
nuclear@0
|
642 // If waiting forever,
|
nuclear@0
|
643 else if (maxWaitMs > 0)
|
nuclear@0
|
644 {
|
nuclear@0
|
645 UInt32 t0 = Timer::GetTicksMs();
|
nuclear@0
|
646
|
nuclear@0
|
647 while (!IsFinished())
|
nuclear@0
|
648 {
|
nuclear@0
|
649 UInt32 t1 = Timer::GetTicksMs();
|
nuclear@0
|
650
|
nuclear@0
|
651 // If the wait has expired,
|
nuclear@0
|
652 int delta = (int)(t1 - t0);
|
nuclear@0
|
653 if (delta >= maxWaitMs)
|
nuclear@0
|
654 {
|
nuclear@0
|
655 return false;
|
nuclear@0
|
656 }
|
nuclear@0
|
657
|
nuclear@0
|
658 Thread::MSleep(10);
|
nuclear@0
|
659 }
|
nuclear@0
|
660
|
nuclear@0
|
661 return true;
|
nuclear@0
|
662 }
|
nuclear@0
|
663 else
|
nuclear@0
|
664 {
|
nuclear@0
|
665 while (!IsFinished())
|
nuclear@0
|
666 {
|
nuclear@0
|
667 pthread_join(ThreadHandle, NULL);
|
nuclear@0
|
668 }
|
nuclear@0
|
669 }
|
nuclear@0
|
670
|
nuclear@0
|
671 return true;
|
nuclear@0
|
672 }
|
nuclear@0
|
673
|
nuclear@0
|
674 /*
|
nuclear@0
|
675 static const char* mapsched_policy(int policy)
|
nuclear@0
|
676 {
|
nuclear@0
|
677 switch(policy)
|
nuclear@0
|
678 {
|
nuclear@0
|
679 case SCHED_OTHER:
|
nuclear@0
|
680 return "SCHED_OTHER";
|
nuclear@0
|
681 case SCHED_RR:
|
nuclear@0
|
682 return "SCHED_RR";
|
nuclear@0
|
683 case SCHED_FIFO:
|
nuclear@0
|
684 return "SCHED_FIFO";
|
nuclear@0
|
685
|
nuclear@0
|
686 }
|
nuclear@0
|
687 return "UNKNOWN";
|
nuclear@0
|
688 }
|
nuclear@0
|
689 int policy;
|
nuclear@0
|
690 sched_param sparam;
|
nuclear@0
|
691 pthread_getschedparam(pthread_self(), &policy, &sparam);
|
nuclear@0
|
692 int max_prior = sched_get_priority_max(policy);
|
nuclear@0
|
693 int min_prior = sched_get_priority_min(policy);
|
nuclear@0
|
694 printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
|
nuclear@0
|
695 #include <stdio.h>
|
nuclear@0
|
696 */
|
nuclear@0
|
697 // ***** Thread management
|
nuclear@0
|
698
|
nuclear@0
|
699 // The actual first function called on thread start
|
nuclear@0
|
700 void* Thread_PthreadStartFn(void* phandle)
|
nuclear@0
|
701 {
|
nuclear@0
|
702 Thread* pthread = (Thread*)phandle;
|
nuclear@0
|
703 int result = pthread->PRun();
|
nuclear@0
|
704 // Signal the thread as done and release it atomically.
|
nuclear@0
|
705 pthread->FinishAndRelease();
|
nuclear@0
|
706 // At this point Thread object might be dead; however we can still pass
|
nuclear@0
|
707 // it to RemoveRunningThread since it is only used as a key there.
|
nuclear@0
|
708 ThreadList::RemoveRunningThread(pthread);
|
nuclear@0
|
709 return reinterpret_cast<void*>(result);
|
nuclear@0
|
710 }
|
nuclear@0
|
711
|
nuclear@0
|
712 int Thread::InitAttr = 0;
|
nuclear@0
|
713 pthread_attr_t Thread::Attr;
|
nuclear@0
|
714
|
nuclear@0
|
715 /* static */
|
nuclear@0
|
716 int Thread::GetOSPriority(ThreadPriority p)
|
nuclear@0
|
717 {
|
nuclear@0
|
718 OVR_UNUSED(p);
|
nuclear@0
|
719 return -1;
|
nuclear@0
|
720 }
|
nuclear@0
|
721
|
nuclear@0
|
722 /* static */
|
nuclear@0
|
723 Thread::ThreadPriority Thread::GetOVRPriority(int osPriority)
|
nuclear@0
|
724 {
|
nuclear@0
|
725 #if defined(OVR_OS_LINUX)
|
nuclear@0
|
726 return (ThreadPriority)(Thread::NormalPriority - osPriority); // This works for both SCHED_OTHER, SCHED_RR, and SCHED_FIFO.
|
nuclear@0
|
727 #else
|
nuclear@0
|
728 // Apple priorities are such that the min is a value less than the max.
|
nuclear@0
|
729 static int minPriority = sched_get_priority_min(SCHED_FIFO); // We don't have a means to pass a policy type to this function.
|
nuclear@0
|
730 static int maxPriority = sched_get_priority_max(SCHED_FIFO);
|
nuclear@0
|
731
|
nuclear@0
|
732 return (ThreadPriority)(Thread::NormalPriority - (osPriority - ((minPriority + maxPriority) / 2)));
|
nuclear@0
|
733 #endif
|
nuclear@0
|
734 }
|
nuclear@0
|
735
|
nuclear@0
|
736
|
nuclear@0
|
737 Thread::ThreadPriority Thread::GetPriority()
|
nuclear@0
|
738 {
|
nuclear@0
|
739 int policy;
|
nuclear@0
|
740 sched_param param;
|
nuclear@0
|
741
|
nuclear@0
|
742 int result = pthread_getschedparam(ThreadHandle, &policy, ¶m);
|
nuclear@0
|
743
|
nuclear@0
|
744 if(result == 0)
|
nuclear@0
|
745 {
|
nuclear@0
|
746 #if !defined(OVR_OS_LINUX)
|
nuclear@0
|
747 if(policy == SCHED_OTHER)
|
nuclear@0
|
748 {
|
nuclear@0
|
749 return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X.
|
nuclear@0
|
750 }
|
nuclear@0
|
751 #endif
|
nuclear@0
|
752
|
nuclear@0
|
753 return GetOVRPriority(param.sched_priority);
|
nuclear@0
|
754 }
|
nuclear@0
|
755
|
nuclear@0
|
756 return Thread::NormalPriority;
|
nuclear@0
|
757 }
|
nuclear@0
|
758
|
nuclear@0
|
759 /* static */
|
nuclear@0
|
760 Thread::ThreadPriority Thread::GetCurrentPriority()
|
nuclear@0
|
761 {
|
nuclear@0
|
762 int policy;
|
nuclear@0
|
763 sched_param param;
|
nuclear@0
|
764 pthread_t currentThreadId = pthread_self();
|
nuclear@0
|
765
|
nuclear@0
|
766 int result = pthread_getschedparam(currentThreadId, &policy, ¶m);
|
nuclear@0
|
767
|
nuclear@0
|
768 if(result == 0)
|
nuclear@0
|
769 {
|
nuclear@0
|
770 #if !defined(OVR_OS_LINUX)
|
nuclear@0
|
771 if(policy == SCHED_OTHER)
|
nuclear@0
|
772 {
|
nuclear@0
|
773 return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X.
|
nuclear@0
|
774 }
|
nuclear@0
|
775 #endif
|
nuclear@0
|
776
|
nuclear@0
|
777 return GetOVRPriority(param.sched_priority);
|
nuclear@0
|
778 }
|
nuclear@0
|
779
|
nuclear@0
|
780 return Thread::NormalPriority;
|
nuclear@0
|
781 }
|
nuclear@0
|
782
|
nuclear@0
|
783
|
nuclear@0
|
784 bool Thread::SetPriority(ThreadPriority)
|
nuclear@0
|
785 {
|
nuclear@0
|
786 // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam
|
nuclear@0
|
787 // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges.
|
nuclear@0
|
788 return false;
|
nuclear@0
|
789 }
|
nuclear@0
|
790
|
nuclear@0
|
791 /* static */
|
nuclear@0
|
792 bool Thread::SetCurrentPriority(ThreadPriority)
|
nuclear@0
|
793 {
|
nuclear@0
|
794 // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam
|
nuclear@0
|
795 // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges.
|
nuclear@0
|
796 return false;
|
nuclear@0
|
797 }
|
nuclear@0
|
798
|
nuclear@0
|
799 bool Thread::Start(ThreadState initialState)
|
nuclear@0
|
800 {
|
nuclear@0
|
801 if (initialState == NotRunning)
|
nuclear@0
|
802 return 0;
|
nuclear@0
|
803 if (GetThreadState() != NotRunning)
|
nuclear@0
|
804 {
|
nuclear@0
|
805 OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
|
nuclear@0
|
806 return 0;
|
nuclear@0
|
807 }
|
nuclear@0
|
808
|
nuclear@0
|
809 if (!InitAttr)
|
nuclear@0
|
810 {
|
nuclear@0
|
811 pthread_attr_init(&Attr);
|
nuclear@0
|
812 pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
|
nuclear@0
|
813 pthread_attr_setstacksize(&Attr, 128 * 1024);
|
nuclear@0
|
814 sched_param sparam;
|
nuclear@0
|
815 sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
|
nuclear@0
|
816 pthread_attr_setschedparam(&Attr, &sparam);
|
nuclear@0
|
817 InitAttr = 1;
|
nuclear@0
|
818 }
|
nuclear@0
|
819
|
nuclear@0
|
820 ExitCode = 0;
|
nuclear@0
|
821 SuspendCount = 0;
|
nuclear@0
|
822 ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
|
nuclear@0
|
823
|
nuclear@0
|
824 // AddRef to us until the thread is finished
|
nuclear@0
|
825 AddRef();
|
nuclear@0
|
826 ThreadList::AddRunningThread(this);
|
nuclear@0
|
827
|
nuclear@0
|
828 int result;
|
nuclear@0
|
829 if (StackSize != 128 * 1024 || Priority != NormalPriority)
|
nuclear@0
|
830 {
|
nuclear@0
|
831 pthread_attr_t attr;
|
nuclear@0
|
832
|
nuclear@0
|
833 pthread_attr_init(&attr);
|
nuclear@0
|
834 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
nuclear@0
|
835 pthread_attr_setstacksize(&attr, StackSize);
|
nuclear@0
|
836 sched_param sparam;
|
nuclear@0
|
837 sparam.sched_priority = Thread::GetOSPriority(Priority);
|
nuclear@0
|
838 pthread_attr_setschedparam(&attr, &sparam);
|
nuclear@0
|
839 result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
|
nuclear@0
|
840 pthread_attr_destroy(&attr);
|
nuclear@0
|
841 }
|
nuclear@0
|
842 else
|
nuclear@0
|
843 result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
|
nuclear@0
|
844
|
nuclear@0
|
845 if (result)
|
nuclear@0
|
846 {
|
nuclear@0
|
847 ThreadFlags = 0;
|
nuclear@0
|
848 Release();
|
nuclear@0
|
849 ThreadList::RemoveRunningThread(this);
|
nuclear@0
|
850 return 0;
|
nuclear@0
|
851 }
|
nuclear@0
|
852 return 1;
|
nuclear@0
|
853 }
|
nuclear@0
|
854
|
nuclear@0
|
855
|
nuclear@0
|
856 // Suspend the thread until resumed
|
nuclear@0
|
857 bool Thread::Suspend()
|
nuclear@0
|
858 {
|
nuclear@0
|
859 OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
|
nuclear@0
|
860 return 0;
|
nuclear@0
|
861 }
|
nuclear@0
|
862
|
nuclear@0
|
863 // Resumes currently suspended thread
|
nuclear@0
|
864 bool Thread::Resume()
|
nuclear@0
|
865 {
|
nuclear@0
|
866 return 0;
|
nuclear@0
|
867 }
|
nuclear@0
|
868
|
nuclear@0
|
869
|
nuclear@0
|
870 // Quits with an exit code
|
nuclear@0
|
871 void Thread::Exit(int exitCode)
|
nuclear@0
|
872 {
|
nuclear@0
|
873 // Can only exist the current thread
|
nuclear@0
|
874 // if (GetThread() != this)
|
nuclear@0
|
875 // return;
|
nuclear@0
|
876
|
nuclear@0
|
877 // Call the virtual OnExit function
|
nuclear@0
|
878 OnExit();
|
nuclear@0
|
879
|
nuclear@0
|
880 // Signal this thread object as done and release it's references.
|
nuclear@0
|
881 FinishAndRelease();
|
nuclear@0
|
882 ThreadList::RemoveRunningThread(this);
|
nuclear@0
|
883
|
nuclear@0
|
884 pthread_exit(reinterpret_cast<void*>(exitCode));
|
nuclear@0
|
885 }
|
nuclear@0
|
886
|
nuclear@0
|
887 ThreadId GetCurrentThreadId()
|
nuclear@0
|
888 {
|
nuclear@0
|
889 return (void*)pthread_self();
|
nuclear@0
|
890 }
|
nuclear@0
|
891
|
nuclear@0
|
892 // *** Sleep functions
|
nuclear@0
|
893
|
nuclear@0
|
894 /* static */
|
nuclear@0
|
895 bool Thread::Sleep(unsigned secs)
|
nuclear@0
|
896 {
|
nuclear@0
|
897 sleep(secs);
|
nuclear@0
|
898 return 1;
|
nuclear@0
|
899 }
|
nuclear@0
|
900 /* static */
|
nuclear@0
|
901 bool Thread::MSleep(unsigned msecs)
|
nuclear@0
|
902 {
|
nuclear@0
|
903 usleep(msecs*1000);
|
nuclear@0
|
904 return 1;
|
nuclear@0
|
905 }
|
nuclear@0
|
906
|
nuclear@0
|
907 /* static */
|
nuclear@0
|
908 int Thread::GetCPUCount()
|
nuclear@0
|
909 {
|
nuclear@0
|
910 #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD)
|
nuclear@0
|
911 // http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/sysctlbyname.3.html
|
nuclear@0
|
912 int cpuCount = 0;
|
nuclear@0
|
913 size_t len = sizeof(cpuCount);
|
nuclear@0
|
914
|
nuclear@0
|
915 if(sysctlbyname("hw.logicalcpu", &cpuCount, &len, NULL, 0) != 0)
|
nuclear@0
|
916 cpuCount = 1;
|
nuclear@0
|
917
|
nuclear@0
|
918 return cpuCount;
|
nuclear@0
|
919
|
nuclear@0
|
920 #else // Linux, Android
|
nuclear@0
|
921
|
nuclear@0
|
922 // Alternative: read /proc/cpuinfo
|
nuclear@0
|
923 #ifdef _SC_NPROCESSORS_ONLN
|
nuclear@0
|
924 return (int)sysconf(_SC_NPROCESSORS_ONLN);
|
nuclear@0
|
925 #else
|
nuclear@0
|
926 return 1;
|
nuclear@0
|
927 #endif
|
nuclear@0
|
928 #endif
|
nuclear@0
|
929 }
|
nuclear@0
|
930
|
nuclear@0
|
931
|
nuclear@0
|
932 void Thread::SetThreadName( const char* name )
|
nuclear@0
|
933 {
|
nuclear@0
|
934 #if defined (OVR_OS_APPLE)
|
nuclear@0
|
935 if(ThreadHandle == pthread_self())
|
nuclear@0
|
936 pthread_setname_np(name);
|
nuclear@0
|
937 // Else there's nothing we can do.
|
nuclear@0
|
938 #else
|
nuclear@0
|
939 if(ThreadHandle != 0)
|
nuclear@0
|
940 pthread_setname_np(ThreadHandle, name);
|
nuclear@0
|
941 // Else we can possibly save this name and set it later when the thread starts.
|
nuclear@0
|
942 #endif
|
nuclear@0
|
943 }
|
nuclear@0
|
944
|
nuclear@0
|
945
|
nuclear@0
|
946 void Thread::SetThreadName(const char* name, ThreadId threadId)
|
nuclear@0
|
947 {
|
nuclear@0
|
948 #if defined (OVR_OS_APPLE)
|
nuclear@0
|
949 if(pthread_equal((pthread_t)threadId, pthread_self()))
|
nuclear@0
|
950 pthread_setname_np(name);
|
nuclear@0
|
951 // Else there's no way to set the name of another thread.
|
nuclear@0
|
952 #else
|
nuclear@0
|
953 pthread_setname_np((pthread_t)threadId, name);
|
nuclear@0
|
954 #endif
|
nuclear@0
|
955 }
|
nuclear@0
|
956
|
nuclear@0
|
957
|
nuclear@0
|
958 void Thread::SetCurrentThreadName(const char* name)
|
nuclear@0
|
959 {
|
nuclear@0
|
960 #if defined (OVR_OS_APPLE)
|
nuclear@0
|
961 pthread_setname_np(name);
|
nuclear@0
|
962 #else
|
nuclear@0
|
963 pthread_setname_np(pthread_self(), name);
|
nuclear@0
|
964 #endif
|
nuclear@0
|
965 }
|
nuclear@0
|
966
|
nuclear@0
|
967
|
nuclear@0
|
968 void Thread::GetThreadName(char* name, size_t nameCapacity, ThreadId threadId)
|
nuclear@0
|
969 {
|
nuclear@0
|
970 name[0] = 0;
|
nuclear@0
|
971 pthread_getname_np((pthread_t)threadId, name, nameCapacity);
|
nuclear@0
|
972 }
|
nuclear@0
|
973
|
nuclear@0
|
974
|
nuclear@0
|
975 void Thread::GetCurrentThreadName(char* name, size_t nameCapacity)
|
nuclear@0
|
976 {
|
nuclear@0
|
977 name[0] = 0;
|
nuclear@0
|
978 pthread_getname_np(pthread_self(), name, nameCapacity);
|
nuclear@0
|
979 }
|
nuclear@0
|
980
|
nuclear@0
|
981
|
nuclear@0
|
982 } // namespace OVR
|
nuclear@0
|
983
|
nuclear@0
|
984 #endif // OVR_ENABLE_THREADS
|