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 S e m a p h o r e */ 00199 /******************************************************************************/ 00200 00201 // XrdSysSemaphore implements the classic counting semaphore. The methods 00202 // should be self-evident. Note that on certain platforms 00203 // semaphores need to be implemented based on condition 00204 // variables since no native implementation is available. 00205 00206 #ifdef __macos__ 00207 class XrdSysSemaphore 00208 { 00209 public: 00210 00211 int CondWait(); 00212 00213 void Post(); 00214 00215 void Wait(); 00216 00217 XrdSysSemaphore(int semval=1,const char *cid=0) : semVar(0, cid) 00218 {semVal = semval; semWait = 0;} 00219 ~XrdSysSemaphore() {} 00220 00221 private: 00222 00223 XrdSysCondVar semVar; 00224 int semVal; 00225 int semWait; 00226 }; 00227 00228 #else 00229 00230 class XrdSysSemaphore 00231 { 00232 public: 00233 00234 inline int CondWait() 00235 {while(sem_trywait( &h_semaphore )) 00236 {if (errno == EAGAIN) return 0; 00237 if (errno != EINTR) { throw "sem_CondWait() failed";} 00238 } 00239 return 1; 00240 } 00241 00242 inline void Post() {if (sem_post(&h_semaphore)) 00243 {throw "sem_post() failed";} 00244 } 00245 00246 inline void Wait() {while (sem_wait(&h_semaphore)) 00247 {if (EINTR != errno) 00248 {throw "sem_wait() failed";} 00249 } 00250 } 00251 00252 XrdSysSemaphore(int semval=1, const char * =0) 00253 {if (sem_init(&h_semaphore, 0, semval)) 00254 {throw "sem_init() failed";} 00255 } 00256 ~XrdSysSemaphore() {if (sem_destroy(&h_semaphore)) 00257 {throw "sem_destroy() failed";} 00258 } 00259 00260 private: 00261 00262 sem_t h_semaphore; 00263 }; 00264 #endif 00265 00266 /******************************************************************************/ 00267 /* X r d S y s T h r e a d */ 00268 /******************************************************************************/ 00269 00270 // The C++ standard makes it impossible to link extern "C" methods with C++ 00271 // methods. Thus, making a full thread object is nearly impossible. So, this 00272 // object is used as the thread manager. Since it is static for all intense 00273 // and purposes, one does not need to create an instance of it. 00274 // 00275 00276 // Options to Run() 00277 // 00278 // BIND creates threads that are bound to a kernel thread. 00279 // 00280 #define XRDSYSTHREAD_BIND 0x001 00281 00282 // HOLD creates a thread that needs to be joined to get its ending value. 00283 // Otherwise, a detached thread is created. 00284 // 00285 #define XRDSYSTHREAD_HOLD 0x002 00286 00287 class XrdSysThread 00288 { 00289 public: 00290 00291 static int Cancel(pthread_t tid) {return pthread_cancel(tid);} 00292 00293 static int Detach(pthread_t tid) {return pthread_detach(tid);} 00294 00295 00296 static int SetCancelOff() { 00297 return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); 00298 }; 00299 00300 static int Join(pthread_t tid, void **ret) { 00301 return pthread_join(tid, ret); 00302 }; 00303 00304 static int SetCancelOn() { 00305 return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); 00306 }; 00307 00308 static int SetCancelAsynchronous() { 00309 return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); 00310 }; 00311 00312 static int SetCancelDeferred() { 00313 return pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0); 00314 }; 00315 00316 static void CancelPoint() { 00317 pthread_testcancel(); 00318 }; 00319 00320 00321 static pthread_t ID(void) {return pthread_self();} 00322 00323 static int Kill(pthread_t tid) {return pthread_cancel(tid);} 00324 00325 static unsigned long Num(void) 00326 {if (!initDone) doInit(); 00327 return (unsigned long)pthread_getspecific(threadNumkey); 00328 } 00329 00330 static int Run(pthread_t *, void *(*proc)(void *), void *arg, 00331 int opts=0, const char *desc = 0); 00332 00333 static int Same(pthread_t t1, pthread_t t2) 00334 {return pthread_equal(t1, t2);} 00335 00336 static void setDebug(XrdSysError *erp) {eDest = erp;} 00337 00338 static void setStackSize(size_t stsz) {stackSize = stsz;} 00339 00340 static int Signal(pthread_t tid, int snum) 00341 {return pthread_kill(tid, snum);} 00342 00343 static int Wait(pthread_t tid); 00344 00345 XrdSysThread() {} 00346 ~XrdSysThread() {} 00347 00348 private: 00349 static void doInit(void); 00350 static XrdSysError *eDest; 00351 static pthread_key_t threadNumkey; 00352 static size_t stackSize; 00353 static int initDone; 00354 }; 00355 #endif