代码拉取完成,页面将自动刷新
/** @file
@brief Implementation
@date 2015
@author
Sensics, Inc.
<http://sensics.com/osvr>
*/
// Copyright 2015 Sensics, Inc.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Internal Includes
#include "vrpn_Thread.h"
#include "vrpn_Shared.h"
// Library/third-party includes
// - none
// Standard includes
#include <stdio.h> // for fprintf, stderr, perror, etc
#include <string.h> // for memcpy, strlen, strcpy, etc
#ifndef _WIN32
#include <errno.h> // for EAGAIN, errno
#include <signal.h> // for pthread_kill, SIGKILL
#endif
#ifdef __APPLE__
#include <unistd.h>
#endif
#define ALL_ASSERT(exp, msg) \
if (!(exp)) { \
fprintf(stderr, "\nAssertion failed! \n %s (%s, %d)\n", msg, __FILE__, \
__LINE__); \
}
// init all fields in init()
vrpn_Semaphore::vrpn_Semaphore(int cNumResources)
: cResources(cNumResources)
{
init();
}
#ifdef sgi
bool vrpn_Semaphore::init()
{
if (vrpn_Semaphore::ppaArena == NULL) {
vrpn_Semaphore::allocArena();
}
if (cResources == 1) {
fUsingLock = true;
ps = NULL;
// use lock instead of semaphore
if ((l = usnewlock(vrpn_Semaphore::ppaArena)) == NULL) {
fprintf(stderr, "vrpn_Semaphore::vrpn_Semaphore: error allocating "
"lock from arena.\n");
return false;
}
}
else {
fUsingLock = false;
l = NULL;
if ((ps = usnewsema(vrpn_Semaphore::ppaArena, cResources)) == NULL) {
fprintf(stderr, "vrpn_Semaphore::vrpn_Semaphore: error allocating "
"semaphore from arena.\n");
return false;
}
}
return true;
}
#elif defined(_WIN32)
bool vrpn_Semaphore::init()
{
// args are security, initial count, max count, and name
// TCH 20 Feb 2001 - Make the PC behavior closer to the SGI behavior.
int numMax = cResources;
if (numMax < 1) {
numMax = 1;
}
hSemaphore = CreateSemaphore(NULL, cResources, numMax, NULL);
if (!hSemaphore) {
// get error info from windows (from FormatMessage help page)
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
fprintf(stderr,
"vrpn_Semaphore::vrpn_Semaphore: error creating semaphore, "
"WIN32 CreateSemaphore call caused the following error: %s\n",
(LPTSTR)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
return false;
}
return true;
}
#elif defined(__APPLE__)
bool vrpn_Semaphore::init()
{
// We need to use sem_open on the mac because sem_init is not implemented
int numMax = cResources;
if (numMax < 1) {
numMax = 1;
}
char tempname[100];
sprintf(tempname, "/tmp/vrpn_sem.XXXXXXX");
semaphore = sem_open(mktemp(tempname), O_CREAT, 0600, numMax);
if (semaphore == SEM_FAILED) {
perror("vrpn_Semaphore::vrpn_Semaphore: error opening semaphore");
return false;
}
return true;
}
#else
bool vrpn_Semaphore::init()
{
// Posix threads are the default.
// We use sem_init on linux (instead of sem_open).
int numMax = cResources;
if (numMax < 1) {
numMax = 1;
}
try { semaphore = new sem_t; }
catch (...) { return false; }
if (sem_init(semaphore, 0, numMax) != 0) {
perror("vrpn_Semaphore::vrpn_Semaphore: error initializing semaphore");
return false;
}
return true;
}
#endif
#ifdef sgi
bool vrpn_Semaphore::destroy()
{
if (fUsingLock) {
usfreelock(l, vrpn_Semaphore::ppaArena);
}
else {
usfreesema(ps, vrpn_Semaphore::ppaArena);
}
return true;
}
#elif defined(_WIN32)
bool vrpn_Semaphore::destroy()
{
if (!CloseHandle(hSemaphore)) {
// get error info from windows (from FormatMessage help page)
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
fprintf(stderr,
"vrpn_Semaphore::destroy: error destroying semaphore, "
"WIN32 CloseHandle call caused the following error: %s\n",
(LPTSTR)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
return false;
}
return true;
}
#else
bool vrpn_Semaphore::destroy()
{
// Posix threads are the default.
#ifdef __APPLE__
if (sem_close(semaphore) != 0) {
perror("vrpn_Semaphore::destroy: error destroying semaphore.");
return false;
}
#else
if (sem_destroy(semaphore) != 0) {
fprintf(stderr,
"vrpn_Semaphore::destroy: error destroying semaphore.\n");
return false;
}
delete semaphore;
#endif
semaphore = NULL;
return true;
}
#endif
vrpn_Semaphore::~vrpn_Semaphore()
{
if (!destroy()) {
fprintf(
stderr,
"vrpn_Semaphore::~vrpn_Semaphore: error destroying semaphore.\n");
}
}
// routine to reset it
bool vrpn_Semaphore::reset(int cNumResources)
{
cResources = cNumResources;
// Destroy the old semaphore and then create a new one with the correct
// value.
if (!destroy()) {
fprintf(stderr, "vrpn_Semaphore::reset: error destroying semaphore.\n");
return false;
}
if (!init()) {
fprintf(stderr,
"vrpn_Semaphore::reset: error initializing semaphore.\n");
return false;
}
return true;
}
// routines to use it (p blocks, cond p does not)
// 1 on success, -1 fail
int vrpn_Semaphore::p()
{
#ifdef sgi
if (fUsingLock) {
if (ussetlock(l) != 1) {
perror("vrpn_Semaphore::p: ussetlock:");
return -1;
}
}
else {
if (uspsema(ps) != 1) {
perror("vrpn_Semaphore::p: uspsema:");
return -1;
}
}
#elif defined(_WIN32)
switch (WaitForSingleObject(hSemaphore, INFINITE)) {
case WAIT_OBJECT_0:
// got the resource
break;
case WAIT_TIMEOUT:
ALL_ASSERT(0, "vrpn_Semaphore::p: infinite wait time timed out!");
return -1;
break;
case WAIT_ABANDONED:
ALL_ASSERT(0, "vrpn_Semaphore::p: thread holding resource died");
return -1;
break;
case WAIT_FAILED:
// get error info from windows (from FormatMessage help page)
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
fprintf(stderr,
"vrpn_Semaphore::p: error waiting for resource, "
"WIN32 WaitForSingleObject call caused the following error: %s",
(LPTSTR)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
return -1;
break;
default:
ALL_ASSERT(0, "vrpn_Semaphore::p: unknown return code");
return -1;
}
#else
// Posix by default
if (sem_wait(semaphore) != 0) {
perror("vrpn_Semaphore::p: ");
return -1;
}
#endif
return 1;
}
// 0 on success, -1 fail
int vrpn_Semaphore::v()
{
#ifdef sgi
if (fUsingLock) {
if (usunsetlock(l)) {
perror("vrpn_Semaphore::v: usunsetlock:");
return -1;
}
}
else {
if (usvsema(ps)) {
perror("vrpn_Semaphore::v: uspsema:");
return -1;
}
}
#elif defined(_WIN32)
if (!ReleaseSemaphore(hSemaphore, 1, NULL)) {
// get error info from windows (from FormatMessage help page)
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
fprintf(stderr,
"vrpn_Semaphore::v: error v'ing semaphore, "
"WIN32 ReleaseSemaphore call caused the following error: %s",
(LPTSTR)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
return -1;
}
#else
// Posix by default
if (sem_post(semaphore) != 0) {
perror("vrpn_Semaphore::p: ");
return -1;
}
#endif
return 0;
}
// 0 if it can't get the resource, 1 if it can
// -1 if fail
int vrpn_Semaphore::condP()
{
int iRetVal = 1;
#ifdef sgi
if (fUsingLock) {
// don't spin at all
iRetVal = uscsetlock(l, 0);
if (iRetVal <= 0) {
perror("vrpn_Semaphore::condP: uscsetlock:");
return -1;
}
}
else {
iRetVal = uscpsema(ps);
if (iRetVal <= 0) {
perror("vrpn_Semaphore::condP: uscpsema:");
return -1;
}
}
#elif defined(_WIN32)
switch (WaitForSingleObject(hSemaphore, 0)) {
case WAIT_OBJECT_0:
// got the resource
break;
case WAIT_TIMEOUT:
// resource not free
iRetVal = 0;
break;
case WAIT_ABANDONED:
ALL_ASSERT(0, "vrpn_Semaphore::condP: thread holding resource died");
return -1;
break;
case WAIT_FAILED:
// get error info from windows (from FormatMessage help page)
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
fprintf(stderr,
"Semaphore::condP: error waiting for resource, "
"WIN32 WaitForSingleObject call caused the following error: %s",
(LPTSTR)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
return -1;
break;
default:
ALL_ASSERT(0, "vrpn_Semaphore::p: unknown return code");
return -1;
}
#else
// Posix by default
iRetVal = sem_trywait(semaphore);
if (iRetVal == 0) {
iRetVal = 1;
}
else if (errno == EAGAIN) {
iRetVal = 0;
}
else {
perror("vrpn_Semaphore::condP: ");
iRetVal = -1;
}
#endif
return iRetVal;
}
int vrpn_Semaphore::numResources() { return cResources; }
// static var definition
#ifdef sgi
usptr_t *vrpn_Semaphore::ppaArena = NULL;
#include <sys/stat.h>
// for umask stuff
#include <sys/types.h>
#include <sys/stat.h>
void vrpn_Semaphore::allocArena()
{
// /dev/zero is a special file which can only be shared between
// processes/threads which share file descriptors.
// It never shows up in the file system.
if ((ppaArena = usinit("/dev/zero")) == NULL) {
perror("vrpn_Thread::allocArena: usinit:");
}
}
#endif
namespace vrpn {
SemaphoreGuard::SemaphoreGuard(vrpn_Semaphore &sem)
: locked_(false)
, sem_(sem)
{
lock();
}
// @brief overload that only tries to lock - doesn't block.
SemaphoreGuard::SemaphoreGuard(vrpn_Semaphore &sem, try_to_lock_t)
: locked_(false)
, sem_(sem)
{
try_to_lock();
}
/// @brief Destructor that unlocks if we've locked.
SemaphoreGuard::~SemaphoreGuard() { unlock(); }
/// @brief Locks the semaphore, if we haven't locked it already.
void SemaphoreGuard::lock()
{
if (locked_) {
return;
}
int result = sem_.p();
handleLockResult_(result);
}
/// @brief Tries to lock - returns true if we locked it.
bool SemaphoreGuard::try_to_lock()
{
if (locked_) {
return true;
}
int result = sem_.condP();
handleLockResult_(result);
return locked_;
}
/// @brief Unlocks the resource, if we have locked it.
void SemaphoreGuard::unlock()
{
if (locked_) {
int result = sem_.v();
ALL_ASSERT(result == 0, "failed to unlock semaphore!");
locked_ = false;
}
}
void SemaphoreGuard::handleLockResult_(int result)
{
ALL_ASSERT(result >= 0, "Lock error!");
if (result == 1) {
locked_ = true;
}
}
} // namespace vrpn
vrpn_Thread::vrpn_Thread(void(*pfThreadparm)(vrpn_ThreadData &ThreadData),
vrpn_ThreadData tdparm)
: pfThread(pfThreadparm)
, td(tdparm)
, threadID(0)
{
}
bool vrpn_Thread::go()
{
if (threadID != 0) {
fprintf(stderr, "vrpn_Thread::go: already running\n");
return false;
}
#ifdef sgi
if ((threadID = sproc(&threadFuncShell, PR_SALL, this)) ==
((unsigned long)-1)) {
perror("vrpn_Thread::go: sproc");
return false;
}
// Threads not defined for the CYGWIN environment yet...
#elif defined(_WIN32) && !defined(__CYGWIN__)
// pass in func, let it pick stack size, and arg to pass to thread
if ((threadID = _beginthread(&threadFuncShell, 0, this)) ==
((unsigned long)-1)) {
perror("vrpn_Thread::go: _beginthread");
return false;
}
#else
// Pthreads by default
if (pthread_create(&threadID, NULL, &threadFuncShellPosix, this) != 0) {
perror("vrpn_Thread::go:pthread_create: ");
return false;
}
#endif
return true;
}
bool vrpn_Thread::kill()
{
// kill the os thread
#if defined(sgi) || defined(_WIN32)
if (threadID > 0) {
#ifdef sgi
if (::kill((long)threadID, SIGKILL) < 0) {
perror("vrpn_Thread::kill: kill:");
return false;
}
#elif defined(_WIN32)
// Return value of -1 passed to TerminateThread causes a warning.
if (!TerminateThread((HANDLE)threadID, 1)) {
fprintf(stderr,
"vrpn_Thread::kill: problem with terminateThread call.\n");
return false;
}
#endif
#else
if (threadID) {
// Posix by default. Detach so that the thread's resources will be
// freed automatically when it is killed.
if (pthread_detach(threadID) != 0) {
perror("vrpn_Thread::kill:pthread_detach: ");
return false;
}
if (pthread_kill(threadID, SIGKILL) != 0) {
perror("vrpn_Thread::kill:pthread_kill: ");
return false;
}
#endif
}
else {
fprintf(stderr, "vrpn_Thread::kill: thread is not currently alive.\n");
return false;
}
threadID = 0;
return true;
}
bool vrpn_Thread::running() { return threadID != 0; }
vrpn_Thread::thread_t vrpn_Thread::pid() { return threadID; }
bool vrpn_Thread::available()
{
#ifdef vrpn_THREADS_AVAILABLE
return true;
#else
return false;
#endif
}
void vrpn_Thread::userData(void *pvNewUserData) { td.pvUD = pvNewUserData; }
void *vrpn_Thread::userData() { return td.pvUD; }
void vrpn_Thread::threadFuncShell(void *pvThread)
{
vrpn_Thread *pth = static_cast<vrpn_Thread *>(pvThread);
pth->pfThread(pth->td);
// thread has stopped running
#if !defined(sgi) && !defined(_WIN32)
// Pthreads; need to detach the thread so its resources will be freed.
if (pthread_detach(pth->threadID) != 0) {
perror("vrpn_Thread::threadFuncShell:pthread_detach: ");
}
#endif
pth->threadID = 0;
}
// This is a Posix-compatible function prototype that
// just calls the other function.
void *vrpn_Thread::threadFuncShellPosix(void *pvThread)
{
threadFuncShell(pvThread);
return NULL;
}
vrpn_Thread::~vrpn_Thread()
{
if (running()) {
kill();
}
}
// For the code to get the number of processor cores.
#ifdef __APPLE__
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
unsigned vrpn_Thread::number_of_processors()
{
#ifdef _WIN32
// Copy the hardware information to the SYSTEM_INFO structure.
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
return siSysInfo.dwNumberOfProcessors;
#elif linux
// For Linux, we look at the /proc/cpuinfo file and count up the number
// of "processor :" entries (tab between processor and colon) in
// the file to find out how many we have.
FILE *f = fopen("/proc/cpuinfo", "r");
int count = 0;
if (f == NULL) {
perror("vrpn_Thread::number_of_processors:fopen: ");
return 1;
}
char line[512];
while (fgets(line, sizeof(line), f) != NULL) {
if (strncmp(line, "processor\t:", strlen("processor\t:")) == 0) {
count++;
}
}
fclose(f);
if (count == 0) {
fprintf(stderr,
"vrpn_Thread::number_of_processors: Found zero, returning 1\n");
count = 1;
}
return count;
#elif __APPLE__
int count;
size_t size = sizeof(count);
if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0)) {
return 1;
}
else {
return static_cast<unsigned>(count);
}
#else
fprintf(stderr, "vrpn_Thread::number_of_processors: Not yet implemented on "
"this architecture.\n");
return 1;
#endif
}
// Thread function to call from within vrpn_test_threads_and_semaphores().
// In this case, the userdata pointer is a pointer to a semaphore that
// the thread should call v() on so that it will free up the main program
// thread.
static void vrpn_test_thread_body(vrpn_ThreadData &threadData)
{
if (threadData.pvUD == NULL) {
fprintf(stderr, "vrpn_test_thread_body(): pvUD is NULL\n");
return;
}
vrpn_Semaphore *s = static_cast<vrpn_Semaphore *>(threadData.pvUD);
s->v();
return;
}
bool vrpn_test_threads_and_semaphores(void)
{
//------------------------------------------------------------
// Make a semaphore to test in single-threaded mode. First run its count
// all the way
// down to zero, then bring it back to the full complement and then bring it
// down
// again. Check that all of the semaphores are available and also that
// there are no
// more than expected available.
const unsigned sem_count = 5;
vrpn_Semaphore s(sem_count);
unsigned i;
for (i = 0; i < sem_count; i++) {
if (s.condP() != 1) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore ran "
"out of counts\n");
return false;
}
}
if (s.condP() != 0) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore had too "
"many counts\n");
return false;
}
for (i = 0; i < sem_count; i++) {
if (s.v() != 0) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): Could not "
"release Semaphore\n");
return false;
}
}
for (i = 0; i < sem_count; i++) {
if (s.condP() != 1) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore ran "
"out of counts, round 2\n");
return false;
}
}
if (s.condP() != 0) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): Semaphore had too "
"many counts, round 2\n");
return false;
}
//------------------------------------------------------------
// Get a semaphore and use it to construct a thread data structure and then
// a thread. Use that thread to test whether threading is enabled (if not,
// then
// this completes our testing) and to find out how many processors there
// are.
vrpn_ThreadData td;
td.pvUD = NULL;
vrpn_Thread t(vrpn_test_thread_body, td);
// If threading is not enabled, then we're done.
if (!t.available()) {
return true;
}
// Find out how many processors we have.
unsigned num_procs = t.number_of_processors();
if (num_procs == 0) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): "
"vrpn_Thread::number_of_processors() returned zero\n");
return false;
}
//------------------------------------------------------------
// Now make sure that we can actually run a thread. Do this by
// creating a semaphore with one entry and calling p() on it.
// Then make sure we can't p() it again and then run a thread
// that will call v() on it when it runs.
vrpn_Semaphore sem;
if (sem.p() != 1) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): thread-test "
"Semaphore had no count\n");
return false;
}
if (sem.condP() != 0) {
fprintf(stderr, "vrpn_test_threads_and_semaphores(): thread-test "
"Semaphore had too many counts\n");
return false;
}
t.userData(&sem);
if (!t.go()) {
fprintf(stderr,
"vrpn_test_threads_and_semaphores(): Could not start thread\n");
return false;
}
struct timeval start;
struct timeval now;
vrpn_gettimeofday(&start, NULL);
while (true) {
if (sem.condP() == 1) {
// The thread must have run; we got the semaphore!
break;
}
// Time out after three seconds if we haven't had the thread run to
// reset the semaphore.
vrpn_gettimeofday(&now, NULL);
struct timeval diff = vrpn_TimevalDiff(now, start);
if (diff.tv_sec >= 3) {
fprintf(stderr,
"vrpn_test_threads_and_semaphores(): Thread didn't run\n");
return false;
}
vrpn_SleepMsecs(1);
}
return true;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。