/******************************************************************************/
/* */
/* 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 . */
/* */
/* 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
#include
#ifndef WIN32
#include
#include
#else
#undef ETIMEDOUT // Make sure that the definition from Winsock2.h is used ...
#include
#include
#include "XrdSys/XrdWin32.hh"
#endif
#include
#if defined(__linux__)
#include
#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 S e m a p h o r e */
/******************************************************************************/
/******************************************************************************/
/* C o n d W a i t */
/******************************************************************************/
#ifdef __APPLE__
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 sempagore, 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(syscall(SYS_gettid));
#elif defined(__solaris__)
return static_cast(pthread_self());
#elif defined(__APPLE__)
return static_cast(pthread_mach_thread_np(pthread_self()));
#else
return static_cast(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(myargs));
}
/******************************************************************************/
/* W a i t */
/******************************************************************************/
int XrdSysThread::Wait(pthread_t tid)
{
int retc, *tstat;
if ((retc = pthread_join(tid, reinterpret_cast(&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();
}