Loading...
Searching...
No Matches
XrdSysPthread.cc
Go to the documentation of this file.
/******************************************************************************/
/* */
/* X r d S y s P t h r e a d . c c */
/* */
/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include <cerrno>
#include <pthread.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#undef ETIMEDOUT // Make sure that the definition from Winsock2.h is used ...
#include <Winsock2.h>
#include <ctime>
#include "XrdSys/XrdWin32.hh"
#endif
#include <sys/types.h>
#if defined(__linux__)
#include <sys/syscall.h>
#endif
#include "XrdSys/XrdSysPthread.hh"
/******************************************************************************/
/* L o c a l S t r u c t s */
/******************************************************************************/
struct XrdSysThreadArgs
{
XrdSysError *eDest;
const char *tDesc;
void *(*proc)(void *);
void *arg;
XrdSysThreadArgs(XrdSysError *ed, const char *td,
void *(*p)(void *), void *a)
: eDest(ed), tDesc(td), proc(p), arg(a) {}
~XrdSysThreadArgs() {}
};
/******************************************************************************/
/* G l o b a l D a t a */
/******************************************************************************/
XrdSysError *XrdSysThread::eDest = 0;
size_t XrdSysThread::stackSize = 0;
/******************************************************************************/
/* T h r e a d I n t e r f a c e P r o g r a m s */
/******************************************************************************/
extern "C"
{
void *XrdSysThread_Xeq(void *myargs)
{
XrdSysThreadArgs *ap = (XrdSysThreadArgs *)myargs;
void *retc;
if (ap->eDest && ap->tDesc)
ap->eDest->Emsg("Xeq", ap->tDesc, "thread started");
retc = ap->proc(ap->arg);
delete ap;
return retc;
}
}
/******************************************************************************/
/* X r d S y s C o n d V a r */
/******************************************************************************/
/******************************************************************************/
/* W a i t */
/******************************************************************************/
int XrdSysCondVar::Wait()
{
int retc;
// Wait for the condition
//
if (relMutex) Lock();
retc = pthread_cond_wait(&cvar, &cmut);
if (relMutex) UnLock();
return retc;
}
/******************************************************************************/
int XrdSysCondVar::Wait(int sec) {return WaitMS(sec*1000);}
/******************************************************************************/
/* W a i t M S */
/******************************************************************************/
int XrdSysCondVar::WaitMS(int msec)
{
int sec, retc, usec;
struct timeval tnow;
struct timespec tval;
// Adjust millseconds
//
if (msec < 1000) sec = 0;
else {sec = msec / 1000; msec = msec % 1000;}
usec = msec * 1000;
// Get the mutex before getting the time
//
if (relMutex) Lock();
// Get current time of day
//
gettimeofday(&tnow, 0);
// Add the second and microseconds
//
tval.tv_sec = tnow.tv_sec + sec;
tval.tv_nsec = tnow.tv_usec + usec;
if (tval.tv_nsec >= 1000000)
{tval.tv_sec += tval.tv_nsec / 1000000;
tval.tv_nsec = tval.tv_nsec % 1000000;
}
tval.tv_nsec *= 1000;
// Now wait for the condition or timeout
//
do {retc = pthread_cond_timedwait(&cvar, &cmut, &tval);}
while (retc && (retc == EINTR));
if (relMutex) UnLock();
// Determine how to return
//
if (retc && retc != ETIMEDOUT) {throw "cond_timedwait() failed";}
return retc == ETIMEDOUT;
}
/******************************************************************************/
/* X r d S y s C o n d V a r 2 */
/******************************************************************************/
/******************************************************************************/
/* W a i t M S */
/******************************************************************************/
bool XrdSysCondVar2::WaitMS(int msec)
{
int sec, retc, usec;
struct timeval tnow;
struct timespec tval;
// Adjust millseconds
//
if (msec < 1000) sec = 0;
else {sec = msec / 1000; msec = msec % 1000;}
usec = msec * 1000;
// Get current time of day
//
gettimeofday(&tnow, 0);
// Add the second and microseconds
//
tval.tv_sec = tnow.tv_sec + sec;
tval.tv_nsec = tnow.tv_usec + usec;
if (tval.tv_nsec >= 1000000)
{tval.tv_sec += tval.tv_nsec / 1000000;
tval.tv_nsec = tval.tv_nsec % 1000000;
}
tval.tv_nsec *= 1000;
// Now wait for the condition or timeout
//
do {retc = pthread_cond_timedwait(&cvar, mtxP, &tval);}
while (retc && (retc == EINTR));
// Determine how to return
//
if (retc && retc != ETIMEDOUT) {throw "cond_timedwait() failed";}
return retc == ETIMEDOUT;
}
/******************************************************************************/
/* X r d S y s S e m a p h o r e */
/******************************************************************************/
/******************************************************************************/
/* C o n d W a i t */
/******************************************************************************/
#if defined(__APPLE__) || defined(__GNU__)
int XrdSysSemaphore::CondWait()
{
int rc;
// Get the semaphore only we can get it without waiting
//
semVar.Lock();
if ((rc = (semVal > 0) && !semWait)) semVal--;
semVar.UnLock();
return rc;
}
/******************************************************************************/
/* P o s t */
/******************************************************************************/
void XrdSysSemaphore::Post()
{
// Add one to the semaphore counter. If we the value is > 0 and there is a
// thread waiting for the semaphore, signal it to get the semaphore.
//
semVar.Lock();
semVal++;
if (semVal && semWait) semVar.Signal();
semVar.UnLock();
}
/******************************************************************************/
/* W a i t */
/******************************************************************************/
void XrdSysSemaphore::Wait()
{
// Wait until the semaphore value is positive. This will not be starvation
// free if the OS implements an unfair mutex.
// Adding a cleanup handler to the stack here enables threads using this OSX
// semaphore to be canceled (which is rare). A scoped lock won't work here
// because OSX is broken and doesn't call destructors properly.
//
semVar.Lock();
pthread_cleanup_push(&XrdSysSemaphore::CleanUp, (void *) &semVar);
if (semVal < 1 || semWait)
while(semVal < 1)
{semWait++;
semVar.Wait();
semWait--;
}
// Decrement the semaphore value, unlock the underlying cond var and return
//
semVal--;
pthread_cleanup_pop(1);
}
/******************************************************************************/
/* C l e a n U p */
/******************************************************************************/
void XrdSysSemaphore::CleanUp(void *semVar)
{
XrdSysCondVar *sv = (XrdSysCondVar *) semVar;
sv->UnLock();
}
#endif
/******************************************************************************/
/* T h r e a d M e t h o d s */
/******************************************************************************/
/******************************************************************************/
/* N u m */
/******************************************************************************/
unsigned long XrdSysThread::Num()
{
#if defined(__linux__)
return static_cast<unsigned long>(syscall(SYS_gettid));
#elif defined(__solaris__)
return static_cast<unsigned long>(pthread_self());
#elif defined(__APPLE__)
return static_cast<unsigned long>(pthread_mach_thread_np(pthread_self()));
#else
return static_cast<unsigned long>(getpid());
#endif
}
/******************************************************************************/
/* R u n */
/******************************************************************************/
int XrdSysThread::Run(pthread_t *tid, void *(*proc)(void *), void *arg,
int opts, const char *tDesc)
{
pthread_attr_t tattr;
XrdSysThreadArgs *myargs;
myargs = new XrdSysThreadArgs(eDest, tDesc, proc, arg);
pthread_attr_init(&tattr);
if ( opts & XRDSYSTHREAD_BIND)
pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
if (!(opts & XRDSYSTHREAD_HOLD))
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
if (stackSize)
pthread_attr_setstacksize(&tattr, stackSize);
return pthread_create(tid, &tattr, XrdSysThread_Xeq,
static_cast<void *>(myargs));
}
/******************************************************************************/
/* s e t S t a c k S i z e */
/******************************************************************************/
void XrdSysThread::setStackSize(size_t stksz, bool force)
{
// If not being forced, then we set the stacksize only if the requested
// size is greater than the default size.
//
if (!force)
{pthread_attr_t tattr;
size_t dflt_stk_sz;
pthread_attr_init(&tattr);
if (pthread_attr_getstacksize(&tattr, &dflt_stk_sz) || stksz <= dflt_stk_sz)
{stackSize = 0;
return;
}
}
// Record the stack size for future use
//
stackSize = stksz;
}
/******************************************************************************/
/* W a i t */
/******************************************************************************/
int XrdSysThread::Wait(pthread_t tid)
{
int retc, *tstat;
if ((retc = pthread_join(tid, reinterpret_cast<void **>(&tstat)))) return retc;
return *tstat;
}
/******************************************************************************/
/* X r d S y s R e c M u t e x */
/******************************************************************************/
XrdSysRecMutex::XrdSysRecMutex()
{
InitRecMutex();
}
int XrdSysRecMutex::InitRecMutex()
{
int rc;
pthread_mutexattr_t attr;
rc = pthread_mutexattr_init( &attr );
if( !rc )
{
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_destroy( &cs );
rc = pthread_mutex_init( &cs, &attr );
}
pthread_mutexattr_destroy(&attr);
return rc;
}
int XrdSysRecMutex::ReInitRecMutex()
{
pthread_mutex_destroy( &cs );
return InitRecMutex();
}
opts
struct myOpts opts
XrdSysThread_Xeq
void * XrdSysThread_Xeq(void *myargs)
Definition XrdSysPthread.cc:79
XrdSysPthread.hh
XRDSYSTHREAD_BIND
#define XRDSYSTHREAD_BIND
Definition XrdSysPthread.hh:543
XRDSYSTHREAD_HOLD
#define XRDSYSTHREAD_HOLD
Definition XrdSysPthread.hh:548
XrdSysCondVar2::WaitMS
bool WaitMS(int msec)
Definition XrdSysPthread.cc:170
XrdSysCondVar2::mtxP
pthread_mutex_t * mtxP
Definition XrdSysPthread.hh:319
XrdSysCondVar2::cvar
pthread_cond_t cvar
Definition XrdSysPthread.hh:318
XrdSysCondVar::Wait
int Wait()
Definition XrdSysPthread.cc:99
XrdSysCondVar::WaitMS
int WaitMS(int msec)
Definition XrdSysPthread.cc:119
XrdSysCondVar::UnLock
void UnLock()
Definition XrdSysPthread.hh:94
XrdSysCondVar::Lock
void Lock()
Definition XrdSysPthread.hh:82
XrdSysError
Definition XrdSysError.hh:90
XrdSysError::Emsg
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition XrdSysError.cc:95
XrdSysMutex::cs
pthread_mutex_t cs
Definition XrdSysPthread.hh:231
XrdSysRecMutex::XrdSysRecMutex
XrdSysRecMutex()
Definition XrdSysPthread.cc:366
XrdSysRecMutex::InitRecMutex
int InitRecMutex()
Definition XrdSysPthread.cc:371
XrdSysRecMutex::ReInitRecMutex
int ReInitRecMutex()
Definition XrdSysPthread.cc:389
XrdSysSemaphore::Wait
void Wait()
Definition XrdSysPthread.hh:509
XrdSysSemaphore::Post
void Post()
Definition XrdSysPthread.hh:505
XrdSysSemaphore::CondWait
int CondWait()
Definition XrdSysPthread.hh:497
XrdSysThread::Wait
static int Wait(pthread_t tid)
Definition XrdSysPthread.cc:354
XrdSysThread::Run
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
Definition XrdSysPthread.cc:307
XrdSysThread::setStackSize
static void setStackSize(size_t stsz, bool force=false)
Definition XrdSysPthread.cc:330
XrdSysThread::Num
static unsigned long Num(void)
Definition XrdSysPthread.cc:290
XrdSysThreadArgs
Definition XrdSysPthread.cc:53
XrdSysThreadArgs::eDest
XrdSysError * eDest
Definition XrdSysPthread.cc:54
XrdSysThreadArgs::tDesc
const char * tDesc
Definition XrdSysPthread.cc:55
XrdSysThreadArgs::arg
void * arg
Definition XrdSysPthread.cc:57
XrdSysThreadArgs::~XrdSysThreadArgs
~XrdSysThreadArgs()
Definition XrdSysPthread.cc:62
XrdSysThreadArgs::XrdSysThreadArgs
XrdSysThreadArgs(XrdSysError *ed, const char *td, void *(*p)(void *), void *a)
Definition XrdSysPthread.cc:59
XrdSysThreadArgs::proc
void *(* proc)(void *)
Definition XrdSysPthread.cc:56