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{
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//
123XrdScheduler::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
158void 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
177XrdScheduler::~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//
245pid_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
404void 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
439void 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
474void 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
537// The above may allow way too many threads. We make sure that the default
538// maximum threads is adhered to.
539//
540 if (max_Workers > DFL_SCHED_PROCS) max_Workers = DFL_SCHED_PROCS;
541#endif
542}
543
544/******************************************************************************/
545/* s e t P a r m s */
546/******************************************************************************/
547
548void XrdScheduler::setParms(int minw, int maxw, int avlw, int maxi, int once)
549{
550 static int isSet = 0;
551
552// Lock the data area and check for 1-time set
553//
554 SchedMutex.Lock();
555 if (once && isSet) {SchedMutex.UnLock(); return;}
556 isSet = 1;
557
558// get a consistent view of all the values
559//
560 if (maxw <= 0) maxw = max_Workers;
561 if (minw < 0) minw = min_Workers;
562 if (minw > maxw) minw = maxw;
563 if (avlw < 0) avlw = maxw/4*3;
564 else if (avlw > maxw) avlw = maxw;
565
566// Set the values
567//
568 min_Workers = minw;
569 max_Workers = maxw;
570 stk_Workers = maxw - avlw;
571 if (maxi >=0) max_Workidl = maxi;
572
573// Unlock the data area
574//
575 SchedMutex.UnLock();
576
577// If we have an idle interval, schedule the idle check
578//
579 if (maxi > 0)
580 {Cancel((XrdJob *)this);
581 Schedule((XrdJob *)this, (time_t)maxi+time(0));
582 }
583
584// Debug the info
585//
586 TRACE(SCHED,"Set min_Workers=" <<min_Workers <<" max_Workers=" <<max_Workers);
587 TRACE(SCHED,"Set stk_Workers=" <<stk_Workers <<" max_Workidl=" <<max_Workidl);
588}
589
590/******************************************************************************/
591/* S t a r t */
592/******************************************************************************/
593
594void XrdScheduler::Start() // Serialized one time call!
595{
596 int retc, numw;
597 pthread_t tid;
598
599// Provide ABI compatibility for XrdOucTrace which is deprecated!
600//
601 if (getenv("XRDDEBUG") != 0) XrdTrace->What = TRACE_SCHED;
602 else if (XrdTraceOld) XrdTrace->What |= XrdTraceOld->What;
603
604// Start a time based scheduler
605//
606 if ((retc = XrdSysThread::Run(&tid, XrdStartTSched, (void *)this,
607 XRDSYSTHREAD_BIND, "Time scheduler")))
608 XrdLog->Emsg("Scheduler", retc, "create time scheduler thread");
609
610// If we an idle interval, schedule the idle check
611//
612 if (max_Workidl > 0) Schedule((XrdJob *)this, (time_t)max_Workidl+time(0));
613
614// Start 1/3 of the minimum number of threads
615//
616 if (!(numw = min_Workers/3)) numw = 2;
617 while(numw--) hireWorker(0);
618
619// Unlock the data area
620//
621 TRACE(SCHED, "Starting with " <<num_Workers <<" workers" );
622}
623
624/******************************************************************************/
625/* S t a t s */
626/******************************************************************************/
627
628int XrdScheduler::Stats(char *buff, int blen, int do_sync)
629{
630 int cnt_Jobs, cnt_JobsinQ, xam_QLength, cnt_Workers, cnt_idl;
631 int cnt_TCreate, cnt_TDestroy, cnt_Limited;
632 static const char statfmt[] = "<stats id=\"sched\"><jobs>%d</jobs>"
633 "<inq>%d</inq><maxinq>%d</maxinq>"
634 "<threads>%d</threads><idle>%d</idle>"
635 "<tcr>%d</tcr><tde>%d</tde>"
636 "<tlimr>%d</tlimr></stats>";
637
638// If only length wanted, do so
639//
640 if (!buff) return sizeof(statfmt) + 16*8;
641
642// Get values protected by the Dispatch lock (avoid lock if no sync needed)
643//
644 if (do_sync) DispatchMutex.Lock();
645 cnt_idl = idl_Workers;
646 if (do_sync) DispatchMutex.UnLock();
647
648// Get values protected by the Scheduler lock (avoid lock if no sync needed)
649//
650 if (do_sync) SchedMutex.Lock();
651 cnt_Workers = num_Workers;
652 cnt_Jobs = num_Jobs;
653 cnt_JobsinQ = num_JobsinQ;
654 xam_QLength = max_QLength;
655 cnt_TCreate = num_TCreate;
656 cnt_TDestroy= num_TDestroy;
657 cnt_Limited = num_Limited;
658 if (do_sync) SchedMutex.UnLock();
659
660// Format the stats and return them
661//
662 return snprintf(buff, blen, statfmt, cnt_Jobs, cnt_JobsinQ, xam_QLength,
663 cnt_Workers, cnt_idl, cnt_TCreate, cnt_TDestroy,
664 cnt_Limited);
665}
666
667/******************************************************************************/
668/* T i m e S c h e d */
669/******************************************************************************/
670
672{
673 XrdJob *jp;
674 int wtime;
675
676// Continuous loop until we find some work here
677//
678 do {TimerMutex.Lock();
679 if (TimerQueue) wtime = TimerQueue->SchedTime-time(0);
680 else wtime = 60*60;
681 if (wtime > 0)
682 {TimerMutex.UnLock();
683 TimerRings.Wait(wtime);
684 } else {
685 jp = TimerQueue;
686 TimerQueue = jp->NextJob;
687 Schedule(jp);
688 TimerMutex.UnLock();
689 }
690 } while(1);
691}
692
693/******************************************************************************/
694/* P r i v a t e M e t h o d s */
695/******************************************************************************/
696/******************************************************************************/
697/* h i r e W o r k e r */
698/******************************************************************************/
699
700void XrdScheduler::hireWorker(int dotrace)
701{
702 pthread_t tid;
703 int retc;
704
705// First check if we reached the maximum number of workers
706//
707 SchedMutex.Lock();
708 if (num_Workers >= max_Workers)
709 {num_Limited++;
710 if ((num_Limited & 4095) == 1)
711 XrdLog->Emsg("Scheduler","Thread limit has been reached!");
712 SchedMutex.UnLock();
713 return;
714 }
715 num_Workers++;
716 num_TCreate++;
717 SchedMutex.UnLock();
718
719// Start a new thread. We do this without the schedMutex to avoid hang-ups. If
720// we can't start a new thread, we recalculate the maximum number we can.
721//
722 retc = XrdSysThread::Run(&tid, XrdStartWorking, (void *)this, 0, "Worker");
723
724// Now check the results and correct if we couldn't start the thread
725//
726 if (retc)
727 {XrdLog->Emsg("Scheduler", retc, "create worker thread");
728 SchedMutex.Lock();
729 num_Workers--;
730 num_TCreate--;
731 max_Workers = num_Workers;
732 min_Workers = (max_Workers/10 ? max_Workers/10 : 1);
733 stk_Workers = max_Workers/4*3;
734 SchedMutex.UnLock();
735 } else if (dotrace) TRACE(SCHED, "Now have " <<num_Workers <<" workers" );
736}
737
738/******************************************************************************/
739/* I n i t */
740/******************************************************************************/
741
742void XrdScheduler::Init(int minw, int maxw, int maxi)
743{
744 min_Workers = minw;
745 max_Workers = maxw;
746 max_Workidl = maxi;
747 num_Workers = 0;
748 num_JobsinQ = 0;
749 stk_Workers = maxw - (maxw/4*3);
750 idl_Workers = 0;
751 num_Jobs = 0;
752 max_QLength = 0;
753 num_TCreate = 0;
754 num_TDestroy= 0;
755 num_Layoffs = 0;
756 num_Limited = 0;
757 firstPID = 0;
758 WorkFirst = WorkLast = TimerQueue = 0;
759}
760
761/******************************************************************************/
762/* t r a c e E x i t */
763/******************************************************************************/
764
765void XrdScheduler::traceExit(pid_t pid, int status)
766{ const char *why;
767 int retc;
768
769 if (WIFEXITED(status))
770 {retc = WEXITSTATUS(status);
771 why = " exited with rc=";
772 } else if (WIFSIGNALED(status))
773 {retc = WTERMSIG(status);
774 why = " killed with signal ";
775 } else {retc = 0;
776 why = " changed state ";
777 }
778 TRACE(SCHED, "Process " <<pid <<why <<retc);
779}
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)