XRootD
Loading...
Searching...
No Matches
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"
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
75void *XrdStartReaper(void *carg)
76 {XrdScheduler *sp = (XrdScheduler *)carg;
77 sp->Reaper();
78 return (void *)0;
79 }
80
81void *XrdStartTSched(void *carg)
82 {XrdScheduler *sp = (XrdScheduler *)carg;
83 sp->TimeSched();
84 return (void *)0;
85 }
86
87void *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//
125XrdScheduler::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
161void 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
180XrdScheduler::~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//
248pid_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
407void 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
442void 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
477void 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
551void 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
597void 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
631int 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
703void 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
745void 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
768void 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
static XrdSysLogger Logger
XrdSysError XrdLog(0, "")
#define close(a)
Definition XrdPosix.hh:48
#define open
Definition XrdPosix.hh:76
#define read(a, b, c)
Definition XrdPosix.hh:82
void * XrdStartWorking(void *carg)
void * XrdStartReaper(void *carg)
void * XrdStartTSched(void *carg)
#define DFL_SCHED_PROCS
#define MAX_SCHED_PROCS
#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
XrdJob * NextJob
Definition XrdJob.hh:46
friend class XrdScheduler
Definition XrdJob.hh:44
XrdJob(const char *desc="")
Definition XrdJob.hh:51
virtual void DoIt()=0
const char * Comment
Definition XrdJob.hh:47
XrdSchedulerPID * next
XrdSchedulerPID(pid_t newpid, XrdSchedulerPID *prev)
int Stats(char *buff, int blen, int do_sync=0)
void Schedule(XrdJob *jp)
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)
XrdSysLogger * logger(XrdSysLogger *lp=0)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)