XRootD
XrdXrootdJob.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d J o b . c c */
4 /* */
5 /* (c) 2006 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cstdio>
32 #include <cstring>
33 #include <netinet/in.h>
34 #include <sys/uio.h>
35 
36 #include "Xrd/XrdLink.hh"
37 #include "Xrd/XrdScheduler.hh"
38 #include "XrdOuc/XrdOucProg.hh"
39 #include "XrdOuc/XrdOucStream.hh"
40 #include "XrdSys/XrdSysError.hh"
41 #include "XrdSys/XrdSysPlatform.hh"
42 #include "XrdSys/XrdSysRAtomic.hh"
46 #include "XProtocol/XProtocol.hh"
47 #include "XProtocol/XPtypes.hh"
48 
49 /******************************************************************************/
50 /* L o c a l C l a s s e s */
51 /******************************************************************************/
52 
53 class XrdXrootdJob2Do : public XrdJob
54 {
55 public:
56 friend class XrdXrootdJob;
57 
58 void DoIt();
59 
61 
63 
65  int jnum,
66  const char **args,
67  XrdXrootdResponse *Resp,
68  int opts);
70 
71 private:
72 int addClient(XrdXrootdResponse *rp, int opts);
73 void delClient(XrdXrootdResponse *rp);
74 XrdOucTList *lstClient(void);
75 int verClient(int dodel=0);
76 void Redrive(void);
77 void sendResult(char *lp, int caned=0, int erc=0);
78 
79 static const int maxClients = 8;
80 struct {XrdLink *Link;
81  unsigned int Inst;
82  kXR_char streamid[2];
83  char isSync;
84  } Client[maxClients];
85 
86  int numClients;
87 
88  XrdOucStream jobStream; // -> Stream for job I/O
89  XrdXrootdJob *theJob; // -> Job description
90  char *theArgs[6]; // -> Program arguments (see XrdOucProg)
91  char *theResult; // -> The result
92  int JobNum; // Job Number
93  int JobRC; // Job kXR_ type return code
94  char JobMark;
95  char doRedrive;
96 static const int argvnum = sizeof(theArgs)/sizeof(theArgs[0]);
97 };
98 
99 /******************************************************************************/
100 /* G l o b a l F u n c t i o n s */
101 /******************************************************************************/
102 
103 namespace XrdXrootd
104 {
105 extern XrdSysError eLog;
106 }
107 using namespace XrdXrootd;
108 
110 
112 {
113  return (item->Status == XrdXrootdJob2Do::Job_Waiting);
114 }
115 
116 /******************************************************************************/
117 /* C l a s s X r d X r o o t d J o b 2 D o */
118 /******************************************************************************/
119 /******************************************************************************/
120 /* C o n s t r u c t o r */
121 /******************************************************************************/
122 
124  int jnum,
125  const char **args,
126  XrdXrootdResponse *resp,
127  int opts)
128  : XrdJob(job->JobName)
129 {
130  int i;
131  for (i = 0; i < argvnum && args[i]; i++) theArgs[i] = strdup(args[i]);
132  for ( ; i < argvnum; i++) theArgs[i] = (char *)0;
133  theJob = job;
134  JobRC = 0;
135  JobNum = jnum;
136  JobMark = 0;
137  numClients = 0;
138  theResult = 0;
139  doRedrive = 0;
141  addClient(resp, opts);
142 }
143 
144 /******************************************************************************/
145 /* D e s t r u c t o r */
146 /******************************************************************************/
147 
149 {
150  int i;
151 
152  for (i = 0; i < numClients; i++)
153  if (!Client[i].isSync) {sendResult(0, 1); break;}
154 
155  for (i = 0; i < argvnum; i++)
156  if (theArgs[i]) free(theArgs[i]);
157 }
158 
159 /******************************************************************************/
160 /* D o I t */
161 /******************************************************************************/
162 
163 #define jobInfo theJob->JobName<<' '<<(theArgs[1] ? theArgs[1] : "")\
164  <<(theArgs[2] ? " " : "")<<(theArgs[2] ? theArgs[2] : "")
165 
167 {
168  static const char *TraceID = "jobXeq";
169  XrdXrootdJob2Do *jp = 0;
170  const char *endStat = " completed";
171  char *lp = 0;
172  int i, rc = 0;
173 
174 // While we were waiting to run we may have been cancelled. If we were not then
175 // perform the actual function and get the result and send to any async clients
176 //
177  if (Status != Job_Cancel)
178  {TRACE(REQ, "Job "<<jobInfo<<" started");
179  if ((rc = theJob->theProg->Run(&jobStream, theArgs[1], theArgs[2],
180  theArgs[3], theArgs[4])))
181  {Status = Job_Cancel;
182  endStat= " failed";
183  lp = jobStream.GetLine();
184  theJob->myMutex.Lock();
185  }
186  else {lp = jobStream.GetLine();
187  rc = theJob->theProg->RunDone(jobStream);
188  theJob->myMutex.Lock();
189  if ((rc && rc != -EPIPE) || (rc == -EPIPE && (!lp || !(*lp))))
190  {Status = Job_Cancel; endStat = " failed";}
191  else if (Status != Job_Cancel)
192  {Status = Job_Done;
193  for (i = 0; i < numClients; i++)
194  if (!Client[i].isSync) {sendResult(lp); break;}
195  }
196  }
197  } else {
198  endStat = " cancelled";
199  theJob->myMutex.Lock();
200  }
201 
202 // Produce a trace record
203 //
204  TRACE(REQ, "Job "<<jobInfo<<endStat);
205 
206 // If the number of jobs > than the max allowed, then redrive a waiting job
207 // if in fact we represent a legitimate job slot (this could a phantom slot
208 // due to ourselves being cancelled.
209 //
210  if (doRedrive)
211  {if (theJob->numJobs > theJob->maxJobs) Redrive();
212  theJob->numJobs--;
213  }
214 
215 // If there are no polling clients left or we have been cancelled, then we
216 // will delete ourselves and, if cancelled, send a notofication to everyone
217 //
218  if (Status != Job_Cancel && numClients) theResult = lp;
219  else {if (Status == Job_Cancel) sendResult(lp, (rc ? -1 : 1), rc);
220  jp = theJob->JobTable.Remove(JobNum);
221  }
222 
223 // At this point we may need to delete ourselves. If so, jp will not be zero.
224 // This must be the last action in this method.
225 //
226  theJob->myMutex.UnLock();
227  if (jp) delete jp;
228 }
229 
230 /******************************************************************************/
231 /* P r i v a t e M e t h o d s */
232 /******************************************************************************/
233 /******************************************************************************/
234 /* a d d C l i e n t */
235 /******************************************************************************/
236 
237 int XrdXrootdJob2Do::addClient(XrdXrootdResponse *rp, int opts)
238 {
239  XrdLink *lp = rp->theLink();
240  unsigned int Inst = lp->Inst();
241  int i;
242 
243 // Remove useless clients
244 //
245  if (numClients >= maxClients) verClient();
246 
247 // See if we are already here
248 //
249  for (i = 0; i < numClients; i++)
250  if (lp == Client[i].Link && Inst == Client[i].Inst) return 0;
251 
252 // Add the client if we can
253 //
254  if (numClients >= maxClients) return -1;
255  Client[numClients].Link = lp;
256  Client[numClients].Inst = Inst;
257  if (opts & JOB_Sync) Client[numClients].isSync = 1;
258  else {rp->StreamID(Client[numClients].streamid);
259  Client[numClients].isSync = 0;
260  }
261  numClients++;
262  JobMark = 0;
263  return 1;
264 }
265 
266 /******************************************************************************/
267 /* d e l C l i e n t */
268 /******************************************************************************/
269 
270 void XrdXrootdJob2Do::delClient(XrdXrootdResponse *rp)
271 {
272  XrdLink *lp = rp->theLink();
273  unsigned int Inst = lp->Inst();
274  int i, j;
275 
276 // See if we are already here
277 //
278  for (i = 0; i < numClients; i++)
279  if (lp == Client[i].Link && Inst == Client[i].Inst)
280  {for (j = i+1; j < numClients; j++) Client[i++] = Client[j];
281  numClients--;
282  break;
283  }
284 }
285 
286 /******************************************************************************/
287 /* l s t C l i e n t */
288 /******************************************************************************/
289 
290 // Warning! The size of buff is large enough for the default number of clients
291 // per job element.
292 //
293 XrdOucTList *XrdXrootdJob2Do::lstClient()
294 {
295  char State, buff[4096], *bp = buff;
296  int bsz, i, k;
297 
298 // Get the state pf the job element
299 //
300  switch(Status)
301  {case Job_Active: State = 'a'; break;
302  case Job_Cancel: State = 'c'; break;
303  case Job_Done: State = 'd'; break;
304  case Job_Waiting: State = 'w'; break;
305  default: State = 'u'; break;
306  };
307 
308 // Insert the header (reserve 8 characters for the trailer)
309 //
310  bp = buff + sprintf(buff, "<s>%c</s><conn>", State);
311  bsz = sizeof(buff) - (bp - buff) - 8;
312 
313 // Remove all clients from a job whose network connection is no longer valid
314 //
315  if (!numClients) bp++;
316  else for (i = 0; i < numClients; i++)
317  if (Client[i].Link && Client[i].Link->isInstance(Client[i].Inst))
318  {if ((k = strlcpy(bp, Client[i].Link->ID, bsz)) >= bsz
319  || (bsz -= k) < 1) {bp++; break;}
320  bp += k; *bp = ' '; bp++; bsz--;
321  }
322 
323 // Insert trailer
324 //
325  if (*(bp-1) == ' ') bp--;
326  strcpy(bp, "</conn>");
327 
328 // Return the text
329 //
330  return new XrdOucTList(buff, bp-buff+7);
331 }
332 
333 /******************************************************************************/
334 /* v e r C l i e n t */
335 /******************************************************************************/
336 
337 int XrdXrootdJob2Do::verClient(int dodel) // Caller must have theJob->myMutex
338 {
339  int i, j, k;
340 
341 // Remove all clients from a job whose network connection is no longer valid
342 //
343  for (i = 0; i < numClients; i++)
344  if (!Client[i].Link->isInstance(Client[i].Inst))
345  {k = i;
346  for (j = i+1; j < numClients && j < maxClients; j++,k++) Client[k] = Client[j];
347  numClients--; i--;
348  }
349 
350 // If no more clients, delete ourselves if safe to do so (caller has lock)
351 //
352  if (!numClients && dodel)
353  {XrdXrootdJob2Do *jp = theJob->JobTable.Remove(JobNum);
354  if (jp)
355  {if (jp->Status == XrdXrootdJob2Do::Job_Waiting) theJob->numJobs--;
356  delete jp;
357  return 0;
358  } else {
359  char ebuff[80];
360  snprintf(ebuff, sizeof(ebuff), "Unable to find %s job %d;",
361  theJob->JobName, JobNum);
362  eLog.Emsg("Job2Do", ebuff, "job slot disabled!");
363  }
364  }
365  return numClients;
366 }
367 
368 /******************************************************************************/
369 /* R e d r i v e */
370 /******************************************************************************/
371 
372 void XrdXrootdJob2Do::Redrive() // Caller must have theJob->myMutex held
373 {
374  XrdXrootdJob2Do *jp;
375  int Start = 0;
376 
377 // Find the first waiting job
378 //
379 
380  while ((jp = theJob->JobTable.Apply(XrdXrootdJobWaiting, (void *)0, Start)))
381  if (jp->verClient(jp->JobMark > 0)) break;
382  else Start = jp->JobNum+1;
383 
384 // Schedule this job if we really have one here
385 //
386  if (jp)
387  {jp->Status = Job_Active; jp->doRedrive = 1;
388  theJob->Sched->Schedule((XrdJob *)jp);
389  }
390 }
391 
392 /******************************************************************************/
393 /* s e n d R e s u l t */
394 /******************************************************************************/
395 
396 // Caller must have theJob->myMutex locked.
397 
398 void XrdXrootdJob2Do::sendResult(char *lp, int caned, int jrc)
399 {
400  static const char *TraceID = "jobSendResult";
401  static const kXR_int32 Xcan = static_cast<kXR_int32>(htonl(kXR_Cancelled));
402  XrdXrootdReqID ReqID;
403  struct iovec jobVec[6];
404  XResponseType jobStat;
405  const char *trc, *tre;
406  kXR_int32 erc;
407  int j, i, dlen = 0, n = 1;
408 
409 // Format the message to be sent
410 //
411  if (!caned && lp)
412  {jobStat = kXR_ok; trc = "ok";
413  if (theArgs[0])
414  { jobVec[n].iov_base = theArgs[0]; // 1
415  dlen = jobVec[n].iov_len = strlen(theArgs[0]); n++;
416  jobVec[n].iov_base = (char *)" "; // 2
417  dlen += jobVec[n].iov_len = 1; n++;
418  }
419  } else {
420  jobStat = kXR_error; trc = "error";
421  if (caned > 0) {erc = Xcan; lp = (char *)"Cancelled by admin.";}
422  else {erc = (jrc ? XProtocol::mapError(jrc) : kXR_ServerError);
423  erc = static_cast<kXR_int32>(htonl(erc));
424  if (!lp || !*lp) lp = (char *)"Program failed.";
425  }
426  jobVec[n].iov_base = (char *)&erc;
427  dlen = jobVec[n].iov_len = sizeof(erc); n++; // 3
428  }
429  jobVec[n].iov_base = lp; // 4
430  dlen += jobVec[n].iov_len = strlen(lp)+1; n++;
431 
432 // Send the response to each client waiting for it
433 //
434  j = 0;
435  for (i = 0; i < numClients; i++)
436  {if (!Client[i].isSync)
437  {ReqID.setID(Client[i].streamid,
438  Client[i].Link->FDnum(), Client[i].Link->Inst());
439  tre = (XrdXrootdResponse::Send(ReqID, jobStat, jobVec, n, dlen) < 0
440  ? "skipped" : "sent");
441  TRACE(RSP, tre <<" async " <<trc <<" to " <<Client[i].Link->ID);
442  } else if (i != j) Client[j++] = Client[i];
443  }
444  numClients = j;
445 }
446 
447 /******************************************************************************/
448 /* C l a s s X r d X r o o t d J o b */
449 /******************************************************************************/
450 /******************************************************************************/
451 /* C o n s t r u c t o r */
452 /******************************************************************************/
453 
455  XrdOucProg *pgm,
456  const char *jname,
457  int maxjobs)
458  : XrdJob("Job Scheduler"),
459  JobTable(maxjobs*3)
460 {
461 // Initialize the base member here
462 //
463  Sched = schp;
464  theProg = pgm;
465  JobName = strdup(jname);
466  maxJobs = maxjobs;
467  numJobs = 0;
468 
469 // Schedule ourselves to run 15 minutes from now
470 //
471  schp->Schedule((XrdJob *)this, time(0) + (reScan));
472 }
473 
474 /******************************************************************************/
475 /* D e s t r u c t o r */
476 /******************************************************************************/
477 
478 // Note! There is no reliable way to delete this object because various
479 // unsynchronized threads may be pending at various break points. Fortunately,
480 // there really is no need to ever delete an object of this kind.
481 
483 {
484  if (JobName) free(JobName);
485  myMutex.Lock();
486  Sched->Cancel((XrdJob *)this);
487  myMutex.UnLock();
488 }
489 
490 /******************************************************************************/
491 /* C a n c e l */
492 /******************************************************************************/
493 
494 int XrdXrootdJob::Cancel(const char *jkey, XrdXrootdResponse *resp)
495 {
496  XrdXrootdJob2Do *jp = 0;
497  int i, jNum, jNext = 0, numcaned = 0;
498 
499 // Lock our data
500 //
501  myMutex.Lock();
502 
503 // Cancel a specific job if a key was passed
504 //
505  if (jkey)
506  {if ((jp = JobTable.Find(jkey)))
507  {numcaned = 1;
508  if (resp) {jp->delClient(resp);
509  if (!jp->numClients) CleanUp(jp);
510  }
511  else CleanUp(jp);
512  }
513  myMutex.UnLock();
514  return numcaned;
515  }
516 
517 // Delete multiple jobs
518 //
519  while((jNum = JobTable.Next(jNext)) >= 0)
520  {jp = JobTable.Item(jNum);
521  if (resp)
522  {i = jp->numClients;
523  jp->delClient(resp);
524  if (i != jp->numClients) numcaned++;
525  if (!jp->numClients) CleanUp(jp);
526  } else {
527  CleanUp(jp);
528  numcaned++;
529  }
530  }
531 
532 // All done
533 //
534  myMutex.UnLock();
535  return numcaned;
536 }
537 
538 /******************************************************************************/
539 /* D o I t */
540 /******************************************************************************/
541 
543 {
544  int jNum, jNext = 0;
545  XrdXrootdJob2Do *jp;
546 
547 // Scan through all of the jobs looking for disconnected clients
548 //
549  while((jNum = JobTable.Next(jNext)) >= 0)
550  {myMutex.Lock();
551  if ((jp = JobTable.Item(jNum)))
552  {if (jp->JobMark) {if (!jp->verClient()) CleanUp(jp);}
553  else jp->JobMark = 1;
554  }
555  myMutex.UnLock();
556  }
557 
558 // Schedule ourselves to run 15 minutes from now
559 //
560  Sched->Schedule((XrdJob *)this, time(0) + (reScan));
561 }
562 
563 /******************************************************************************/
564 /* L i s t */
565 /******************************************************************************/
566 
567 // Output: <job id="jname">%jobkey<s>%status</s><c>%clientid ...</c> ....</job>
568 //
570 {
571  char *jkey, buff[1024];
572  int tlen, jNum, jNext = 0;
573  XrdXrootdJob2Do *jp;
574  XrdOucTList *tF = 0, *tL = 0, *tp;
575 
576 // Scan through all of the jobs listing each, in turn
577 //
578  while((jNum = JobTable.Next(jNext)) >= 0)
579  {myMutex.Lock();
580  if ((jp = JobTable.Item(jNum, &jkey)) && (tp = jp->lstClient()))
581  {tlen = sprintf(buff, "<job id=\"%s\">%s", JobName, jkey);
582  if (tL) tL->next = new XrdOucTList(buff, tlen, tp);
583  else tF = new XrdOucTList(buff, tlen, tp);
584  tL = tp->next = new XrdOucTList("</job>", 6);
585  }
586  myMutex.UnLock();
587  }
588 
589 // Return the whole schmear
590 //
591  return tF;
592 }
593 
594 /******************************************************************************/
595 /* S c h e d u l e */
596 /******************************************************************************/
597 
598 int XrdXrootdJob::Schedule(const char *jkey,
599  const char **args,
600  XrdXrootdResponse *resp,
601  int Opts)
602 {
603  XrdXrootdJob2Do *jp;
604  const char *msg = "Job resources currently not available.";
605  int jobNum, rc, isSync = Opts & JOB_Sync;
606 
607 // Make sure we have a target
608 //
609  if (!jkey || !(*jkey))
610  return resp->Send(kXR_ArgMissing, "Job target not specified.");
611 
612 // First find if this is a duplicate or create a new one
613 //
614  myMutex.Lock();
615  if (!(Opts & JOB_Unique) && (jp = JobTable.Find(jkey)))
616  {if (jp->Status == XrdXrootdJob2Do::Job_Done)
617  {rc = sendResult(resp, args[0], jp);
618  myMutex.UnLock();
619  return rc;
620  }
621  if (jp->addClient(resp, Opts) < 0) isSync = 1;
622  else msg = "Job scheduled.";
623  } else {
624  if ((jobNum = JobTable.Alloc()) < 0) isSync = 1;
625  else {if ((jp = new XrdXrootdJob2Do(this, jobNum, args, resp, Opts)))
626  {JobTable.Insert(jp, jkey, jobNum);
627  if (numJobs < maxJobs)
628  {Sched->Schedule((XrdJob *)jp);
629  jp->Status = XrdXrootdJob2Do::Job_Active;
630  jp->doRedrive = 1;
631  }
632  numJobs++; msg = "Job Scheduled";
633  }
634  }
635  }
636 
637 // Tell the client to wait
638 //
639  if (isSync) rc = resp->Send(kXR_wait, 30, msg);
640  else rc = resp->Send(kXR_waitresp, 600, "Job scheduled.");
641  myMutex.UnLock();
642  return rc;
643 }
644 
645 /******************************************************************************/
646 /* P r i v a t e M e t h o d s */
647 /******************************************************************************/
648 /******************************************************************************/
649 /* C l e a n U p */
650 /******************************************************************************/
651 
652 // The caller must have myMutex locked
653 
654 void XrdXrootdJob::CleanUp(XrdXrootdJob2Do *jp)
655 {
656  int theStatus = jp->Status;
657 
658 // Now we have to be careful. If the job is waiting or completed schedule
659 // it for cancellation. If it's active then kill the associated process. The
660 // thread waiting for the result will see the cancellation. Otherwise, it
661 // already has been cancelled and is in the scheduled queue.
662 //
664  if (theStatus == XrdXrootdJob2Do::Job_Waiting
665  || theStatus == XrdXrootdJob2Do::Job_Done)
666  Sched->Schedule((XrdJob *)jp);
667  else{if (theStatus == XrdXrootdJob2Do::Job_Active) jp->jobStream.Drain();}
668 
669  if (theStatus == XrdXrootdJob2Do::Job_Waiting) numJobs--;
670 }
671 
672 /******************************************************************************/
673 /* s e n d R e s u l t */
674 /******************************************************************************/
675 
676 // Caller must have myMutex locked.
677 
678 int XrdXrootdJob::sendResult(XrdXrootdResponse *resp,
679  const char *rpfx,
680  XrdXrootdJob2Do *job)
681 {
682  struct iovec jobResp[4];
683  int dlen, i, rc;
684 
685 // Send an error result if no result is present
686 //
687  if (!(job->theResult)) rc = resp->Send(kXR_ServerError,"Program failed");
688  else {if (!rpfx) {dlen = 0; i = 1;}
689  else { jobResp[1].iov_base = (char *)rpfx;
690  dlen = jobResp[1].iov_len = strlen(rpfx);
691  jobResp[2].iov_base = (char *)" ";
692  dlen += jobResp[2].iov_len = 1;
693  i = 3;
694  }
695  jobResp[i].iov_base = job->theResult;
696  dlen += jobResp[i].iov_len = strlen(job->theResult);
697  rc = resp->Send(jobResp, i+1, dlen);
698  }
699 
700 // Remove the client from the job. Check if clean-up is required
701 //
702  job->delClient(resp);
703  if (!job->numClients) CleanUp(job);
704 
705 // All done
706 //
707  return rc;
708 }
@ kXR_ArgMissing
Definition: XProtocol.hh:991
@ kXR_Cancelled
Definition: XProtocol.hh:1007
@ kXR_ServerError
Definition: XProtocol.hh:1002
XResponseType
Definition: XProtocol.hh:898
@ kXR_waitresp
Definition: XProtocol.hh:906
@ kXR_ok
Definition: XProtocol.hh:899
@ kXR_wait
Definition: XProtocol.hh:905
@ kXR_error
Definition: XProtocol.hh:903
int kXR_int32
Definition: XPtypes.hh:89
unsigned char kXR_char
Definition: XPtypes.hh:65
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
XrdSysTrace XrdXrootdTrace
int XrdXrootdJobWaiting(XrdXrootdJob2Do *item, void *arg)
#define jobInfo
#define JOB_Unique
Definition: XrdXrootdJob.hh:49
#define JOB_Sync
Definition: XrdXrootdJob.hh:48
static int mapError(int rc)
Definition: XProtocol.hh:1361
Definition: XrdJob.hh:43
int RunDone(XrdOucStream &cmd) const
Definition: XrdOucProg.cc:257
int Run(XrdOucStream *Sp, const char *argV[], int argc=0, const char *envV[]=0) const
Definition: XrdOucProg.cc:108
char * GetLine()
T * Find(const char *key, int *Tnum=0)
Definition: XrdOucTable.hh:93
T * Apply(int(*func)(T *, void *), void *Arg, int Start=0)
Definition: XrdOucTable.hh:67
T * Remove(int Tnum)
Definition: XrdOucTable.hh:132
T * Item(int Tnum, char **ikey=0)
Definition: XrdOucTable.hh:114
int Insert(T *Item, const char *key=0, int Tnum=-1)
Definition: XrdOucTable.hh:105
int Next(int &Tnum)
Definition: XrdOucTable.hh:123
void Schedule(XrdJob *jp)
void Cancel(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdXrootdJob2Do(XrdXrootdJob *job, int jnum, const char **args, XrdXrootdResponse *Resp, int opts)
XrdSys::RAtomic< JobStatus > Status
Definition: XrdXrootdJob.cc:62
XrdXrootdJob(XrdScheduler *schp, XrdOucProg *pgm, const char *jname, int maxjobs=4)
int Schedule(const char *jkey, const char **args, XrdXrootdResponse *resp, int Opts=0)
friend class XrdXrootdJob2Do
Definition: XrdXrootdJob.hh:53
int Cancel(const char *jkey=0, XrdXrootdResponse *resp=0)
XrdOucTList * List(void)
void setID(unsigned long long id)
void StreamID(kXR_char *sid)
XrdScheduler Sched
Definition: XrdLinkCtl.cc:54
int Opts
Definition: XrdMpxStats.cc:58
XrdSysError * eLog
XrdSysError eLog