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