vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Thread.C
Go to the documentation of this file.
1
12// Copyright 2015 Sensics, Inc.
13// Distributed under the Boost Software License, Version 1.0.
14// (See accompanying file LICENSE_1_0.txt or copy at
15// http://www.boost.org/LICENSE_1_0.txt)
16
17// Internal Includes
18#include "vrpn_Thread.h"
19#include "vrpn_Shared.h"
20
21// Library/third-party includes
22// - none
23
24// Standard includes
25#include <stdio.h> // for fprintf, stderr, perror, etc
26#include <string.h> // for memcpy, strlen, strcpy, etc
27#ifndef _WIN32
28#include <errno.h> // for EAGAIN, errno
29#include <signal.h> // for pthread_kill, SIGKILL
30#endif
31
32#ifdef __APPLE__
33#include <unistd.h>
34#endif
35
36#define ALL_ASSERT(exp, msg) \
37 if (!(exp)) { \
38 fprintf(stderr, "\nAssertion failed! \n %s (%s, %d)\n", msg, __FILE__, \
39 __LINE__); \
40 }
41
42// init all fields in init()
44 : cResources(cNumResources)
45{
46 init();
47}
48
49#ifdef sgi
50bool vrpn_Semaphore::init()
51{
52 if (vrpn_Semaphore::ppaArena == NULL) {
53 vrpn_Semaphore::allocArena();
54 }
55 if (cResources == 1) {
56 fUsingLock = true;
57 ps = NULL;
58 // use lock instead of semaphore
59 if ((l = usnewlock(vrpn_Semaphore::ppaArena)) == NULL) {
60 fprintf(stderr, "vrpn_Semaphore::vrpn_Semaphore: error allocating "
61 "lock from arena.\n");
62 return false;
63 }
64 }
65 else {
66 fUsingLock = false;
67 l = NULL;
68 if ((ps = usnewsema(vrpn_Semaphore::ppaArena, cResources)) == NULL) {
69 fprintf(stderr, "vrpn_Semaphore::vrpn_Semaphore: error allocating "
70 "semaphore from arena.\n");
71 return false;
72 }
73 }
74 return true;
75}
76#elif defined(_WIN32)
77bool vrpn_Semaphore::init()
78{
79 // args are security, initial count, max count, and name
80 // TCH 20 Feb 2001 - Make the PC behavior closer to the SGI behavior.
81 int numMax = cResources;
82 if (numMax < 1) {
83 numMax = 1;
84 }
85 hSemaphore = CreateSemaphore(NULL, cResources, numMax, NULL);
86 if (!hSemaphore) {
87 // get error info from windows (from FormatMessage help page)
88 LPVOID lpMsgBuf;
89
90 FormatMessage(
91 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
92 GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
93 // Default language
94 (LPTSTR)&lpMsgBuf, 0, NULL);
95 fprintf(stderr,
96 "vrpn_Semaphore::vrpn_Semaphore: error creating semaphore, "
97 "WIN32 CreateSemaphore call caused the following error: %s\n",
98 (LPTSTR)lpMsgBuf);
99 // Free the buffer.
100 LocalFree(lpMsgBuf);
101 return false;
102 }
103 return true;
104}
105#elif defined(__APPLE__)
106bool vrpn_Semaphore::init()
107{
108 // We need to use sem_open on the mac because sem_init is not implemented
109 int numMax = cResources;
110 if (numMax < 1) {
111 numMax = 1;
112 }
113 char tempname[100];
114 sprintf(tempname, "/tmp/vrpn_sem.XXXXXXX");
115 semaphore = sem_open(mktemp(tempname), O_CREAT, 0600, numMax);
116 if (semaphore == SEM_FAILED) {
117 perror("vrpn_Semaphore::vrpn_Semaphore: error opening semaphore");
118 return false;
119 }
120 return true;
121}
122#else
123
124bool vrpn_Semaphore::init()
125{
126 // Posix threads are the default.
127 // We use sem_init on linux (instead of sem_open).
128 int numMax = cResources;
129 if (numMax < 1) {
130 numMax = 1;
131 }
132 try { semaphore = new sem_t; }
133 catch (...) { return false; }
134 if (sem_init(semaphore, 0, numMax) != 0) {
135 perror("vrpn_Semaphore::vrpn_Semaphore: error initializing semaphore");
136 return false;
137 }
138 return true;
139}
140#endif
141
142#ifdef sgi
143bool vrpn_Semaphore::destroy()
144{
145 if (fUsingLock) {
146 usfreelock(l, vrpn_Semaphore::ppaArena);
147 }
148 else {
149 usfreesema(ps, vrpn_Semaphore::ppaArena);
150 }
151 return true;
152}
153#elif defined(_WIN32)
154bool vrpn_Semaphore::destroy()
155{
156 if (!CloseHandle(hSemaphore)) {
157 // get error info from windows (from FormatMessage help page)
158 LPVOID lpMsgBuf;
159
160 FormatMessage(
161 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
162 GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
163 // Default language
164 (LPTSTR)&lpMsgBuf, 0, NULL);
165 fprintf(stderr,
166 "vrpn_Semaphore::destroy: error destroying semaphore, "
167 "WIN32 CloseHandle call caused the following error: %s\n",
168 (LPTSTR)lpMsgBuf);
169 // Free the buffer.
170 LocalFree(lpMsgBuf);
171 return false;
172 }
173 return true;
174 }
175#else
176bool vrpn_Semaphore::destroy()
177{
178 // Posix threads are the default.
179#ifdef __APPLE__
180 if (sem_close(semaphore) != 0) {
181 perror("vrpn_Semaphore::destroy: error destroying semaphore.");
182 return false;
183 }
184#else
185 if (sem_destroy(semaphore) != 0) {
186 fprintf(stderr,
187 "vrpn_Semaphore::destroy: error destroying semaphore.\n");
188 return false;
189 }
190 try {
191 delete semaphore;
192 } catch (...) {
193 fprintf(stderr, "vrpn_Semaphore::destroy(): delete failed\n");
194 return false;
195 }
196#endif
197 semaphore = NULL;
198 return true;
199}
200#endif
201
203{
204 if (!destroy()) {
205 fprintf(
206 stderr,
207 "vrpn_Semaphore::~vrpn_Semaphore: error destroying semaphore.\n");
208 }
209}
210
211// routine to reset it
212bool vrpn_Semaphore::reset(int cNumResources)
213{
214 cResources = cNumResources;
215
216 // Destroy the old semaphore and then create a new one with the correct
217 // value.
218 if (!destroy()) {
219 fprintf(stderr, "vrpn_Semaphore::reset: error destroying semaphore.\n");
220 return false;
221 }
222 if (!init()) {
223 fprintf(stderr,
224 "vrpn_Semaphore::reset: error initializing semaphore.\n");
225 return false;
226 }
227 return true;
228}
229
230// routines to use it (p blocks, cond p does not)
231// 1 on success, -1 fail
233{
234#ifdef sgi
235 if (fUsingLock) {
236 if (ussetlock(l) != 1) {
237 perror("vrpn_Semaphore::p: ussetlock:");
238 return -1;
239 }
240 }
241 else {
242 if (uspsema(ps) != 1) {
243 perror("vrpn_Semaphore::p: uspsema:");
244 return -1;
245 }
246 }
247#elif defined(_WIN32)
248 switch (WaitForSingleObject(hSemaphore, INFINITE)) {
249 case WAIT_OBJECT_0:
250 // got the resource
251 break;
252 case WAIT_TIMEOUT:
253 ALL_ASSERT(0, "vrpn_Semaphore::p: infinite wait time timed out!");
254 return -1;
255 break;
256 case WAIT_ABANDONED:
257 ALL_ASSERT(0, "vrpn_Semaphore::p: thread holding resource died");
258 return -1;
259 break;
260 case WAIT_FAILED:
261 // get error info from windows (from FormatMessage help page)
262 LPVOID lpMsgBuf;
263
264 FormatMessage(
265 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
266 GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
267 // Default language
268 (LPTSTR)&lpMsgBuf, 0, NULL);
269 fprintf(stderr,
270 "vrpn_Semaphore::p: error waiting for resource, "
271 "WIN32 WaitForSingleObject call caused the following error: %s",
272 (LPTSTR)lpMsgBuf);
273 // Free the buffer.
274 LocalFree(lpMsgBuf);
275 return -1;
276 break;
277 default:
278 ALL_ASSERT(0, "vrpn_Semaphore::p: unknown return code");
279 return -1;
280 }
281#else
282 // Posix by default
283 if (sem_wait(semaphore) != 0) {
284 perror("vrpn_Semaphore::p: ");
285 return -1;
286 }
287#endif
288 return 1;
289}
290
291// 0 on success, -1 fail
293{
294#ifdef sgi
295 if (fUsingLock) {
296 if (usunsetlock(l)) {
297 perror("vrpn_Semaphore::v: usunsetlock:");
298 return -1;
299 }
300 }
301 else {
302 if (usvsema(ps)) {
303 perror("vrpn_Semaphore::v: uspsema:");
304 return -1;
305 }
306 }
307#elif defined(_WIN32)
308 if (!ReleaseSemaphore(hSemaphore, 1, NULL)) {
309 // get error info from windows (from FormatMessage help page)
310 LPVOID lpMsgBuf;
311
312 FormatMessage(
313 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
314 GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
315 // Default language
316 (LPTSTR)&lpMsgBuf, 0, NULL);
317 fprintf(stderr,
318 "vrpn_Semaphore::v: error v'ing semaphore, "
319 "WIN32 ReleaseSemaphore call caused the following error: %s",
320 (LPTSTR)lpMsgBuf);
321 // Free the buffer.
322 LocalFree(lpMsgBuf);
323 return -1;
324 }
325#else
326 // Posix by default
327 if (sem_post(semaphore) != 0) {
328 perror("vrpn_Semaphore::p: ");
329 return -1;
330 }
331#endif
332 return 0;
333}
334
335// 0 if it can't get the resource, 1 if it can
336// -1 if fail
338{
339 int iRetVal = 1;
340#ifdef sgi
341 if (fUsingLock) {
342 // don't spin at all
343 iRetVal = uscsetlock(l, 0);
344 if (iRetVal <= 0) {
345 perror("vrpn_Semaphore::condP: uscsetlock:");
346 return -1;
347 }
348 }
349 else {
350 iRetVal = uscpsema(ps);
351 if (iRetVal <= 0) {
352 perror("vrpn_Semaphore::condP: uscpsema:");
353 return -1;
354 }
355 }
356#elif defined(_WIN32)
357 switch (WaitForSingleObject(hSemaphore, 0)) {
358 case WAIT_OBJECT_0:
359 // got the resource
360 break;
361 case WAIT_TIMEOUT:
362 // resource not free
363 iRetVal = 0;
364 break;
365 case WAIT_ABANDONED:
366 ALL_ASSERT(0, "vrpn_Semaphore::condP: thread holding resource died");
367 return -1;
368 break;
369 case WAIT_FAILED:
370 // get error info from windows (from FormatMessage help page)
371 LPVOID lpMsgBuf;
372
373 FormatMessage(
374 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
375 GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
376 // Default language
377 (LPTSTR)&lpMsgBuf, 0, NULL);
378 fprintf(stderr,
379 "Semaphore::condP: error waiting for resource, "
380 "WIN32 WaitForSingleObject call caused the following error: %s",
381 (LPTSTR)lpMsgBuf);
382 // Free the buffer.
383 LocalFree(lpMsgBuf);
384 return -1;
385 break;
386 default:
387 ALL_ASSERT(0, "vrpn_Semaphore::p: unknown return code");
388 return -1;
389 }
390#else
391 // Posix by default
392 iRetVal = sem_trywait(semaphore);
393 if (iRetVal == 0) {
394 iRetVal = 1;
395 }
396 else if (errno == EAGAIN) {
397 iRetVal = 0;
398 }
399 else {
400 perror("vrpn_Semaphore::condP: ");
401 iRetVal = -1;
402 }
403#endif
404 return iRetVal;
405}
406
407int vrpn_Semaphore::numResources() { return cResources; }
408
409// static var definition
410#ifdef sgi
411usptr_t *vrpn_Semaphore::ppaArena = NULL;
412
413#include <sys/stat.h>
414// for umask stuff
415#include <sys/types.h>
416#include <sys/stat.h>
417
418void vrpn_Semaphore::allocArena()
419{
420 // /dev/zero is a special file which can only be shared between
421 // processes/threads which share file descriptors.
422 // It never shows up in the file system.
423 if ((ppaArena = usinit("/dev/zero")) == NULL) {
424 perror("vrpn_Thread::allocArena: usinit:");
425 }
426}
427#endif
428
429namespace vrpn {
430 SemaphoreGuard::SemaphoreGuard(vrpn_Semaphore &sem)
431 : locked_(false)
432 , sem_(sem)
433 {
434 lock();
435 }
436
437 // @brief overload that only tries to lock - doesn't block.
438 SemaphoreGuard::SemaphoreGuard(vrpn_Semaphore &sem, try_to_lock_t)
439 : locked_(false)
440 , sem_(sem)
441 {
442 try_to_lock();
443 }
444
446 SemaphoreGuard::~SemaphoreGuard() { unlock(); }
447
449 void SemaphoreGuard::lock()
450 {
451 if (locked_) {
452 return;
453 }
454 int result = sem_.p();
455 handleLockResult_(result);
456 }
457
459 bool SemaphoreGuard::try_to_lock()
460 {
461 if (locked_) {
462 return true;
463 }
464 int result = sem_.condP();
465 handleLockResult_(result);
466 return locked_;
467 }
468
470 void SemaphoreGuard::unlock()
471 {
472 if (locked_) {
473 int result = sem_.v();
474 ALL_ASSERT(result == 0, "failed to unlock semaphore!");
475 locked_ = false;
476 }
477 }
478 void SemaphoreGuard::handleLockResult_(int result)
479 {
480 ALL_ASSERT(result >= 0, "Lock error!");
481 if (result == 1) {
482 locked_ = true;
483 }
484 }
485
486} // namespace vrpn
487
488vrpn_Thread::vrpn_Thread(void(*pfThreadparm)(vrpn_ThreadData &ThreadData),
489 vrpn_ThreadData tdparm)
490 : pfThread(pfThreadparm)
491 , td(tdparm)
492 , threadID(0)
493{
494}
495
497{
498 if (threadID != 0) {
499 fprintf(stderr, "vrpn_Thread::go: already running\n");
500 return false;
501 }
502
503#ifdef sgi
504 if ((threadID = sproc(&threadFuncShell, PR_SALL, this)) ==
505 ((unsigned long)-1)) {
506 perror("vrpn_Thread::go: sproc");
507 return false;
508 }
509 // Threads not defined for the CYGWIN environment yet...
510#elif defined(_WIN32) && !defined(__CYGWIN__)
511 // pass in func, let it pick stack size, and arg to pass to thread
512 if ((threadID = _beginthread(&threadFuncShell, 0, this)) ==
513 ((unsigned long)-1)) {
514 perror("vrpn_Thread::go: _beginthread");
515 return false;
516 }
517#else
518 // Pthreads by default
519 if (pthread_create(&threadID, NULL, &threadFuncShellPosix, this) != 0) {
520 perror("vrpn_Thread::go:pthread_create: ");
521 return false;
522 }
523#endif
524 return true;
525}
526
528{
529 // kill the os thread
530#if defined(sgi) || defined(_WIN32)
531 if (threadID > 0) {
532#ifdef sgi
533 if (::kill((long)threadID, SIGKILL) < 0) {
534 perror("vrpn_Thread::kill: kill:");
535 return false;
536 }
537#elif defined(_WIN32)
538 // Return value of -1 passed to TerminateThread causes a warning.
539 if (!TerminateThread((HANDLE)threadID, 1)) {
540 fprintf(stderr,
541 "vrpn_Thread::kill: problem with terminateThread call.\n");
542 return false;
543 }
544#endif
545#else
546 if (threadID) {
547 // Posix by default. Detach so that the thread's resources will be
548 // freed automatically when it is killed.
549 if (pthread_detach(threadID) != 0) {
550 perror("vrpn_Thread::kill:pthread_detach: ");
551 return false;
552 }
553 if (pthread_kill(threadID, SIGKILL) != 0) {
554 perror("vrpn_Thread::kill:pthread_kill: ");
555 return false;
556 }
557#endif
558 }
559 else {
560 fprintf(stderr, "vrpn_Thread::kill: thread is not currently alive.\n");
561 return false;
562 }
563 threadID = 0;
564 return true;
565 }
566
567bool vrpn_Thread::running() { return threadID != 0; }
568
570
572{
573#ifdef vrpn_THREADS_AVAILABLE
574 return true;
575#else
576 return false;
577#endif
578}
579
580void vrpn_Thread::userData(void *pvNewUserData) { td.pvUD = pvNewUserData; }
581
582void *vrpn_Thread::userData() { return td.pvUD; }
583
585{
586 vrpn_Thread *pth = static_cast<vrpn_Thread *>(pvThread);
587 pth->pfThread(pth->td);
588 // thread has stopped running
589#if !defined(sgi) && !defined(_WIN32)
590 // Pthreads; need to detach the thread so its resources will be freed.
591 if (pthread_detach(pth->threadID) != 0) {
592 perror("vrpn_Thread::threadFuncShell:pthread_detach: ");
593 }
594#endif
595 pth->threadID = 0;
596}
597
598// This is a Posix-compatible function prototype that
599// just calls the other function.
601{
602 threadFuncShell(pvThread);
603 return NULL;
604}
605
607{
608 if (running()) {
609 kill();
610 }
611}
612
613// For the code to get the number of processor cores.
614#ifdef __APPLE__
615#include <sys/param.h>
616#include <sys/sysctl.h>
617#endif
618
620{
621#ifdef _WIN32
622 // Copy the hardware information to the SYSTEM_INFO structure.
623 SYSTEM_INFO siSysInfo;
624 GetSystemInfo(&siSysInfo);
625 return siSysInfo.dwNumberOfProcessors;
626#elif linux
627 // For Linux, we look at the /proc/cpuinfo file and count up the number
628 // of "processor :" entries (tab between processor and colon) in
629 // the file to find out how many we have.
630 FILE *f = fopen("/proc/cpuinfo", "r");
631 int count = 0;
632 if (f == NULL) {
633 perror("vrpn_Thread::number_of_processors:fopen: ");
634 return 1;
635 }
636
637 char line[512];
638 while (fgets(line, sizeof(line), f) != NULL) {
639 if (strncmp(line, "processor\t:", strlen("processor\t:")) == 0) {
640 count++;
641 }
642 }
643
644 fclose(f);
645 if (count == 0) {
646 fprintf(stderr,
647 "vrpn_Thread::number_of_processors: Found zero, returning 1\n");
648 count = 1;
649 }
650 return count;
651
652#elif __APPLE__
653 int count;
654 size_t size = sizeof(count);
655 if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0)) {
656 return 1;
657 }
658 else {
659 return static_cast<unsigned>(count);
660 }
661
662#else
663 fprintf(stderr, "vrpn_Thread::number_of_processors: Not yet implemented on "
664 "this architecture.\n");
665 return 1;
666#endif
667}
668
669// Thread function to call from within vrpn_test_threads_and_semaphores().
670// In this case, the userdata pointer is a pointer to a semaphore that
671// the thread should call v() on so that it will free up the main program
672// thread.
673static void vrpn_test_thread_body(vrpn_ThreadData &threadData)
674{
675 if (threadData.pvUD == NULL) {
676 fprintf(stderr, "vrpn_test_thread_body(): pvUD is NULL\n");
677 return;
678 }
679 vrpn_Semaphore *s = static_cast<vrpn_Semaphore *>(threadData.pvUD);
680 s->v();
681
682 return;
683}
684
686{
687 //------------------------------------------------------------
688 // Make a semaphore to test in single-threaded mode. First run its count
689 // all the way
690 // down to zero, then bring it back to the full complement and then bring it
691 // down
692 // again. Check that all of the semaphores are available and also that
693 // there are no
694 // more than expected available.
695 const unsigned sem_count = 5;
696 vrpn_Semaphore s(sem_count);
697 unsigned i;
698 for (i = 0; i < sem_count; i++) {
699 if (s.condP() != 1) {
700 fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore ran "
701 "out of counts\n");
702 return false;
703 }
704 }
705 if (s.condP() != 0) {
706 fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore had too "
707 "many counts\n");
708 return false;
709 }
710 for (i = 0; i < sem_count; i++) {
711 if (s.v() != 0) {
712 fprintf(stderr, "vrpn_test_threads_and_semaphores(): Could not "
713 "release Semaphore\n");
714 return false;
715 }
716 }
717 for (i = 0; i < sem_count; i++) {
718 if (s.condP() != 1) {
719 fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore ran "
720 "out of counts, round 2\n");
721 return false;
722 }
723 }
724 if (s.condP() != 0) {
725 fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore had too "
726 "many counts, round 2\n");
727 return false;
728 }
729
730 //------------------------------------------------------------
731 // Get a semaphore and use it to construct a thread data structure and then
732 // a thread. Use that thread to test whether threading is enabled (if not,
733 // then
734 // this completes our testing) and to find out how many processors there
735 // are.
737 td.pvUD = NULL;
738 vrpn_Thread t(vrpn_test_thread_body, td);
739
740 // If threading is not enabled, then we're done.
741 if (!t.available()) {
742 return true;
743 }
744
745 // Find out how many processors we have.
746 unsigned num_procs = t.number_of_processors();
747 if (num_procs == 0) {
748 fprintf(stderr, "vrpn_test_threads_and_semaphores(): "
749 "vrpn_Thread::number_of_processors() returned zero\n");
750 return false;
751 }
752
753 //------------------------------------------------------------
754 // Now make sure that we can actually run a thread. Do this by
755 // creating a semaphore with one entry and calling p() on it.
756 // Then make sure we can't p() it again and then run a thread
757 // that will call v() on it when it runs.
758 vrpn_Semaphore sem;
759 if (sem.p() != 1) {
760 fprintf(stderr, "vrpn_test_threads_and_semaphores(): thread-test "
761 "Semaphore had no count\n");
762 return false;
763 }
764 if (sem.condP() != 0) {
765 fprintf(stderr, "vrpn_test_threads_and_semaphores(): thread-test "
766 "Semaphore had too many counts\n");
767 return false;
768 }
769 t.userData(&sem);
770 if (!t.go()) {
771 fprintf(stderr,
772 "vrpn_test_threads_and_semaphores(): Could not start thread\n");
773 return false;
774 }
775 struct timeval start;
776 struct timeval now;
777 vrpn_gettimeofday(&start, NULL);
778 while (true) {
779 if (sem.condP() == 1) {
780 // The thread must have run; we got the semaphore!
781 break;
782 }
783
784 // Time out after three seconds if we haven't had the thread run to
785 // reset the semaphore.
786 vrpn_gettimeofday(&now, NULL);
787 struct timeval diff = vrpn_TimevalDiff(now, start);
788 if (diff.tv_sec >= 3) {
789 fprintf(stderr,
790 "vrpn_test_threads_and_semaphores(): Thread didn't run\n");
791 return false;
792 }
793
795 }
796
797 return true;
798}
int v()
Release of resource. ("up")
~vrpn_Semaphore()
destructor
vrpn_Semaphore(int cNumResources=1)
constructor - mutex by default (0 is a sync primitive)
Definition vrpn_Thread.C:43
bool reset(int cNumResources=1)
routine to reset it (true on success, false on failure) (may create new semaphore)
int numResources()
read values
int condP()
Non-blocking attempt to acquire resource ("down")
int p()
Blocking acquire of resource. ("down")
static void * threadFuncShellPosix(void *pvThread)
static void threadFuncShell(void *pvThread)
static unsigned number_of_processors()
bool running()
void(* pfThread)(vrpn_ThreadData &ThreadData)
vrpn_Thread(vrpn_THREAD_FUNC pfThread, vrpn_ThreadData td)
thread_t threadID
static bool available()
vrpn_ThreadData td
void * userData()
void userData(void *pvNewUserData)
thread_t pid()
pthread_t thread_t
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
void vrpn_SleepMsecs(double dMilliSecs)
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99
#define ALL_ASSERT(exp, msg)
Definition vrpn_Thread.C:36
Header containing vrpn_Thread, vrpn_Semaphore (formerly in vrpn_Shared.h), as well as a lock-guard cl...
bool vrpn_test_threads_and_semaphores(void)