Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:15:43

0001 #ifndef __SYS_PTHREAD__
0002 #define __SYS_PTHREAD__
0003 /******************************************************************************/
0004 /*                                                                            */
0005 /*                      X r d S y s P t h r e a d . h h                       */
0006 /*                                                                            */
0007 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
0008 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
0009 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
0010 /*                                                                            */
0011 /* This file is part of the XRootD software suite.                            */
0012 /*                                                                            */
0013 /* XRootD is free software: you can redistribute it and/or modify it under    */
0014 /* the terms of the GNU Lesser General Public License as published by the     */
0015 /* Free Software Foundation, either version 3 of the License, or (at your     */
0016 /* option) any later version.                                                 */
0017 /*                                                                            */
0018 /* XRootD is distributed in the hope that it will be useful, but WITHOUT      */
0019 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or      */
0020 /* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public       */
0021 /* License for more details.                                                  */
0022 /*                                                                            */
0023 /* You should have received a copy of the GNU Lesser General Public License   */
0024 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file  */
0025 /* COPYING (GPL license).  If not, see <http://www.gnu.org/licenses/>.        */
0026 /*                                                                            */
0027 /* The copyright holder's institutional names and contributor's names may not */
0028 /* be used to endorse or promote products derived from this software without  */
0029 /* specific prior written permission of the institution or contributor.       */
0030 /******************************************************************************/
0031 
0032 #include <cerrno>
0033 #ifdef WIN32
0034 #define HAVE_STRUCT_TIMESPEC 1
0035 #endif
0036 #include <pthread.h>
0037 #include <signal.h>
0038 #ifdef AIX
0039 #include <sys/sem.h>
0040 #else
0041 #include <semaphore.h>
0042 #endif
0043 
0044 #ifdef __APPLE__
0045 #ifndef CLOCK_REALTIME
0046 #include <mach/clock.h>
0047 #include <mach/mach.h>
0048 #endif
0049 namespace
0050 {
0051   template< typename TYPE >
0052   void get_apple_realtime( TYPE & wait )
0053   {
0054 #ifdef CLOCK_REALTIME
0055     clock_gettime(CLOCK_REALTIME, &wait);
0056 #else
0057     clock_serv_t cclock;
0058     mach_timespec_t mts;
0059     host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
0060     clock_get_time(cclock, &mts);
0061     mach_port_deallocate(mach_task_self(), cclock);
0062     wait.tv_sec  = mts.tv_sec;
0063     wait.tv_nsec = mts.tv_nsec;
0064 #endif
0065   }
0066 }
0067 #endif
0068 
0069 #include "XrdSys/XrdSysError.hh"
0070 
0071 /******************************************************************************/
0072 /*                         X r d S y s C o n d V a r                          */
0073 /******************************************************************************/
0074   
0075 // XrdSysCondVar implements the standard POSIX-compliant condition variable.
0076 //               Methods correspond to the equivalent pthread condvar functions.
0077 
0078 class XrdSysCondVar
0079 {
0080 public:
0081 
0082 inline void  Lock()           {pthread_mutex_lock(&cmut);}
0083 
0084 inline void  Signal()         {if (relMutex) pthread_mutex_lock(&cmut);
0085                                pthread_cond_signal(&cvar);
0086                                if (relMutex) pthread_mutex_unlock(&cmut);
0087                               }
0088 
0089 inline void  Broadcast()      {if (relMutex) pthread_mutex_lock(&cmut);
0090                                pthread_cond_broadcast(&cvar);
0091                                if (relMutex) pthread_mutex_unlock(&cmut);
0092                               }
0093 
0094 inline void  UnLock()         {pthread_mutex_unlock(&cmut);}
0095 
0096        int   Wait();
0097        int   Wait(int sec);
0098        int   WaitMS(int msec);
0099 
0100       XrdSysCondVar(      int   relm=1, // 0->Caller will handle lock/unlock
0101                     const char *cid=0   // ID string for debugging only
0102                    ) {pthread_cond_init(&cvar, NULL);
0103                       pthread_mutex_init(&cmut, NULL);
0104                       relMutex = relm; condID = (cid ? cid : "unk");
0105                      }
0106      ~XrdSysCondVar() {pthread_cond_destroy(&cvar);
0107                        pthread_mutex_destroy(&cmut);
0108                       }
0109 private:
0110 
0111 pthread_cond_t  cvar;
0112 pthread_mutex_t cmut;
0113 int             relMutex;
0114 const char     *condID;
0115 };
0116 
0117 
0118 /******************************************************************************/
0119 /*                     X r d S y s C o n d V a r H e l p e r                  */
0120 /******************************************************************************/
0121 
0122 // XrdSysCondVarHelper is used to implement monitors with the Lock of a a condvar.
0123 //                     Monitors are used to lock
0124 //                     whole regions of code (e.g., a method) and automatically
0125 //                     unlock with exiting the region (e.g., return). The
0126 //                     methods should be self-evident.
0127   
0128 class XrdSysCondVarHelper
0129 {
0130 public:
0131 
0132 inline void   Lock(XrdSysCondVar *CndVar)
0133                   {if (cnd) {if (cnd != CndVar) cnd->UnLock();
0134                                 else return;
0135                             }
0136                    CndVar->Lock();
0137                    cnd = CndVar;
0138                   };
0139 
0140 inline void UnLock() {if (cnd) {cnd->UnLock(); cnd = 0;}}
0141 
0142             XrdSysCondVarHelper(XrdSysCondVar *CndVar=0)
0143                  {if (CndVar) CndVar->Lock();
0144                   cnd = CndVar;
0145                  }
0146             XrdSysCondVarHelper(XrdSysCondVar &CndVar)
0147                  {CndVar.Lock();
0148                   cnd = &CndVar;
0149                  }
0150 
0151            ~XrdSysCondVarHelper() {if (cnd) UnLock();}
0152 private:
0153 XrdSysCondVar *cnd;
0154 };
0155 
0156 
0157 /******************************************************************************/
0158 /*                           X r d S y s M u t e x                            */
0159 /******************************************************************************/
0160 
0161 // XrdSysMutex implements the standard POSIX mutex. The methods correspond
0162 //             to the equivalent pthread mutex functions.
0163   
0164 class XrdSysMutex
0165 {
0166 public:
0167 friend class XrdSysCondVar2;
0168 
0169 inline int CondLock()
0170        {if (pthread_mutex_trylock( &cs )) return 0;
0171         return 1;
0172        }
0173 #ifdef __APPLE__
0174 inline int TimedLock( int wait_ms )
0175 {
0176   struct timespec wait, cur, dur;
0177   get_apple_realtime(wait);
0178   wait.tv_sec += (wait_ms / 1000);
0179   wait.tv_nsec += (wait_ms % 1000) * 1000000;
0180   wait.tv_sec += (wait.tv_nsec / 1000000000);
0181   wait.tv_nsec = wait.tv_nsec % 1000000000;
0182 
0183   int rc;
0184   while( ( rc = pthread_mutex_trylock( &cs ) ) == EBUSY )
0185   {
0186     get_apple_realtime(cur);
0187     if( ( cur.tv_sec > wait.tv_sec ) || 
0188     ( ( cur.tv_sec == wait.tv_sec ) && ( cur.tv_nsec >= wait.tv_nsec ) ) )
0189       return 0;
0190 
0191     dur.tv_sec  = wait.tv_sec  - cur.tv_sec;
0192     dur.tv_nsec = wait.tv_nsec - cur.tv_nsec;
0193     if( dur.tv_nsec < 0 )
0194     {
0195       --dur.tv_sec;
0196       dur.tv_nsec += 1000000000;
0197     }
0198     
0199     if( ( dur.tv_sec != 0 ) || ( dur.tv_nsec > 1000000 ) )
0200     {
0201       dur.tv_sec  = 0;
0202       dur.tv_nsec = 1000000;
0203     }
0204 
0205     nanosleep( &dur, 0 );
0206   }
0207 
0208   return !rc;
0209 }
0210 #else
0211 inline int TimedLock(int wait_ms)
0212        {struct timespec wait;
0213         clock_gettime(CLOCK_REALTIME, &wait);
0214         wait.tv_sec += (wait_ms / 1000);
0215         wait.tv_nsec += (wait_ms % 1000) * 1000000;
0216         wait.tv_sec += (wait.tv_nsec / 1000000000);
0217         wait.tv_nsec = wait.tv_nsec % 1000000000;
0218         return !pthread_mutex_timedlock(&cs, &wait);
0219        }
0220 #endif
0221 
0222 inline void   Lock() {pthread_mutex_lock(&cs);}
0223 
0224 inline void UnLock() {pthread_mutex_unlock(&cs);}
0225 
0226         XrdSysMutex() {pthread_mutex_init(&cs, NULL);}
0227        ~XrdSysMutex() {pthread_mutex_destroy(&cs);}
0228 
0229 protected:
0230 
0231 pthread_mutex_t cs;
0232 };
0233 
0234 /******************************************************************************/
0235 /*                         X r d S y s R e c M u t e x                        */
0236 /******************************************************************************/
0237 
0238 // XrdSysRecMutex implements the recursive POSIX mutex. The methods correspond
0239 //             to the equivalent pthread mutex functions.
0240   
0241 class XrdSysRecMutex: public XrdSysMutex
0242 {
0243 public:
0244 
0245 XrdSysRecMutex();
0246 
0247 int InitRecMutex();
0248 int ReInitRecMutex();
0249 
0250 };
0251 
0252 
0253 /******************************************************************************/
0254 /*                     X r d S y s M u t e x H e l p e r                      */
0255 /******************************************************************************/
0256 
0257 // XrdSysMutexHelper us ised to implement monitors. Monitors are used to lock
0258 //                   whole regions of code (e.g., a method) and automatically
0259 //                   unlock with exiting the region (e.g., return). The
0260 //                   methods should be self-evident.
0261   
0262 class XrdSysMutexHelper
0263 {
0264 public:
0265 
0266 inline void   Lock(XrdSysMutex *Mutex)
0267                   {if (mtx) {if (mtx != Mutex) mtx->UnLock();
0268                                 else return;
0269                             }
0270                    Mutex->Lock();
0271                    mtx = Mutex;
0272                   };
0273 
0274 inline void UnLock() {if (mtx) {mtx->UnLock(); mtx = 0;}}
0275 
0276             XrdSysMutexHelper(XrdSysMutex *mutex=0)
0277                  {if (mutex) mutex->Lock();
0278                   mtx = mutex;
0279                  }
0280             XrdSysMutexHelper(XrdSysMutex &mutex)
0281                  {mutex.Lock();
0282                   mtx = &mutex;
0283                  }
0284 
0285            ~XrdSysMutexHelper() {if (mtx) UnLock();}
0286 private:
0287 XrdSysMutex *mtx;
0288 };
0289   
0290 /******************************************************************************/
0291 /*                        X r d S y s C o n d V a r 2                         */
0292 /******************************************************************************/
0293   
0294 // XrdSysCondVar2 implements the standard POSIX-compliant condition variable but
0295 //                unlike XrdSysCondVar requires the caller to supply a working
0296 //                mutex and does not handle any locking other than what is
0297 //                defined by POSIX.
0298 
0299 class XrdSysCondVar2
0300 {
0301 public:
0302 
0303 inline void  Signal()         {pthread_cond_signal(&cvar);}
0304 
0305 inline void  Broadcast()      {pthread_cond_broadcast(&cvar);}
0306 
0307 inline int   Wait()           {return pthread_cond_wait(&cvar, mtxP);}
0308        bool  Wait(int sec)    {return WaitMS(sec*1000);}
0309        bool  WaitMS(int msec);
0310 
0311        XrdSysCondVar2(XrdSysMutex &mtx) : mtxP(&mtx.cs)
0312                      {pthread_cond_init(&cvar, NULL);}
0313 
0314       ~XrdSysCondVar2() {pthread_cond_destroy(&cvar);}
0315 
0316 protected:
0317 
0318 pthread_cond_t   cvar;
0319 pthread_mutex_t *mtxP;
0320 };
0321 
0322 /******************************************************************************/
0323 /*                           X r d S y s R W L o c k                          */
0324 /******************************************************************************/
0325 
0326 // XrdSysRWLock implements the standard POSIX wrlock mutex. The methods correspond
0327 //             to the equivalent pthread wrlock functions.
0328   
0329 class XrdSysRWLock
0330 {
0331 public:
0332 
0333 inline int CondReadLock()
0334        {if (pthread_rwlock_tryrdlock( &lock )) return 0;
0335         return 1;
0336        }
0337 inline int CondWriteLock()
0338        {if (pthread_rwlock_trywrlock( &lock )) return 0;
0339         return 1;
0340        }
0341 
0342 inline void  ReadLock() {pthread_rwlock_rdlock(&lock);}
0343 inline void  WriteLock() {pthread_rwlock_wrlock(&lock);}
0344 
0345 inline void ReadLock( int &status ) {status = pthread_rwlock_rdlock(&lock);}
0346 inline void WriteLock( int &status ) {status = pthread_rwlock_wrlock(&lock);}
0347 
0348 inline void UnLock() {pthread_rwlock_unlock(&lock);}
0349 
0350 enum PrefType {prefWR=1};
0351 
0352         XrdSysRWLock(PrefType /* ptype */)
0353                     {
0354 #if defined(__linux__) && (defined(__GLIBC__) || defined(__UCLIBC__))
0355                      pthread_rwlockattr_t attr;
0356                      pthread_rwlockattr_setkind_np(&attr,
0357                              PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
0358                      pthread_rwlock_init(&lock, &attr);
0359 #else
0360                      pthread_rwlock_init(&lock, NULL);
0361 #endif
0362                     }
0363 
0364         XrdSysRWLock() {pthread_rwlock_init(&lock, NULL);}
0365        ~XrdSysRWLock() {pthread_rwlock_destroy(&lock);}
0366 
0367 inline void ReInitialize(PrefType /* ptype */)
0368 {
0369   pthread_rwlock_destroy(&lock);
0370 #if defined(__linux__) && (defined(__GLIBC__) || defined(__UCLIBC__))
0371   pthread_rwlockattr_t attr;
0372   pthread_rwlockattr_setkind_np(&attr,
0373                      PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
0374   pthread_rwlock_init(&lock, &attr);
0375 #else
0376   pthread_rwlock_init(&lock, NULL);
0377 #endif
0378 }
0379 
0380 inline void ReInitialize()
0381 {
0382   pthread_rwlock_destroy(&lock);
0383   pthread_rwlock_init(&lock, NULL);
0384 }
0385 
0386 protected:
0387 
0388 pthread_rwlock_t lock;
0389 };
0390 
0391 /******************************************************************************/
0392 /*                     X r d S y s W R L o c k H e l p e r                    */
0393 /******************************************************************************/
0394 
0395 // XrdSysWRLockHelper : helper class for XrdSysRWLock
0396   
0397 class XrdSysRWLockHelper
0398 {
0399 public:
0400 
0401 inline void   Lock(XrdSysRWLock *lock, bool rd = 1)
0402                   {if (lck) {if (lck != lock) lck->UnLock();
0403                                 else return;
0404                             }
0405                    if (rd) lock->ReadLock();
0406                       else lock->WriteLock();
0407                    lck = lock;
0408                   };
0409 
0410 inline void UnLock() {if (lck) {lck->UnLock(); lck = 0;}}
0411 
0412             XrdSysRWLockHelper(XrdSysRWLock *l=0, bool rd = 1)
0413                  { if (l) {if (rd) l->ReadLock();
0414                               else l->WriteLock();
0415                           }
0416                    lck = l;
0417                  }
0418             XrdSysRWLockHelper(XrdSysRWLock &l, bool rd = 1)
0419                  { if (rd) l.ReadLock();
0420                       else l.WriteLock();
0421                    lck = &l;
0422                  }
0423 
0424            ~XrdSysRWLockHelper() {if (lck) UnLock();}
0425 private:
0426 XrdSysRWLock *lck;
0427 };
0428 
0429 /******************************************************************************/
0430 /*                      X r d S y s F u s e d M u t e x                       */
0431 /******************************************************************************/
0432 
0433 class XrdSysFusedMutex
0434 {
0435 public:
0436 
0437 inline void  Lock()      {isRW ? rwLok->WriteLock() : mutex->Lock();}
0438 
0439 inline void  ReadLock()  {isRW ? rwLok->ReadLock()  : mutex->Lock();}
0440 
0441 inline void  WriteLock() {isRW ? rwLok->WriteLock() : mutex->Lock();}
0442 
0443 inline void  UnLock()    {isRW ? rwLok->UnLock()    : mutex->UnLock();}
0444 
0445              XrdSysFusedMutex(XrdSysRWLock &mtx)
0446                              : rwLok(&mtx), isRW(true) {}
0447 
0448              XrdSysFusedMutex(XrdSysMutex  &mtx)
0449                              : mutex(&mtx), isRW(false) {}
0450 
0451             ~XrdSysFusedMutex() {}
0452 private:
0453 
0454 union {XrdSysRWLock *rwLok; XrdSysMutex *mutex;};
0455 bool  isRW;
0456 };
0457   
0458 /******************************************************************************/
0459 /*                       X r d S y s S e m a p h o r e                        */
0460 /******************************************************************************/
0461 
0462 // XrdSysSemaphore implements the classic counting semaphore. The methods
0463 //                 should be self-evident. Note that on certain platforms
0464 //                 semaphores need to be implemented based on condition
0465 //                 variables since no native implementation is available.
0466   
0467 #if defined(__APPLE__) || defined(__GNU__)
0468 class XrdSysSemaphore
0469 {
0470 public:
0471 
0472        int  CondWait();
0473 
0474        void Post();
0475 
0476        void Wait();
0477 
0478 static void CleanUp(void *semVar);
0479 
0480   XrdSysSemaphore(int semval=1,const char *cid=0) : semVar(0, cid)
0481                                   {semVal = semval; semWait = 0;}
0482  ~XrdSysSemaphore() {}
0483 
0484 private:
0485 
0486 XrdSysCondVar semVar;
0487 int           semVal;
0488 int           semWait;
0489 };
0490 
0491 #else
0492 
0493 class XrdSysSemaphore
0494 {
0495 public:
0496 
0497 inline int  CondWait()
0498        {while(sem_trywait( &h_semaphore ))
0499              {if (errno == EAGAIN) return 0;
0500               if (errno != EINTR) { throw "sem_CondWait() failed";}
0501              }
0502         return 1;
0503        }
0504 
0505 inline void Post() {if (sem_post(&h_semaphore))
0506                        {throw "sem_post() failed";}
0507                    }
0508 
0509 inline void Wait() {while (sem_wait(&h_semaphore))
0510                           {if (EINTR != errno) 
0511                               {throw "sem_wait() failed";}
0512                           }
0513                    }
0514 
0515   XrdSysSemaphore(int semval=1, const char * =0)
0516                                {if (sem_init(&h_semaphore, 0, semval))
0517                                    {throw "sem_init() failed";}
0518                                }
0519  ~XrdSysSemaphore() {if (sem_destroy(&h_semaphore))
0520                         {abort();}
0521                     }
0522 
0523 private:
0524 
0525 sem_t h_semaphore;
0526 };
0527 #endif
0528 
0529 /******************************************************************************/
0530 /*                          X r d S y s T h r e a d                           */
0531 /******************************************************************************/
0532   
0533 // The C++ standard makes it impossible to link extern "C" methods with C++
0534 // methods. Thus, making a full thread object is nearly impossible. So, this
0535 // object is used as the thread manager. Since it is static for all intense
0536 // and purposes, one does not need to create an instance of it.
0537 //
0538 
0539 // Options to Run()
0540 //
0541 // BIND creates threads that are bound to a kernel thread.
0542 //
0543 #define XRDSYSTHREAD_BIND 0x001
0544 
0545 // HOLD creates a thread that needs to be joined to get its ending value.
0546 //      Otherwise, a detached thread is created.
0547 //
0548 #define XRDSYSTHREAD_HOLD 0x002
0549 
0550 class XrdSysThread
0551 {
0552 public:
0553 
0554 static int          Cancel(pthread_t tid) {return pthread_cancel(tid);}
0555 
0556 static int          Detach(pthread_t tid) {return pthread_detach(tid);}
0557 
0558 
0559 static  int  SetCancelOff() {
0560       return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
0561  };
0562 
0563 static  int  Join(pthread_t tid, void **ret) {
0564    return pthread_join(tid, ret);
0565  };
0566 
0567 static  int  SetCancelOn() {
0568       return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
0569  };
0570 
0571 static  int  SetCancelAsynchronous() {
0572       return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
0573  };
0574 
0575 static int  SetCancelDeferred() {
0576       return pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
0577  };
0578 
0579 static void  CancelPoint() {
0580       pthread_testcancel();
0581  };
0582 
0583 
0584 static pthread_t    ID(void)              {return pthread_self();}
0585 
0586 static int          Kill(pthread_t tid)   {return pthread_cancel(tid);}
0587 
0588 static unsigned long Num(void);
0589 
0590 static int          Run(pthread_t *, void *(*proc)(void *), void *arg, 
0591                         int opts=0, const char *desc = 0);
0592 
0593 static int          Same(pthread_t t1, pthread_t t2)
0594                         {return pthread_equal(t1, t2);}
0595 
0596 static void         setDebug(XrdSysError *erp) {eDest = erp;}
0597 
0598 static void         setStackSize(size_t stsz, bool force=false);
0599 
0600 static int          Signal(pthread_t tid, int snum)
0601                        {return pthread_kill(tid, snum);}
0602  
0603 static int          Wait(pthread_t tid);
0604 
0605                     XrdSysThread() {}
0606                    ~XrdSysThread() {}
0607 
0608 private:
0609 static XrdSysError  *eDest;
0610 static size_t        stackSize;
0611 };
0612 #endif