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