XRootD
XrdSysPthread.hh
Go to the documentation of this file.
1 #ifndef __SYS_PTHREAD__
2 #define __SYS_PTHREAD__
3 /******************************************************************************/
4 /* */
5 /* X r d S y s P t h r e a d . h h */
6 /* */
7 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
8 /* Produced by Andrew Hanushevsky for Stanford University under contract */
9 /* DE-AC02-76-SFO0515 with the Department of Energy */
10 /* */
11 /* This file is part of the XRootD software suite. */
12 /* */
13 /* XRootD is free software: you can redistribute it and/or modify it under */
14 /* the terms of the GNU Lesser General Public License as published by the */
15 /* Free Software Foundation, either version 3 of the License, or (at your */
16 /* option) any later version. */
17 /* */
18 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
19 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
20 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
21 /* License for more details. */
22 /* */
23 /* You should have received a copy of the GNU Lesser General Public License */
24 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
25 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
26 /* */
27 /* The copyright holder's institutional names and contributor's names may not */
28 /* be used to endorse or promote products derived from this software without */
29 /* specific prior written permission of the institution or contributor. */
30 /******************************************************************************/
31 
32 #include <cerrno>
33 #ifdef WIN32
34 #define HAVE_STRUCT_TIMESPEC 1
35 #endif
36 #include <pthread.h>
37 #include <signal.h>
38 #ifdef AIX
39 #include <sys/sem.h>
40 #else
41 #include <semaphore.h>
42 #endif
43 
44 #ifdef __APPLE__
45 #ifndef CLOCK_REALTIME
46 #include <mach/clock.h>
47 #include <mach/mach.h>
48 #endif
49 namespace
50 {
51  template< typename TYPE >
52  void get_apple_realtime( TYPE & wait )
53  {
54 #ifdef CLOCK_REALTIME
55  clock_gettime(CLOCK_REALTIME, &wait);
56 #else
57  clock_serv_t cclock;
58  mach_timespec_t mts;
59  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
60  clock_get_time(cclock, &mts);
61  mach_port_deallocate(mach_task_self(), cclock);
62  wait.tv_sec = mts.tv_sec;
63  wait.tv_nsec = mts.tv_nsec;
64 #endif
65  }
66 }
67 #endif
68 
69 #include "XrdSys/XrdSysError.hh"
70 
71 /******************************************************************************/
72 /* X r d S y s C o n d V a r */
73 /******************************************************************************/
74 
75 // XrdSysCondVar implements the standard POSIX-compliant condition variable.
76 // Methods correspond to the equivalent pthread condvar functions.
77 
79 {
80 public:
81 
82 inline void Lock() {pthread_mutex_lock(&cmut);}
83 
84 inline void Signal() {if (relMutex) pthread_mutex_lock(&cmut);
85  pthread_cond_signal(&cvar);
86  if (relMutex) pthread_mutex_unlock(&cmut);
87  }
88 
89 inline void Broadcast() {if (relMutex) pthread_mutex_lock(&cmut);
90  pthread_cond_broadcast(&cvar);
91  if (relMutex) pthread_mutex_unlock(&cmut);
92  }
93 
94 inline void UnLock() {pthread_mutex_unlock(&cmut);}
95 
96  int Wait();
97  int Wait(int sec);
98  int WaitMS(int msec);
99 
100  XrdSysCondVar( int relm=1, // 0->Caller will handle lock/unlock
101  const char *cid=0 // ID string for debugging only
102  ) {pthread_cond_init(&cvar, NULL);
103  pthread_mutex_init(&cmut, NULL);
104  relMutex = relm; condID = (cid ? cid : "unk");
105  }
106  ~XrdSysCondVar() {pthread_cond_destroy(&cvar);
107  pthread_mutex_destroy(&cmut);
108  }
109 private:
110 
111 pthread_cond_t cvar;
112 pthread_mutex_t cmut;
113 int relMutex;
114 const char *condID;
115 };
116 
117 
118 /******************************************************************************/
119 /* X r d S y s C o n d V a r H e l p e r */
120 /******************************************************************************/
121 
122 // XrdSysCondVarHelper is used to implement monitors with the Lock of a a condvar.
123 // Monitors are used to lock
124 // whole regions of code (e.g., a method) and automatically
125 // unlock with exiting the region (e.g., return). The
126 // methods should be self-evident.
127 
129 {
130 public:
131 
132 inline void Lock(XrdSysCondVar *CndVar)
133  {if (cnd) {if (cnd != CndVar) cnd->UnLock();
134  else return;
135  }
136  CndVar->Lock();
137  cnd = CndVar;
138  };
139 
140 inline void UnLock() {if (cnd) {cnd->UnLock(); cnd = 0;}}
141 
143  {if (CndVar) CndVar->Lock();
144  cnd = CndVar;
145  }
147  {CndVar.Lock();
148  cnd = &CndVar;
149  }
150 
151  ~XrdSysCondVarHelper() {if (cnd) UnLock();}
152 private:
153 XrdSysCondVar *cnd;
154 };
155 
156 
157 /******************************************************************************/
158 /* X r d S y s M u t e x */
159 /******************************************************************************/
160 
161 // XrdSysMutex implements the standard POSIX mutex. The methods correspond
162 // to the equivalent pthread mutex functions.
163 
165 {
166 public:
167 friend class XrdSysCondVar2;
168 
169 inline int CondLock()
170  {if (pthread_mutex_trylock( &cs )) return 0;
171  return 1;
172  }
173 #ifdef __APPLE__
174 inline int TimedLock( int wait_ms )
175 {
176  struct timespec wait, cur, dur;
177  get_apple_realtime(wait);
178  wait.tv_sec += (wait_ms / 1000);
179  wait.tv_nsec += (wait_ms % 1000) * 1000000;
180  wait.tv_sec += (wait.tv_nsec / 1000000000);
181  wait.tv_nsec = wait.tv_nsec % 1000000000;
182 
183  int rc;
184  while( ( rc = pthread_mutex_trylock( &cs ) ) == EBUSY )
185  {
186  get_apple_realtime(cur);
187  if( ( cur.tv_sec > wait.tv_sec ) ||
188  ( ( cur.tv_sec == wait.tv_sec ) && ( cur.tv_nsec >= wait.tv_nsec ) ) )
189  return 0;
190 
191  dur.tv_sec = wait.tv_sec - cur.tv_sec;
192  dur.tv_nsec = wait.tv_nsec - cur.tv_nsec;
193  if( dur.tv_nsec < 0 )
194  {
195  --dur.tv_sec;
196  dur.tv_nsec += 1000000000;
197  }
198 
199  if( ( dur.tv_sec != 0 ) || ( dur.tv_nsec > 1000000 ) )
200  {
201  dur.tv_sec = 0;
202  dur.tv_nsec = 1000000;
203  }
204 
205  nanosleep( &dur, 0 );
206  }
207 
208  return !rc;
209 }
210 #else
211 inline int TimedLock(int wait_ms)
212  {struct timespec wait;
213  clock_gettime(CLOCK_REALTIME, &wait);
214  wait.tv_sec += (wait_ms / 1000);
215  wait.tv_nsec += (wait_ms % 1000) * 1000000;
216  wait.tv_sec += (wait.tv_nsec / 1000000000);
217  wait.tv_nsec = wait.tv_nsec % 1000000000;
218  return !pthread_mutex_timedlock(&cs, &wait);
219  }
220 #endif
221 
222 inline void Lock() {pthread_mutex_lock(&cs);}
223 
224 inline void UnLock() {pthread_mutex_unlock(&cs);}
225 
226  XrdSysMutex() {pthread_mutex_init(&cs, NULL);}
227  ~XrdSysMutex() {pthread_mutex_destroy(&cs);}
228 
229 protected:
230 
231 pthread_mutex_t cs;
232 };
233 
234 /******************************************************************************/
235 /* X r d S y s R e c M u t e x */
236 /******************************************************************************/
237 
238 // XrdSysRecMutex implements the recursive POSIX mutex. The methods correspond
239 // to the equivalent pthread mutex functions.
240 
242 {
243 public:
244 
246 
247 int InitRecMutex();
248 int ReInitRecMutex();
249 
250 };
251 
252 
253 /******************************************************************************/
254 /* X r d S y s M u t e x H e l p e r */
255 /******************************************************************************/
256 
257 // XrdSysMutexHelper us ised to implement monitors. Monitors are used to lock
258 // whole regions of code (e.g., a method) and automatically
259 // unlock with exiting the region (e.g., return). The
260 // methods should be self-evident.
261 
263 {
264 public:
265 
266 inline void Lock(XrdSysMutex *Mutex)
267  {if (mtx) {if (mtx != Mutex) mtx->UnLock();
268  else return;
269  }
270  Mutex->Lock();
271  mtx = Mutex;
272  };
273 
274 inline void UnLock() {if (mtx) {mtx->UnLock(); mtx = 0;}}
275 
277  {if (mutex) mutex->Lock();
278  mtx = mutex;
279  }
281  {mutex.Lock();
282  mtx = &mutex;
283  }
284 
285  ~XrdSysMutexHelper() {if (mtx) UnLock();}
286 private:
287 XrdSysMutex *mtx;
288 };
289 
290 /******************************************************************************/
291 /* X r d S y s C o n d V a r 2 */
292 /******************************************************************************/
293 
294 // XrdSysCondVar2 implements the standard POSIX-compliant condition variable but
295 // unlike XrdSysCondVar requires the caller to supply a working
296 // mutex and does not handle any locking other than what is
297 // defined by POSIX.
298 
300 {
301 public:
302 
303 inline void Signal() {pthread_cond_signal(&cvar);}
304 
305 inline void Broadcast() {pthread_cond_broadcast(&cvar);}
306 
307 inline int Wait() {return pthread_cond_wait(&cvar, mtxP);}
308  bool Wait(int sec) {return WaitMS(sec*1000);}
309  bool WaitMS(int msec);
310 
311  XrdSysCondVar2(XrdSysMutex &mtx) : mtxP(&mtx.cs)
312  {pthread_cond_init(&cvar, NULL);}
313 
314  ~XrdSysCondVar2() {pthread_cond_destroy(&cvar);}
315 
316 protected:
317 
318 pthread_cond_t cvar;
319 pthread_mutex_t *mtxP;
320 };
321 
322 /******************************************************************************/
323 /* X r d S y s R W L o c k */
324 /******************************************************************************/
325 
326 // XrdSysRWLock implements the standard POSIX wrlock mutex. The methods correspond
327 // to the equivalent pthread wrlock functions.
328 
330 {
331 public:
332 
333 inline int CondReadLock()
334  {if (pthread_rwlock_tryrdlock( &lock )) return 0;
335  return 1;
336  }
337 inline int CondWriteLock()
338  {if (pthread_rwlock_trywrlock( &lock )) return 0;
339  return 1;
340  }
341 
342 inline void ReadLock() {pthread_rwlock_rdlock(&lock);}
343 inline void WriteLock() {pthread_rwlock_wrlock(&lock);}
344 
345 inline void ReadLock( int &status ) {status = pthread_rwlock_rdlock(&lock);}
346 inline void WriteLock( int &status ) {status = pthread_rwlock_wrlock(&lock);}
347 
348 inline void UnLock() {pthread_rwlock_unlock(&lock);}
349 
350 enum PrefType {prefWR=1};
351 
352  XrdSysRWLock(PrefType /* ptype */)
353  {
354 #if defined(__linux__) && (defined(__GLIBC__) || defined(__UCLIBC__))
355  pthread_rwlockattr_t attr;
356  pthread_rwlockattr_setkind_np(&attr,
357  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
358  pthread_rwlock_init(&lock, &attr);
359 #else
360  pthread_rwlock_init(&lock, NULL);
361 #endif
362  }
363 
364  XrdSysRWLock() {pthread_rwlock_init(&lock, NULL);}
365  ~XrdSysRWLock() {pthread_rwlock_destroy(&lock);}
366 
367 inline void ReInitialize(PrefType /* ptype */)
368 {
369  pthread_rwlock_destroy(&lock);
370 #if defined(__linux__) && (defined(__GLIBC__) || defined(__UCLIBC__))
371  pthread_rwlockattr_t attr;
372  pthread_rwlockattr_setkind_np(&attr,
373  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
374  pthread_rwlock_init(&lock, &attr);
375 #else
376  pthread_rwlock_init(&lock, NULL);
377 #endif
378 }
379 
380 inline void ReInitialize()
381 {
382  pthread_rwlock_destroy(&lock);
383  pthread_rwlock_init(&lock, NULL);
384 }
385 
386 protected:
387 
388 pthread_rwlock_t lock;
389 };
390 
391 /******************************************************************************/
392 /* X r d S y s W R L o c k H e l p e r */
393 /******************************************************************************/
394 
395 // XrdSysWRLockHelper : helper class for XrdSysRWLock
396 
398 {
399 public:
400 
401 inline void Lock(XrdSysRWLock *lock, bool rd = 1)
402  {if (lck) {if (lck != lock) lck->UnLock();
403  else return;
404  }
405  if (rd) lock->ReadLock();
406  else lock->WriteLock();
407  lck = lock;
408  };
409 
410 inline void UnLock() {if (lck) {lck->UnLock(); lck = 0;}}
411 
412  XrdSysRWLockHelper(XrdSysRWLock *l=0, bool rd = 1)
413  { if (l) {if (rd) l->ReadLock();
414  else l->WriteLock();
415  }
416  lck = l;
417  }
419  { if (rd) l.ReadLock();
420  else l.WriteLock();
421  lck = &l;
422  }
423 
424  ~XrdSysRWLockHelper() {if (lck) UnLock();}
425 private:
426 XrdSysRWLock *lck;
427 };
428 
429 /******************************************************************************/
430 /* X r d S y s F u s e d M u t e x */
431 /******************************************************************************/
432 
434 {
435 public:
436 
437 inline void Lock() {isRW ? rwLok->WriteLock() : mutex->Lock();}
438 
439 inline void ReadLock() {isRW ? rwLok->ReadLock() : mutex->Lock();}
440 
441 inline void WriteLock() {isRW ? rwLok->WriteLock() : mutex->Lock();}
442 
443 inline void UnLock() {isRW ? rwLok->UnLock() : mutex->UnLock();}
444 
446  : rwLok(&mtx), isRW(true) {}
447 
449  : mutex(&mtx), isRW(false) {}
450 
452 private:
453 
454 union {XrdSysRWLock *rwLok; XrdSysMutex *mutex;};
455 bool isRW;
456 };
457 
458 /******************************************************************************/
459 /* X r d S y s S e m a p h o r e */
460 /******************************************************************************/
461 
462 // XrdSysSemaphore implements the classic counting semaphore. The methods
463 // should be self-evident. Note that on certain platforms
464 // semaphores need to be implemented based on condition
465 // variables since no native implementation is available.
466 
467 #if defined(__APPLE__) || defined(__GNU__)
468 class XrdSysSemaphore
469 {
470 public:
471 
472  int CondWait();
473 
474  void Post();
475 
476  void Wait();
477 
478 static void CleanUp(void *semVar);
479 
480  XrdSysSemaphore(int semval=1,const char *cid=0) : semVar(0, cid)
481  {semVal = semval; semWait = 0;}
482  ~XrdSysSemaphore() {}
483 
484 private:
485 
486 XrdSysCondVar semVar;
487 int semVal;
488 int semWait;
489 };
490 
491 #else
492 
494 {
495 public:
496 
497 inline int CondWait()
498  {while(sem_trywait( &h_semaphore ))
499  {if (errno == EAGAIN) return 0;
500  if (errno != EINTR) { throw "sem_CondWait() failed";}
501  }
502  return 1;
503  }
504 
505 inline void Post() {if (sem_post(&h_semaphore))
506  {throw "sem_post() failed";}
507  }
508 
509 inline void Wait() {while (sem_wait(&h_semaphore))
510  {if (EINTR != errno)
511  {throw "sem_wait() failed";}
512  }
513  }
514 
515  XrdSysSemaphore(int semval=1, const char * =0)
516  {if (sem_init(&h_semaphore, 0, semval))
517  {throw "sem_init() failed";}
518  }
519  ~XrdSysSemaphore() {if (sem_destroy(&h_semaphore))
520  {abort();}
521  }
522 
523 private:
524 
525 sem_t h_semaphore;
526 };
527 #endif
528 
529 /******************************************************************************/
530 /* X r d S y s T h r e a d */
531 /******************************************************************************/
532 
533 // The C++ standard makes it impossible to link extern "C" methods with C++
534 // methods. Thus, making a full thread object is nearly impossible. So, this
535 // object is used as the thread manager. Since it is static for all intense
536 // and purposes, one does not need to create an instance of it.
537 //
538 
539 // Options to Run()
540 //
541 // BIND creates threads that are bound to a kernel thread.
542 //
543 #define XRDSYSTHREAD_BIND 0x001
544 
545 // HOLD creates a thread that needs to be joined to get its ending value.
546 // Otherwise, a detached thread is created.
547 //
548 #define XRDSYSTHREAD_HOLD 0x002
549 
551 {
552 public:
553 
554 static int Cancel(pthread_t tid) {return pthread_cancel(tid);}
555 
556 static int Detach(pthread_t tid) {return pthread_detach(tid);}
557 
558 
559 static int SetCancelOff() {
560  return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
561  };
562 
563 static int Join(pthread_t tid, void **ret) {
564  return pthread_join(tid, ret);
565  };
566 
567 static int SetCancelOn() {
568  return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
569  };
570 
571 static int SetCancelAsynchronous() {
572  return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
573  };
574 
575 static int SetCancelDeferred() {
576  return pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
577  };
578 
579 static void CancelPoint() {
580  pthread_testcancel();
581  };
582 
583 
584 static pthread_t ID(void) {return pthread_self();}
585 
586 static int Kill(pthread_t tid) {return pthread_cancel(tid);}
587 
588 static unsigned long Num(void);
589 
590 static int Run(pthread_t *, void *(*proc)(void *), void *arg,
591  int opts=0, const char *desc = 0);
592 
593 static int Same(pthread_t t1, pthread_t t2)
594  {return pthread_equal(t1, t2);}
595 
596 static void setDebug(XrdSysError *erp) {eDest = erp;}
597 
598 static void setStackSize(size_t stsz, bool force=false);
599 
600 static int Signal(pthread_t tid, int snum)
601  {return pthread_kill(tid, snum);}
602 
603 static int Wait(pthread_t tid);
604 
607 
608 private:
609 static XrdSysError *eDest;
610 static size_t stackSize;
611 };
612 #endif
struct myOpts opts
bool WaitMS(int msec)
pthread_mutex_t * mtxP
pthread_cond_t cvar
XrdSysCondVar2(XrdSysMutex &mtx)
bool Wait(int sec)
void Lock(XrdSysCondVar *CndVar)
XrdSysCondVarHelper(XrdSysCondVar *CndVar=0)
XrdSysCondVarHelper(XrdSysCondVar &CndVar)
XrdSysCondVar(int relm=1, const char *cid=0)
int WaitMS(int msec)
XrdSysFusedMutex(XrdSysMutex &mtx)
XrdSysFusedMutex(XrdSysRWLock &mtx)
XrdSysMutexHelper(XrdSysMutex *mutex=0)
void Lock(XrdSysMutex *Mutex)
XrdSysMutexHelper(XrdSysMutex &mutex)
pthread_mutex_t cs
int TimedLock(int wait_ms)
XrdSysRWLockHelper(XrdSysRWLock *l=0, bool rd=1)
void Lock(XrdSysRWLock *lock, bool rd=1)
XrdSysRWLockHelper(XrdSysRWLock &l, bool rd=1)
void ReadLock(int &status)
XrdSysRWLock(PrefType)
void ReInitialize()
pthread_rwlock_t lock
void WriteLock(int &status)
void ReInitialize(PrefType)
XrdSysSemaphore(int semval=1, const char *=0)
static void setDebug(XrdSysError *erp)
static void CancelPoint()
static int Wait(pthread_t tid)
static int Same(pthread_t t1, pthread_t t2)
static int SetCancelAsynchronous()
static int Join(pthread_t tid, void **ret)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static int Cancel(pthread_t tid)
static int SetCancelOn()
static pthread_t ID(void)
static int Signal(pthread_t tid, int snum)
static int Kill(pthread_t tid)
static int Detach(pthread_t tid)
static void setStackSize(size_t stsz, bool force=false)
static unsigned long Num(void)
static int SetCancelOff()
static int SetCancelDeferred()