XRootD
XrdSysPthread.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S y s P t h r e a d . c c */
4 /* */
5 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <cerrno>
31 #include <pthread.h>
32 #ifndef WIN32
33 #include <unistd.h>
34 #include <sys/time.h>
35 #else
36 #undef ETIMEDOUT // Make sure that the definition from Winsock2.h is used ...
37 #include <Winsock2.h>
38 #include <ctime>
39 #include "XrdSys/XrdWin32.hh"
40 #endif
41 #include <sys/types.h>
42 #if defined(__linux__)
43 #include <sys/syscall.h>
44 #endif
45 
46 #include "XrdSys/XrdSysPthread.hh"
47 
48 /******************************************************************************/
49 /* L o c a l S t r u c t s */
50 /******************************************************************************/
51 
53  {
55  const char *tDesc;
56  void *(*proc)(void *);
57  void *arg;
58 
59  XrdSysThreadArgs(XrdSysError *ed, const char *td,
60  void *(*p)(void *), void *a)
61  : eDest(ed), tDesc(td), proc(p), arg(a) {}
63  };
64 
65 /******************************************************************************/
66 /* G l o b a l D a t a */
67 /******************************************************************************/
68 
69 XrdSysError *XrdSysThread::eDest = 0;
70 
71 size_t XrdSysThread::stackSize = 0;
72 
73 /******************************************************************************/
74 /* T h r e a d I n t e r f a c e P r o g r a m s */
75 /******************************************************************************/
76 
77 extern "C"
78 {
79 void *XrdSysThread_Xeq(void *myargs)
80 {
81  XrdSysThreadArgs *ap = (XrdSysThreadArgs *)myargs;
82  void *retc;
83 
84  if (ap->eDest && ap->tDesc)
85  ap->eDest->Emsg("Xeq", ap->tDesc, "thread started");
86  retc = ap->proc(ap->arg);
87  delete ap;
88  return retc;
89 }
90 }
91 
92 /******************************************************************************/
93 /* X r d S y s C o n d V a r */
94 /******************************************************************************/
95 /******************************************************************************/
96 /* W a i t */
97 /******************************************************************************/
98 
100 {
101  int retc;
102 
103 // Wait for the condition
104 //
105  if (relMutex) Lock();
106  retc = pthread_cond_wait(&cvar, &cmut);
107  if (relMutex) UnLock();
108  return retc;
109 }
110 
111 /******************************************************************************/
112 
113 int XrdSysCondVar::Wait(int sec) {return WaitMS(sec*1000);}
114 
115 /******************************************************************************/
116 /* W a i t M S */
117 /******************************************************************************/
118 
120 {
121  int sec, retc, usec;
122  struct timeval tnow;
123  struct timespec tval;
124 
125 // Adjust millseconds
126 //
127  if (msec < 1000) sec = 0;
128  else {sec = msec / 1000; msec = msec % 1000;}
129  usec = msec * 1000;
130 
131 // Get the mutex before getting the time
132 //
133  if (relMutex) Lock();
134 
135 // Get current time of day
136 //
137  gettimeofday(&tnow, 0);
138 
139 // Add the second and microseconds
140 //
141  tval.tv_sec = tnow.tv_sec + sec;
142  tval.tv_nsec = tnow.tv_usec + usec;
143  if (tval.tv_nsec >= 1000000)
144  {tval.tv_sec += tval.tv_nsec / 1000000;
145  tval.tv_nsec = tval.tv_nsec % 1000000;
146  }
147  tval.tv_nsec *= 1000;
148 
149 
150 // Now wait for the condition or timeout
151 //
152  do {retc = pthread_cond_timedwait(&cvar, &cmut, &tval);}
153  while (retc && (retc == EINTR));
154 
155  if (relMutex) UnLock();
156 
157 // Determine how to return
158 //
159  if (retc && retc != ETIMEDOUT) {throw "cond_timedwait() failed";}
160  return retc == ETIMEDOUT;
161 }
162 
163 /******************************************************************************/
164 /* X r d S y s C o n d V a r 2 */
165 /******************************************************************************/
166 /******************************************************************************/
167 /* W a i t M S */
168 /******************************************************************************/
169 
171 {
172  int sec, retc, usec;
173  struct timeval tnow;
174  struct timespec tval;
175 
176 // Adjust millseconds
177 //
178  if (msec < 1000) sec = 0;
179  else {sec = msec / 1000; msec = msec % 1000;}
180  usec = msec * 1000;
181 
182 // Get current time of day
183 //
184  gettimeofday(&tnow, 0);
185 
186 // Add the second and microseconds
187 //
188  tval.tv_sec = tnow.tv_sec + sec;
189  tval.tv_nsec = tnow.tv_usec + usec;
190  if (tval.tv_nsec >= 1000000)
191  {tval.tv_sec += tval.tv_nsec / 1000000;
192  tval.tv_nsec = tval.tv_nsec % 1000000;
193  }
194  tval.tv_nsec *= 1000;
195 
196 
197 // Now wait for the condition or timeout
198 //
199  do {retc = pthread_cond_timedwait(&cvar, mtxP, &tval);}
200  while (retc && (retc == EINTR));
201 
202 // Determine how to return
203 //
204  if (retc && retc != ETIMEDOUT) {throw "cond_timedwait() failed";}
205  return retc == ETIMEDOUT;
206 }
207 
208 /******************************************************************************/
209 /* X r d S y s S e m a p h o r e */
210 /******************************************************************************/
211 /******************************************************************************/
212 /* C o n d W a i t */
213 /******************************************************************************/
214 
215 #if defined(__APPLE__) || defined(__GNU__)
216 
218 {
219  int rc;
220 
221 // Get the semaphore only we can get it without waiting
222 //
223  semVar.Lock();
224  if ((rc = (semVal > 0) && !semWait)) semVal--;
225  semVar.UnLock();
226  return rc;
227 }
228 
229 /******************************************************************************/
230 /* P o s t */
231 /******************************************************************************/
232 
234 {
235 // Add one to the semaphore counter. If we the value is > 0 and there is a
236 // thread waiting for the semaphore, signal it to get the semaphore.
237 //
238  semVar.Lock();
239  semVal++;
240  if (semVal && semWait) semVar.Signal();
241  semVar.UnLock();
242 }
243 
244 /******************************************************************************/
245 /* W a i t */
246 /******************************************************************************/
247 
249 {
250 
251 // Wait until the semaphore value is positive. This will not be starvation
252 // free if the OS implements an unfair mutex.
253 // Adding a cleanup handler to the stack here enables threads using this OSX
254 // semaphore to be canceled (which is rare). A scoped lock won't work here
255 // because OSX is broken and doesn't call destructors properly.
256 //
257  semVar.Lock();
258  pthread_cleanup_push(&XrdSysSemaphore::CleanUp, (void *) &semVar);
259  if (semVal < 1 || semWait)
260  while(semVal < 1)
261  {semWait++;
262  semVar.Wait();
263  semWait--;
264  }
265 
266 // Decrement the semaphore value, unlock the underlying cond var and return
267 //
268  semVal--;
269  pthread_cleanup_pop(1);
270 }
271 
272 /******************************************************************************/
273 /* C l e a n U p */
274 /******************************************************************************/
275 
276 void XrdSysSemaphore::CleanUp(void *semVar)
277 {
278  XrdSysCondVar *sv = (XrdSysCondVar *) semVar;
279  sv->UnLock();
280 }
281 #endif
282 
283 /******************************************************************************/
284 /* T h r e a d M e t h o d s */
285 /******************************************************************************/
286 /******************************************************************************/
287 /* N u m */
288 /******************************************************************************/
289 
290 unsigned long XrdSysThread::Num()
291 {
292 #if defined(__linux__)
293  return static_cast<unsigned long>(syscall(SYS_gettid));
294 #elif defined(__solaris__)
295  return static_cast<unsigned long>(pthread_self());
296 #elif defined(__APPLE__)
297  return static_cast<unsigned long>(pthread_mach_thread_np(pthread_self()));
298 #else
299  return static_cast<unsigned long>(getpid());
300 #endif
301 }
302 
303 /******************************************************************************/
304 /* R u n */
305 /******************************************************************************/
306 
307 int XrdSysThread::Run(pthread_t *tid, void *(*proc)(void *), void *arg,
308  int opts, const char *tDesc)
309 {
310  pthread_attr_t tattr;
311  XrdSysThreadArgs *myargs;
312 
313  myargs = new XrdSysThreadArgs(eDest, tDesc, proc, arg);
314 
315  pthread_attr_init(&tattr);
316  if ( opts & XRDSYSTHREAD_BIND)
317  pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
318  if (!(opts & XRDSYSTHREAD_HOLD))
319  pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
320  if (stackSize)
321  pthread_attr_setstacksize(&tattr, stackSize);
322  return pthread_create(tid, &tattr, XrdSysThread_Xeq,
323  static_cast<void *>(myargs));
324 }
325 
326 /******************************************************************************/
327 /* s e t S t a c k S i z e */
328 /******************************************************************************/
329 
330 void XrdSysThread::setStackSize(size_t stksz, bool force)
331 {
332 // If not being forced, then we set the stacksize only if the requested
333 // size is greater than the default size.
334 //
335 if (!force)
336  {pthread_attr_t tattr;
337  size_t dflt_stk_sz;
338  pthread_attr_init(&tattr);
339  if (pthread_attr_getstacksize(&tattr, &dflt_stk_sz) || stksz <= dflt_stk_sz)
340  {stackSize = 0;
341  return;
342  }
343  }
344 
345 // Record the stack size for future use
346 //
347  stackSize = stksz;
348 }
349 
350 /******************************************************************************/
351 /* W a i t */
352 /******************************************************************************/
353 
354 int XrdSysThread::Wait(pthread_t tid)
355 {
356  int retc, *tstat;
357  if ((retc = pthread_join(tid, reinterpret_cast<void **>(&tstat)))) return retc;
358  return *tstat;
359 }
360 
361 
362 
363 /******************************************************************************/
364 /* X r d S y s R e c M u t e x */
365 /******************************************************************************/
367 {
368  InitRecMutex();
369 }
370 
372 {
373  int rc;
374  pthread_mutexattr_t attr;
375 
376  rc = pthread_mutexattr_init( &attr );
377 
378  if( !rc )
379  {
380  pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
381  pthread_mutex_destroy( &cs );
382  rc = pthread_mutex_init( &cs, &attr );
383  }
384 
385  pthread_mutexattr_destroy(&attr);
386  return rc;
387 }
388 
390 {
391  pthread_mutex_destroy( &cs );
392  return InitRecMutex();
393 }
static XrdSysError eDest(0,"crypto_")
struct myOpts opts
void * XrdSysThread_Xeq(void *myargs)
#define XRDSYSTHREAD_BIND
#define XRDSYSTHREAD_HOLD
bool WaitMS(int msec)
pthread_mutex_t * mtxP
pthread_cond_t cvar
int WaitMS(int msec)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
pthread_mutex_t cs
static int Wait(pthread_t tid)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static void setStackSize(size_t stsz, bool force=false)
static unsigned long Num(void)
XrdSysError * eDest
const char * tDesc
void *(* proc)(void *)
XrdSysThreadArgs(XrdSysError *ed, const char *td, void *(*p)(void *), void *a)