xrootd
|
00001 #ifndef __SYS_PTHREAD__ 00002 #define __SYS_PTHREAD__ 00003 /******************************************************************************/ 00004 /* */ 00005 /* X r d S y s P t h r e a d . h h */ 00006 /* */ 00007 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */ 00008 /* All Rights Reserved. See XrdInfo.cc for complete License Terms */ 00009 /* Produced by Andrew Hanushevsky for Stanford University under contract */ 00010 /* DE-AC03-76-SFO0515 with the Department of Energy */ 00011 /******************************************************************************/ 00012 00013 // $Id$ 00014 00015 #include <errno.h> 00016 #ifdef WIN32 00017 #define HAVE_STRUCT_TIMESPEC 1 00018 #endif 00019 #include <pthread.h> 00020 #include <signal.h> 00021 #ifdef AIX 00022 #include <sys/sem.h> 00023 #else 00024 #include <semaphore.h> 00025 #endif 00026 00027 #include "XrdSys/XrdSysError.hh" 00028 00029 /******************************************************************************/ 00030 /* X r d S y s C o n d V a r */ 00031 /******************************************************************************/ 00032 00033 // XrdSysCondVar implements the standard POSIX-compliant condition variable. 00034 // Methods correspond to the equivalent pthread condvar functions. 00035 00036 class XrdSysCondVar 00037 { 00038 public: 00039 00040 inline void Lock() {pthread_mutex_lock(&cmut);} 00041 00042 inline void Signal() {if (relMutex) pthread_mutex_lock(&cmut); 00043 pthread_cond_signal(&cvar); 00044 if (relMutex) pthread_mutex_unlock(&cmut); 00045 } 00046 00047 inline void Broadcast() {if (relMutex) pthread_mutex_lock(&cmut); 00048 pthread_cond_broadcast(&cvar); 00049 if (relMutex) pthread_mutex_unlock(&cmut); 00050 } 00051 00052 inline void UnLock() {pthread_mutex_unlock(&cmut);} 00053 00054 int Wait(); 00055 int Wait(int sec); 00056 int WaitMS(int msec); 00057 00058 XrdSysCondVar( int relm=1, // 0->Caller will handle lock/unlock 00059 const char *cid=0 // ID string for debugging only 00060 ) {pthread_cond_init(&cvar, NULL); 00061 pthread_mutex_init(&cmut, NULL); 00062 relMutex = relm; condID = (cid ? cid : "unk"); 00063 } 00064 ~XrdSysCondVar() {pthread_cond_destroy(&cvar); 00065 pthread_mutex_destroy(&cmut); 00066 } 00067 private: 00068 00069 pthread_cond_t cvar; 00070 pthread_mutex_t cmut; 00071 int relMutex; 00072 const char *condID; 00073 }; 00074 00075 00076 00077 /******************************************************************************/ 00078 /* X r d S y s C o n d V a r H e l p e r */ 00079 /******************************************************************************/ 00080 00081 // XrdSysCondVarHelper is used to implement monitors with the Lock of a a condvar. 00082 // Monitors are used to lock 00083 // whole regions of code (e.g., a method) and automatically 00084 // unlock with exiting the region (e.g., return). The 00085 // methods should be self-evident. 00086 00087 class XrdSysCondVarHelper 00088 { 00089 public: 00090 00091 inline void Lock(XrdSysCondVar *CndVar) 00092 {if (cnd) {if (cnd != CndVar) cnd->UnLock(); 00093 else return; 00094 } 00095 CndVar->Lock(); 00096 cnd = CndVar; 00097 }; 00098 00099 inline void UnLock() {if (cnd) {cnd->UnLock(); cnd = 0;}} 00100 00101 XrdSysCondVarHelper(XrdSysCondVar *CndVar=0) 00102 {if (CndVar) CndVar->Lock(); 00103 cnd = CndVar; 00104 } 00105 XrdSysCondVarHelper(XrdSysCondVar &CndVar) { 00106 CndVar.Lock(); 00107 cnd = &CndVar; 00108 } 00109 00110 ~XrdSysCondVarHelper() {if (cnd) UnLock();} 00111 private: 00112 XrdSysCondVar *cnd; 00113 }; 00114 00115 00116 /******************************************************************************/ 00117 /* X r d S y s M u t e x */ 00118 /******************************************************************************/ 00119 00120 // XrdSysMutex implements the standard POSIX mutex. The methods correspond 00121 // to the equivalent pthread mutex functions. 00122 00123 class XrdSysMutex 00124 { 00125 public: 00126 00127 inline int CondLock() 00128 {if (pthread_mutex_trylock( &cs )) return 0; 00129 return 1; 00130 } 00131 00132 inline void Lock() {pthread_mutex_lock(&cs);} 00133 00134 inline void UnLock() {pthread_mutex_unlock(&cs);} 00135 00136 XrdSysMutex() {pthread_mutex_init(&cs, NULL);} 00137 ~XrdSysMutex() {pthread_mutex_destroy(&cs);} 00138 00139 protected: 00140 00141 pthread_mutex_t cs; 00142 }; 00143 00144 /******************************************************************************/ 00145 /* X r d S y s R e c M u t e x */ 00146 /******************************************************************************/ 00147 00148 // XrdSysRecMutex implements the recursive POSIX mutex. The methods correspond 00149 // to the equivalent pthread mutex functions. 00150 00151 class XrdSysRecMutex: public XrdSysMutex 00152 { 00153 public: 00154 00155 XrdSysRecMutex(); 00156 00157 }; 00158 00159 00160 /******************************************************************************/ 00161 /* X r d S y s M u t e x H e l p e r */ 00162 /******************************************************************************/ 00163 00164 // XrdSysMutexHelper us ised to implement monitors. Monitors are used to lock 00165 // whole regions of code (e.g., a method) and automatically 00166 // unlock with exiting the region (e.g., return). The 00167 // methods should be self-evident. 00168 00169 class XrdSysMutexHelper 00170 { 00171 public: 00172 00173 inline void Lock(XrdSysMutex *Mutex) 00174 {if (mtx) {if (mtx != Mutex) mtx->UnLock(); 00175 else return; 00176 } 00177 Mutex->Lock(); 00178 mtx = Mutex; 00179 }; 00180 00181 inline void UnLock() {if (mtx) {mtx->UnLock(); mtx = 0;}} 00182 00183 XrdSysMutexHelper(XrdSysMutex *mutex=0) 00184 {if (mutex) mutex->Lock(); 00185 mtx = mutex; 00186 } 00187 XrdSysMutexHelper(XrdSysMutex &mutex) { 00188 mutex.Lock(); 00189 mtx = &mutex; 00190 } 00191 00192 ~XrdSysMutexHelper() {if (mtx) UnLock();} 00193 private: 00194 XrdSysMutex *mtx; 00195 }; 00196 00197 /******************************************************************************/ 00198 /* X r d S y s R W L o c k */ 00199 /******************************************************************************/ 00200 00201 // XrdSysRWLock implements the standard POSIX wrlock mutex. The methods correspond 00202 // to the equivalent pthread wrlock functions. 00203 00204 class XrdSysRWLock 00205 { 00206 public: 00207 00208 inline int CondReadLock() 00209 {if (pthread_rwlock_tryrdlock( &lock )) return 0; 00210 return 1; 00211 } 00212 inline int CondWriteLock() 00213 {if (pthread_rwlock_trywrlock( &lock )) return 0; 00214 return 1; 00215 } 00216 00217 inline void ReadLock() {pthread_rwlock_rdlock(&lock);} 00218 inline void WriteLock() {pthread_rwlock_wrlock(&lock);} 00219 00220 inline void UnLock() {pthread_rwlock_unlock(&lock);} 00221 00222 XrdSysRWLock() {pthread_rwlock_init(&lock, NULL);} 00223 ~XrdSysRWLock() {pthread_rwlock_destroy(&lock);} 00224 00225 protected: 00226 00227 pthread_rwlock_t lock; 00228 }; 00229 00230 /******************************************************************************/ 00231 /* X r d S y s W R L o c k H e l p e r */ 00232 /******************************************************************************/ 00233 00234 // XrdSysWRLockHelper : helper class for XrdSysRWLock 00235 00236 class XrdSysRWLockHelper 00237 { 00238 public: 00239 00240 inline void Lock(XrdSysRWLock *lock, bool rd = 1) 00241 {if (lck) {if (lck != lock) lck->UnLock(); 00242 else return; 00243 } 00244 if (rd) lock->ReadLock(); 00245 else lock->WriteLock(); 00246 lck = lock; 00247 }; 00248 00249 inline void UnLock() {if (lck) {lck->UnLock(); lck = 0;}} 00250 00251 XrdSysRWLockHelper(XrdSysRWLock *l=0, bool rd = 1) 00252 { if (l) {if (rd) l->ReadLock(); 00253 else l->WriteLock(); 00254 } 00255 lck = l; 00256 } 00257 XrdSysRWLockHelper(XrdSysRWLock &l, bool rd = 1) 00258 { if (rd) l.ReadLock(); 00259 else l.WriteLock(); 00260 lck = &l; 00261 } 00262 00263 ~XrdSysRWLockHelper() {if (lck) UnLock();} 00264 private: 00265 XrdSysRWLock *lck; 00266 }; 00267 00268 /******************************************************************************/ 00269 /* X r d S y s S e m a p h o r e */ 00270 /******************************************************************************/ 00271 00272 // XrdSysSemaphore implements the classic counting semaphore. The methods 00273 // should be self-evident. Note that on certain platforms 00274 // semaphores need to be implemented based on condition 00275 // variables since no native implementation is available. 00276 00277 #ifdef __macos__ 00278 class XrdSysSemaphore 00279 { 00280 public: 00281 00282 int CondWait(); 00283 00284 void Post(); 00285 00286 void Wait(); 00287 00288 XrdSysSemaphore(int semval=1,const char *cid=0) : semVar(0, cid) 00289 {semVal = semval; semWait = 0;} 00290 ~XrdSysSemaphore() {} 00291 00292 private: 00293 00294 XrdSysCondVar semVar; 00295 int semVal; 00296 int semWait; 00297 }; 00298 00299 #else 00300 00301 class XrdSysSemaphore 00302 { 00303 public: 00304 00305 inline int CondWait() 00306 {while(sem_trywait( &h_semaphore )) 00307 {if (errno == EAGAIN) return 0; 00308 if (errno != EINTR) { throw "sem_CondWait() failed";} 00309 } 00310 return 1; 00311 } 00312 00313 inline void Post() {if (sem_post(&h_semaphore)) 00314 {throw "sem_post() failed";} 00315 } 00316 00317 inline void Wait() {while (sem_wait(&h_semaphore)) 00318 {if (EINTR != errno) 00319 {throw "sem_wait() failed";} 00320 } 00321 } 00322 00323 XrdSysSemaphore(int semval=1, const char * =0) 00324 {if (sem_init(&h_semaphore, 0, semval)) 00325 {throw "sem_init() failed";} 00326 } 00327 ~XrdSysSemaphore() {if (sem_destroy(&h_semaphore)) 00328 {throw "sem_destroy() failed";} 00329 } 00330 00331 private: 00332 00333 sem_t h_semaphore; 00334 }; 00335 #endif 00336 00337 /******************************************************************************/ 00338 /* X r d S y s T h r e a d */ 00339 /******************************************************************************/ 00340 00341 // The C++ standard makes it impossible to link extern "C" methods with C++ 00342 // methods. Thus, making a full thread object is nearly impossible. So, this 00343 // object is used as the thread manager. Since it is static for all intense 00344 // and purposes, one does not need to create an instance of it. 00345 // 00346 00347 // Options to Run() 00348 // 00349 // BIND creates threads that are bound to a kernel thread. 00350 // 00351 #define XRDSYSTHREAD_BIND 0x001 00352 00353 // HOLD creates a thread that needs to be joined to get its ending value. 00354 // Otherwise, a detached thread is created. 00355 // 00356 #define XRDSYSTHREAD_HOLD 0x002 00357 00358 class XrdSysThread 00359 { 00360 public: 00361 00362 static int Cancel(pthread_t tid) {return pthread_cancel(tid);} 00363 00364 static int Detach(pthread_t tid) {return pthread_detach(tid);} 00365 00366 00367 static int SetCancelOff() { 00368 return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); 00369 }; 00370 00371 static int Join(pthread_t tid, void **ret) { 00372 return pthread_join(tid, ret); 00373 }; 00374 00375 static int SetCancelOn() { 00376 return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); 00377 }; 00378 00379 static int SetCancelAsynchronous() { 00380 return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); 00381 }; 00382 00383 static int SetCancelDeferred() { 00384 return pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0); 00385 }; 00386 00387 static void CancelPoint() { 00388 pthread_testcancel(); 00389 }; 00390 00391 00392 static pthread_t ID(void) {return pthread_self();} 00393 00394 static int Kill(pthread_t tid) {return pthread_cancel(tid);} 00395 00396 static unsigned long Num(void) 00397 {if (!initDone) doInit(); 00398 return (unsigned long)pthread_getspecific(threadNumkey); 00399 } 00400 00401 static int Run(pthread_t *, void *(*proc)(void *), void *arg, 00402 int opts=0, const char *desc = 0); 00403 00404 static int Same(pthread_t t1, pthread_t t2) 00405 {return pthread_equal(t1, t2);} 00406 00407 static void setDebug(XrdSysError *erp) {eDest = erp;} 00408 00409 static void setStackSize(size_t stsz) {stackSize = stsz;} 00410 00411 static int Signal(pthread_t tid, int snum) 00412 {return pthread_kill(tid, snum);} 00413 00414 static int Wait(pthread_t tid); 00415 00416 XrdSysThread() {} 00417 ~XrdSysThread() {} 00418 00419 private: 00420 static void doInit(void); 00421 static XrdSysError *eDest; 00422 static pthread_key_t threadNumkey; 00423 static size_t stackSize; 00424 static int initDone; 00425 }; 00426 #endif