XRootD
XrdScheduler.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S c h e d u l e r . 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 <fcntl.h>
32 #include <signal.h>
33 #include <cstdio>
34 #include <sys/resource.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #ifdef __APPLE__
39 #include <AvailabilityMacros.h>
40 #endif
41 
42 #include "Xrd/XrdJob.hh"
43 #include "Xrd/XrdScheduler.hh"
44 #include "XrdOuc/XrdOucTrace.hh" // For ABI compatibility only!
45 #include "XrdSys/XrdSysError.hh"
46 #include "XrdSys/XrdSysLogger.hh"
47 
48 #define XRD_TRACE XrdTrace->
49 #include "Xrd/XrdTrace.hh"
50 
51 /******************************************************************************/
52 /* S t a t i c O b j e c t s */
53 /******************************************************************************/
54 
55  const char *XrdScheduler::TraceID = "Sched";
56 
57 /******************************************************************************/
58 /* L o c a l C l a s s e s */
59 /******************************************************************************/
60 
62  {public:
64  pid_t pid;
65 
66  XrdSchedulerPID(pid_t newpid, XrdSchedulerPID *prev)
67  {next = prev; pid = newpid;}
69  };
70 
71 /******************************************************************************/
72 /* E x t e r n a l T h r e a d I n t e r f a c e s */
73 /******************************************************************************/
74 
75 void *XrdStartReaper(void *carg)
76  {XrdScheduler *sp = (XrdScheduler *)carg;
77  sp->Reaper();
78  return (void *)0;
79  }
80 
81 void *XrdStartTSched(void *carg)
82  {XrdScheduler *sp = (XrdScheduler *)carg;
83  sp->TimeSched();
84  return (void *)0;
85  }
86 
87 void *XrdStartWorking(void *carg)
88  {XrdScheduler *sp = (XrdScheduler *)carg;
89  sp->Run();
90  return (void *)0;
91  }
92 
93 /******************************************************************************/
94 /* C o n s t r u c t o r */
95 /******************************************************************************/
96 
98  int minw, int maxw, int maxi)
99  : XrdJob("underused thread monitor"),
100  XrdTraceOld(0), WorkAvail(0, "sched work")
101 {
102  Boot(eP, tP, minw, maxw, maxi);
103 }
104 
105 /******************************************************************************/
106 
107 
109  int minw, int maxw, int maxi)
110  : XrdJob("underused thread monitor"),
111  XrdTraceOld(tP), WorkAvail(0, "sched work")
112 {
113 
114 // Invoke the main initialization function with a new style trace object
115 //
116  Boot(eP, new XrdSysTrace("Xrd", eP->logger()), minw, maxw, maxi);
117 }
118 
119 /******************************************************************************/
120 
121 // This constructor creates a self contained scheduler.
122 //
123 XrdScheduler::XrdScheduler(int minw, int maxw, int maxi)
124  : XrdJob("underused thread monitor"),
125  XrdTraceOld(0), WorkAvail(0, "sched work")
126 {
128  int eFD;
129 
130 // Get a file descriptor mirroring standard error
131 //
132 #if ( defined(__linux__) || defined(__GNU__) ) && defined(F_DUPFD_CLOEXEC)
133  eFD = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0);
134 #else
135  eFD = dup(STDERR_FILENO);
136  fcntl(eFD, F_SETFD, FD_CLOEXEC);
137 #endif
138 
139 // Now we need to get a logger object. We make this a real dumb one.
140 //
141  Logger = new XrdSysLogger(eFD, 0);
142  XrdLog = new XrdSysError(Logger);
143 
144 // Now get a trace object
145 //
146  XrdTrace = new XrdSysTrace("Xrd", Logger);
147  if (getenv("XRDDEBUG") != 0) XrdTrace->What = TRACE_SCHED;
148 
149 // Set remaining values. We do no use maximum possible threads here.
150 //
151  Init(minw, maxw, maxi);
152 }
153 
154 /******************************************************************************/
155 /* Private: B o o t */
156 /******************************************************************************/
157 
158 void XrdScheduler::Boot(XrdSysError *eP, XrdSysTrace *tP,
159  int minw, int maxw, int maxi)
160 {
161 // Perform common initialization
162 //
163  XrdLog = eP;
164  XrdTrace = tP;
165  Init(minw, maxw, maxi);
166 
167 // Make sure we are using the maximum number of threads allowed (Linux only)
168 //
169 #if ( defined(__linux__) || defined(__GNU__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) ) && defined(RLIMIT_NPROC)
170 
171  struct rlimit rlim;
172 
173 // First determine the absolute maximum we can have
174 //
175  rlim_t theMax = MAX_SCHED_PROCS;
176  int pdFD, rdsz;
177  if ((pdFD = open("/proc/sys/kernel/pid_max", O_RDONLY)) >= 0)
178  {char pmBuff[32];
179  if ((rdsz = read(pdFD, pmBuff, sizeof(pmBuff))) > 0)
180  {rdsz = atoi(pmBuff);
181  if (rdsz < 16384) theMax = 16384; // This is unlikely
182  else if (rdsz < MAX_SCHED_PROCS)
183  theMax = static_cast<rlim_t>(rdsz-2000);
184  }
185  close(pdFD);
186  }
187 
188 // Get the resource thread limit and set to maximum. In Linux this may be -1
189 // to indicate useless infnity, so we have to come up with a number, sigh.
190 //
191  if (!getrlimit(RLIMIT_NPROC, &rlim))
192  {if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max > theMax)
193  {rlim.rlim_cur = theMax;
194  setrlimit(RLIMIT_NPROC, &rlim);
195  } else {
196  if (rlim.rlim_cur != rlim.rlim_max)
197  {rlim.rlim_cur = rlim.rlim_max;
198  setrlimit(RLIMIT_NPROC, &rlim);
199  }
200  }
201  }
202 
203 // Readjust our internal maximum to be the actual maximum
204 //
205  if (!getrlimit(RLIMIT_NPROC, &rlim))
206  {if (rlim.rlim_cur == RLIM_INFINITY || rlim.rlim_cur > theMax)
207  max_Workers = static_cast<int>(theMax);
208  else max_Workers = static_cast<int>(rlim.rlim_cur);
209  }
210 #endif
211 
212 }
213 
214 /******************************************************************************/
215 /* D e s t r u c t o r */
216 /******************************************************************************/
217 
218 XrdScheduler::~XrdScheduler() // The scheduler is never deleted!
219 {
220 }
221 
222 /******************************************************************************/
223 /* C a n c e l */
224 /******************************************************************************/
225 
227 {
228  XrdJob *p, *pp = 0;
229 
230 // Lock the queue
231 //
232  TimerMutex.Lock();
233 
234 // Find the matching job, if any
235 //
236  p = TimerQueue;
237  while(p && p != jp) {pp = p; p = p->NextJob;}
238 
239 // Delete the job element
240 //
241  if (p)
242  {if (pp) pp->NextJob = p->NextJob;
243  else TimerQueue = p->NextJob;
244  TRACE(SCHED, "time event " <<jp->Comment <<" cancelled");
245  }
246 
247 // All done
248 //
249  TimerMutex.UnLock();
250 }
251 
252 /******************************************************************************/
253 /* D o I t */
254 /******************************************************************************/
255 
257 {
258  int num_kill, num_idle;
259 
260 // Now check if there are too many idle threads (kill them if there are)
261 //
262  if (!num_JobsinQ)
263  {DispatchMutex.Lock(); num_idle = idl_Workers; DispatchMutex.UnLock();
264  num_kill = num_idle - min_Workers;
265  TRACE(SCHED, num_Workers <<" threads; " <<num_idle <<" idle");
266  if (num_kill > 0)
267  {if (num_kill > 1) num_kill = num_kill/2;
268  SchedMutex.Lock();
269  num_Layoffs = num_kill;
270  while(num_kill--) WorkAvail.Post();
271  SchedMutex.UnLock();
272  }
273  }
274 
275 // Check if we should reschedule ourselves
276 //
277  if (max_Workidl > 0) Schedule((XrdJob *)this, max_Workidl+time(0));
278 }
279 
280 /******************************************************************************/
281 /* F o r k */
282 /******************************************************************************/
283 
284 // This entry exists solely so that we can start a reaper thread for processes
285 //
286 pid_t XrdScheduler::Fork(const char *id)
287 {
288  static int retc, ReaperStarted = 0;
289  pthread_t tid;
290  pid_t pid;
291 
292 // Fork
293 //
294  if ((pid = fork()) < 0)
295  {XrdLog->Emsg("Scheduler",errno,"fork to handle",id);
296  return pid;
297  }
298  if (!pid) return pid;
299 
300 // Obtain the status of the reaper thread.
301 //
302  ReaperMutex.Lock();
303  firstPID = new XrdSchedulerPID(pid, firstPID);
304  retc = ReaperStarted;
305  ReaperStarted = 1;
306  ReaperMutex.UnLock();
307 
308 // Start the reaper thread if it has not started.
309 //
310  if (!retc)
311  if ((retc = XrdSysThread::Run(&tid, XrdStartReaper, (void *)this,
312  0, "Process reaper")))
313  {XrdLog->Emsg("Scheduler", retc, "create reaper thread");
314  ReaperStarted = 0;
315  }
316 
317  return pid;
318 }
319 
320 /******************************************************************************/
321 /* R e a p e r */
322 /******************************************************************************/
323 
325 {
326  int status;
327  pid_t pid;
328  XrdSchedulerPID *tp, *ptp, *xtp;
329 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_5)
330  struct timespec ts = { 1, 0 };
331 #else
332  sigset_t Sset;
333  int signum;
334 
335 // Set up for signal handling. Note: main() must block this signal at start)
336 //
337  sigemptyset(&Sset);
338  sigaddset(&Sset, SIGCHLD);
339 #endif
340 
341 // Wait for all outstanding children
342 //
343  do {ReaperMutex.Lock();
344  tp = firstPID; ptp = 0;
345  while(tp)
346  {do {pid = waitpid(tp->pid, &status, WNOHANG);}
347  while (pid < 0 && errno == EINTR);
348  if (pid > 0)
349  {if (TRACING(TRACE_SCHED)) traceExit(pid, status);
350  xtp = tp; tp = tp->next;
351  if (ptp) ptp->next = tp;
352  else firstPID = tp;
353  delete xtp;
354  } else {ptp = tp; tp = tp->next;}
355  }
356  ReaperMutex.UnLock();
357 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_5)
358  // Mac OS X sigwait() is broken on <= 10.4.
359  } while (nanosleep(&ts, 0) <= 0);
360 #else
361  } while(sigwait(&Sset, &signum) >= 0);
362 #endif
363  return (void *)0;
364 }
365 
366 /******************************************************************************/
367 /* R u n */
368 /******************************************************************************/
369 
371 {
372  int waiting;
373  XrdJob *jp;
374 
375 // Wait for work then do it (an endless task for a worker thread)
376 //
377  do {do {DispatchMutex.Lock(); idl_Workers++;DispatchMutex.UnLock();
378  WorkAvail.Wait();
379  DispatchMutex.Lock();waiting = --idl_Workers;DispatchMutex.UnLock();
380  SchedMutex.Lock();
381  if ((jp = WorkFirst))
382  {if (!(WorkFirst = jp->NextJob)) WorkLast = 0;
383  if (num_JobsinQ) num_JobsinQ--;
384  else XrdLog->Emsg("Scheduler","Job queue count underflow!");
385  } else {
386  num_JobsinQ = 0;
387  if (num_Layoffs > 0)
388  {num_Layoffs--;
389  if (waiting)
390  {num_TDestroy++; num_Workers--;
391  TRACE(SCHED, "terminating thread; workers=" <<num_Workers);
392  SchedMutex.UnLock();
393  return;
394  }
395  }
396  }
397  SchedMutex.UnLock();
398  } while(!jp);
399 
400  // Check if we should hire a new worker (we always want 1 idle thread)
401  // before running this job.
402  //
403  if (!waiting) hireWorker();
404  if (TRACING(TRACE_SCHED) && *(jp->Comment) != '.')
405  {TRACE(SCHED, "running " <<jp->Comment <<" inq=" <<num_JobsinQ);}
406  jp->DoIt();
407  } while(1);
408 }
409 
410 /******************************************************************************/
411 /* S c h e d u l e */
412 /******************************************************************************/
413 
415 {
416 // Lock down our data area
417 //
418  SchedMutex.Lock();
419 
420 // Place the request on the queue and broadcast it
421 //
422  jp->NextJob = 0;
423  if (WorkFirst)
424  {WorkLast->NextJob = jp;
425  WorkLast = jp;
426  } else {
427  WorkFirst = jp;
428  WorkLast = jp;
429  }
430  WorkAvail.Post();
431 
432 // Calculate statistics
433 //
434  num_Jobs++;
435  num_JobsinQ++;
436  if (num_JobsinQ > max_QLength) max_QLength = num_JobsinQ;
437 
438 // Unlock the data area and return
439 //
440  SchedMutex.UnLock();
441 }
442 
443 /******************************************************************************/
444 
445 void XrdScheduler::Schedule(int numjobs, XrdJob *jfirst, XrdJob *jlast)
446 {
447 
448 // Lock down our data area
449 //
450  SchedMutex.Lock();
451 
452 // Place the request list on the queue
453 //
454  jlast->NextJob = 0;
455  if (WorkFirst)
456  {WorkLast->NextJob = jfirst;
457  WorkLast = jlast;
458  } else {
459  WorkFirst = jfirst;
460  WorkLast = jlast;
461  }
462 
463 // Calculate statistics
464 //
465  num_Jobs += numjobs;
466  num_JobsinQ += numjobs;
467  if (num_JobsinQ > max_QLength) max_QLength = num_JobsinQ;
468 
469 // Indicate number of jobs to work on
470 //
471  while(numjobs--) WorkAvail.Post();
472 
473 // Unlock the data area and return
474 //
475  SchedMutex.UnLock();
476 }
477 
478 /******************************************************************************/
479 
480 void XrdScheduler::Schedule(XrdJob *jp, time_t atime)
481 {
482  XrdJob *pp = 0, *p;
483 
484 // Cancel this event, if scheduled
485 //
486  Cancel(jp);
487 
488 // Lock the queue
489 //
490  if (TRACING(TRACE_SCHED) && *(jp->Comment) != '.')
491  {TRACE(SCHED, "scheduling " <<jp->Comment <<" in " <<atime-time(0) <<" seconds");}
492  jp->SchedTime = atime;
493  TimerMutex.Lock();
494 
495 // Find the insertion point for the work element
496 //
497  p = TimerQueue;
498  while(p && p->SchedTime <= atime) {pp = p; p = p->NextJob;}
499 
500 // Insert the job element
501 //
502  jp->NextJob = p;
503  if (pp) pp->NextJob = jp;
504  else {TimerQueue = jp; TimerRings.Signal();}
505 
506 // All done
507 //
508  TimerMutex.UnLock();
509 }
510 
511 /******************************************************************************/
512 /* s e t P a r m s */
513 /******************************************************************************/
514 
515 void XrdScheduler::setParms(int minw, int maxw, int avlw, int maxi, int once)
516 {
517  static int isSet = 0;
518 
519 // Lock the data area and check for 1-time set
520 //
521  SchedMutex.Lock();
522  if (once && isSet) {SchedMutex.UnLock(); return;}
523  isSet = 1;
524 
525 // get a consistent view of all the values
526 //
527  if (maxw <= 0) maxw = max_Workers;
528  if (minw < 0) minw = min_Workers;
529  if (minw > maxw) minw = maxw;
530  if (avlw < 0) avlw = maxw/4*3;
531  else if (avlw > maxw) avlw = maxw;
532 
533 // Set the values
534 //
535  min_Workers = minw;
536  max_Workers = maxw;
537  stk_Workers = maxw - avlw;
538  if (maxi >=0) max_Workidl = maxi;
539 
540 // Unlock the data area
541 //
542  SchedMutex.UnLock();
543 
544 // If we have an idle interval, schedule the idle check
545 //
546  if (maxi > 0)
547  {Cancel((XrdJob *)this);
548  Schedule((XrdJob *)this, (time_t)maxi+time(0));
549  }
550 
551 // Debug the info
552 //
553  TRACE(SCHED,"Set min_Workers=" <<min_Workers <<" max_Workers=" <<max_Workers);
554  TRACE(SCHED,"Set stk_Workers=" <<stk_Workers <<" max_Workidl=" <<max_Workidl);
555 }
556 
557 /******************************************************************************/
558 /* S t a r t */
559 /******************************************************************************/
560 
561 void XrdScheduler::Start() // Serialized one time call!
562 {
563  int retc, numw;
564  pthread_t tid;
565 
566 // Provide ABI compatibility for XrdOucTrace which is deprecated!
567 //
568  if (getenv("XRDDEBUG") != 0) XrdTrace->What = TRACE_SCHED;
569  else if (XrdTraceOld) XrdTrace->What |= XrdTraceOld->What;
570 
571 // Start a time based scheduler
572 //
573  if ((retc = XrdSysThread::Run(&tid, XrdStartTSched, (void *)this,
574  XRDSYSTHREAD_BIND, "Time scheduler")))
575  XrdLog->Emsg("Scheduler", retc, "create time scheduler thread");
576 
577 // If we an idle interval, schedule the idle check
578 //
579  if (max_Workidl > 0) Schedule((XrdJob *)this, (time_t)max_Workidl+time(0));
580 
581 // Start 1/3 of the minimum number of threads
582 //
583  if (!(numw = min_Workers/3)) numw = 2;
584  while(numw--) hireWorker(0);
585 
586 // Unlock the data area
587 //
588  TRACE(SCHED, "Starting with " <<num_Workers <<" workers" );
589 }
590 
591 /******************************************************************************/
592 /* S t a t s */
593 /******************************************************************************/
594 
595 int XrdScheduler::Stats(char *buff, int blen, int do_sync)
596 {
597  int cnt_Jobs, cnt_JobsinQ, xam_QLength, cnt_Workers, cnt_idl;
598  int cnt_TCreate, cnt_TDestroy, cnt_Limited;
599  static char statfmt[] = "<stats id=\"sched\"><jobs>%d</jobs>"
600  "<inq>%d</inq><maxinq>%d</maxinq>"
601  "<threads>%d</threads><idle>%d</idle>"
602  "<tcr>%d</tcr><tde>%d</tde>"
603  "<tlimr>%d</tlimr></stats>";
604 
605 // If only length wanted, do so
606 //
607  if (!buff) return sizeof(statfmt) + 16*8;
608 
609 // Get values protected by the Dispatch lock (avoid lock if no sync needed)
610 //
611  if (do_sync) DispatchMutex.Lock();
612  cnt_idl = idl_Workers;
613  if (do_sync) DispatchMutex.UnLock();
614 
615 // Get values protected by the Scheduler lock (avoid lock if no sync needed)
616 //
617  if (do_sync) SchedMutex.Lock();
618  cnt_Workers = num_Workers;
619  cnt_Jobs = num_Jobs;
620  cnt_JobsinQ = num_JobsinQ;
621  xam_QLength = max_QLength;
622  cnt_TCreate = num_TCreate;
623  cnt_TDestroy= num_TDestroy;
624  cnt_Limited = num_Limited;
625  if (do_sync) SchedMutex.UnLock();
626 
627 // Format the stats and return them
628 //
629  return snprintf(buff, blen, statfmt, cnt_Jobs, cnt_JobsinQ, xam_QLength,
630  cnt_Workers, cnt_idl, cnt_TCreate, cnt_TDestroy,
631  cnt_Limited);
632 }
633 
634 /******************************************************************************/
635 /* T i m e S c h e d */
636 /******************************************************************************/
637 
639 {
640  XrdJob *jp;
641  int wtime;
642 
643 // Continuous loop until we find some work here
644 //
645  do {TimerMutex.Lock();
646  if (TimerQueue) wtime = TimerQueue->SchedTime-time(0);
647  else wtime = 60*60;
648  if (wtime > 0)
649  {TimerMutex.UnLock();
650  TimerRings.Wait(wtime);
651  } else {
652  jp = TimerQueue;
653  TimerQueue = jp->NextJob;
654  Schedule(jp);
655  TimerMutex.UnLock();
656  }
657  } while(1);
658 }
659 
660 /******************************************************************************/
661 /* P r i v a t e M e t h o d s */
662 /******************************************************************************/
663 /******************************************************************************/
664 /* h i r e W o r k e r */
665 /******************************************************************************/
666 
667 void XrdScheduler::hireWorker(int dotrace)
668 {
669  pthread_t tid;
670  int retc;
671 
672 // First check if we reached the maximum number of workers
673 //
674  SchedMutex.Lock();
675  if (num_Workers >= max_Workers)
676  {num_Limited++;
677  if ((num_Limited & 4095) == 1)
678  XrdLog->Emsg("Scheduler","Thread limit has been reached!");
679  SchedMutex.UnLock();
680  return;
681  }
682  num_Workers++;
683  num_TCreate++;
684  SchedMutex.UnLock();
685 
686 // Start a new thread. We do this without the schedMutex to avoid hang-ups. If
687 // we can't start a new thread, we recalculate the maximum number we can.
688 //
689  retc = XrdSysThread::Run(&tid, XrdStartWorking, (void *)this, 0, "Worker");
690 
691 // Now check the results and correct if we couldn't start the thread
692 //
693  if (retc)
694  {XrdLog->Emsg("Scheduler", retc, "create worker thread");
695  SchedMutex.Lock();
696  num_Workers--;
697  num_TCreate--;
698  max_Workers = num_Workers;
699  min_Workers = (max_Workers/10 ? max_Workers/10 : 1);
700  stk_Workers = max_Workers/4*3;
701  SchedMutex.UnLock();
702  } else if (dotrace) TRACE(SCHED, "Now have " <<num_Workers <<" workers" );
703 }
704 
705 /******************************************************************************/
706 /* I n i t */
707 /******************************************************************************/
708 
709 void XrdScheduler::Init(int minw, int maxw, int maxi)
710 {
711  min_Workers = minw;
712  max_Workers = maxw;
713  max_Workidl = maxi;
714  num_Workers = 0;
715  num_JobsinQ = 0;
716  stk_Workers = maxw - (maxw/4*3);
717  idl_Workers = 0;
718  num_Jobs = 0;
719  max_QLength = 0;
720  num_TCreate = 0;
721  num_TDestroy= 0;
722  num_Layoffs = 0;
723  num_Limited = 0;
724  firstPID = 0;
725  WorkFirst = WorkLast = TimerQueue = 0;
726 }
727 
728 /******************************************************************************/
729 /* t r a c e E x i t */
730 /******************************************************************************/
731 
732 void XrdScheduler::traceExit(pid_t pid, int status)
733 { const char *why;
734  int retc;
735 
736  if (WIFEXITED(status))
737  {retc = WEXITSTATUS(status);
738  why = " exited with rc=";
739  } else if (WIFSIGNALED(status))
740  {retc = WTERMSIG(status);
741  why = " killed with signal ";
742  } else {retc = 0;
743  why = " changed state ";
744  }
745  TRACE(SCHED, "Process " <<pid <<why <<retc);
746 }
XrdSysError XrdLog(0, "")
int open(const char *path, int oflag,...)
int fcntl(int fd, int cmd,...)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:43
void * XrdStartTSched(void *carg)
Definition: XrdScheduler.cc:81
void * XrdStartWorking(void *carg)
Definition: XrdScheduler.cc:87
void * XrdStartReaper(void *carg)
Definition: XrdScheduler.cc:75
#define MAX_SCHED_PROCS
Definition: XrdScheduler.hh:43
#define XRDSYSTHREAD_BIND
#define TRACE_SCHED
Definition: XrdTrace.hh:42
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACING(x)
Definition: XrdTrace.hh:70
Definition: XrdJob.hh:43
XrdJob * NextJob
Definition: XrdJob.hh:46
friend class XrdScheduler
Definition: XrdJob.hh:44
virtual void DoIt()=0
const char * Comment
Definition: XrdJob.hh:47
XrdSchedulerPID * next
Definition: XrdScheduler.cc:63
XrdSchedulerPID(pid_t newpid, XrdSchedulerPID *prev)
Definition: XrdScheduler.cc:66
int Stats(char *buff, int blen, int do_sync=0)
void Schedule(XrdJob *jp)
void TimeSched()
void setParms(int minw, int maxw, int avlt, int maxi, int once=0)
void Cancel(XrdJob *jp)
void * Reaper()
pid_t Fork(const char *id)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
XrdSysLogger Logger
Definition: XrdGlobals.cc:47
XrdSysTrace XrdTrace
Definition: XrdTrace.hh:56