00001
00002
00003
00004
00005
00006
00007
00009 #include "JobControl/JobCEnv.h"
00010 extern "C" {
00011 #ifdef MACOSX
00012 #include <unistd.h>
00013 #else
00014 #include <getopt.h>
00015 #endif
00016 #ifndef GETOPTDONE // Some getopt.h's have this, some don't...
00017 #define GETOPTDONE (-1)
00018 #endif
00019 #include <sys/types.h>
00020 #include <dirent.h>
00021 }
00022 #include <cstdlib>
00023 #include <cassert>
00024 #include <cstring>
00025 #include <csignal>
00026 #include "TEnv.h"
00027 #include "TROOT.h"
00028 #include "TSystem.h"
00029 #include "JobControl/JobCRootEnv.h"
00030 #include "JobControl/JobCleaner.h"
00031 #include "JobControl/JobCFloatXImp.h"
00032 #include "JobControl/IsArgMacroFile.h"
00033 #include "MessageService/MsgService.h"
00034 #include "MinosObjectMap/MomNavigator.h"
00035
00036 CVSID("$Id: JobCEnv.cxx,v 1.42 2007/08/17 01:31:02 rhatcher Exp $");
00037
00038 JobCEnv* JobCEnv::fInstance = 0;
00039 bool gsSIGHUP = false;
00040 bool gsSIGUSR1 = false;
00041
00042
00043
00044 static void gsSIGHUPhandler(int ) { gsSIGHUP = true; }
00045 static void gsSIGUSR1handler(int ) { gsSIGUSR1 = true; }
00046
00047 int JobCEnvSetenv(const char *name, const char *value) {
00048
00049
00050
00051
00052
00053
00054 char *s = new char [strlen(name)+strlen(value)+2];
00055 sprintf(s,"%s=%s",name,value);
00056 int success = ::putenv(s);
00057
00058
00059 return success;
00060 }
00061
00062
00063
00064 JobCEnv::JobCEnv() :
00065 fArgc(0),
00066 fArgv(0),
00067 fModuleHelpList(0),
00068 fDfltOutFile(""),
00069 fTimeStart(time(0)),
00070 fTimeLimit(-1.0),
00071 fRecordLimit(-1),
00072 fIsBatch(false),
00073 fRootEnv(0)
00074 {
00075
00076
00077
00078 }
00079
00080
00081
00082 JobCEnv::JobCEnv(int argc, char** argv) :
00083 fArgc(argc),
00084 fArgv(argv),
00085 fModuleHelpList(0),
00086 fDfltOutFile(""),
00087 fTimeStart(time(0)),
00088 fTimeLimit(-1.0),
00089 fRecordLimit(-1),
00090 fIsBatch(false),
00091 fRootEnv(0)
00092 {
00093
00094
00095
00096 this->ProcessCommandLine(argc,argv);
00097
00098
00099
00100 fRootEnv = new JobCRootEnv(argc,argv);
00101 assert(fRootEnv);
00102
00103
00104 this->SetSignalHandlers();
00105 }
00106
00107
00108
00109 JobCEnv::~JobCEnv()
00110 {
00111
00112
00113
00114 if (fRootEnv) {
00115 delete fRootEnv; fRootEnv = 0;
00116 }
00117 }
00118
00119
00120
00121 const char* JobCEnv::GetModuleHelpList() const
00122 {
00123 return fModuleHelpList;
00124 }
00125
00126
00127
00128 int JobCEnv::GetArgc() const { return fArgc; }
00129
00130
00131
00132 char* const* JobCEnv::GetArgv() const { return fArgv; }
00133
00134
00135
00136 const char* JobCEnv::GetArgv(int i) const
00137 {
00138
00139
00140
00141 assert(i>=0 && i<fArgc);
00142 return fArgv[i];
00143 }
00144
00145
00146
00147 const char* JobCEnv::GetMacroFile(unsigned int i) const
00148 {
00149
00150
00151
00152
00153 if (i<this->fMacroFileList.size()) return fMacroFileList[i].c_str();
00154 else return 0;
00155 }
00156
00157
00158
00159 const char* JobCEnv::GetFileName(int i) const
00160 {
00161
00162
00163
00164
00165 assert(i>=0 && i<this->GetNfile());
00166 return fDataFileList[i].c_str();
00167 }
00168
00169
00170
00171 int JobCEnv::GetNfile() const
00172 {
00173
00174
00175
00176
00177 return fDataFileList.size();
00178 }
00179
00180
00181
00182 const char* JobCEnv::GetDefaultOutputFileName() const
00183 {
00184
00185
00186
00187
00188 return fDfltOutFile.c_str();
00189 }
00190
00191
00192
00193 bool JobCEnv::HaveInaccessibleFile() const
00194 {
00195 if (!fRootEnv) return false;
00196 return fRootEnv->HaveInaccessibleFile();
00197 }
00198
00199
00200
00201 void JobCEnv::SetTimeLimit(const char* s)
00202 {
00203
00204
00205
00206
00207
00208
00209
00210 int i;
00211 float t;
00212 char unit[256];
00213 double fac;
00214
00215 const char* second[] = {"s","second","seconds","sec", "secs", 0};
00216 const char* minute[] = {"m","minute","minutes","min", "mins", 0};
00217 const char* hour[] = {"h","hour","hours","hr","hrs", 0};
00218 const char* day[] = {"d","day","days", 0};
00219 const char* week[] = {"w","week","weeks","wk","wks", 0};
00220 const char* year[] = {"y","year","years","yr","yrs", 0};
00221
00222
00223 sscanf(s,"%f %s",&t,unit);
00224
00225
00226 fac = 0.0;
00227 for (i=0; second[i]!=0; ++i) {
00228 if (strcasecmp(unit,second[i])==0) fac = 1.0;
00229 }
00230 for (i=0; minute[i]!=0; ++i) {
00231 if (strcasecmp(unit,minute[i])==0) fac = 60.0;
00232 }
00233 for (i=0; hour[i]!=0; ++i) {
00234 if (strcasecmp(unit,hour[i])==0) fac = 60.0*60.0;
00235 }
00236 for (i=0; day[i]!=0; ++i) {
00237 if (strcasecmp(unit,day[i])==0) fac = 60.0*60.0*24.0;
00238 }
00239 for (i=0; week[i]!=0; ++i) {
00240 if (strcasecmp(unit,week[i])==0) fac = 60.0*60.0*24.0*7.0;
00241 }
00242 for (i=0; year[i]!=0; ++i) {
00243 if (strcasecmp(unit,year[i])==0) fac=60.0*60.0*24.0*365.25;
00244 }
00245 if (fac==0.0 && strlen(unit)>0) {
00246 MSG("JobC",Msg::kWarning) <<
00247 "Time unit '"<<unit<<"' is not recognized.\n" <<
00248 "Try 's', 'm', 'h', 'd', 'w', or 'y'\n" <<
00249 "Assuming unit given is seconds.\n";
00250 fac = 1.0;
00251 }
00252
00253
00254 fTimeLimit = t*fac;
00255 }
00256
00257
00258
00259 void JobCEnv::SetSignalHandlers()
00260 {
00261
00262
00263
00264 signal(SIGHUP,gsSIGHUPhandler);
00265 signal(SIGUSR1,gsSIGUSR1handler);
00266
00267 bool activateFPE = true;
00268
00269 if(gEnv) {
00270 if(strcasecmp(gEnv->GetValue("Loon.fpe","on"),"off")==0) activateFPE=false;
00271 }
00272 static JobCFloatXImp floatX(activateFPE);
00273
00274 }
00275
00276
00277
00278 bool JobCEnv::CheckRecordLimit(int n) const
00279 {
00280
00281
00282
00283
00284 if (fRecordLimit<0) return false;
00285 if (n>=fRecordLimit) return true;
00286 return false;
00287 }
00288
00289 bool JobCEnv::CheckTimeLimit(int* tsec) const
00290 {
00291
00292
00293
00294
00295 if (fTimeLimit<0.0) return false;
00296
00297 time_t t = time(0);
00298 *tsec = t;
00299 if (difftime(t,fTimeStart) >= fTimeLimit) return true;
00300
00301 return false;
00302 }
00303
00304
00305
00306 bool JobCEnv::ContinueRun(int n) const
00307 {
00308
00309
00310
00311
00312
00313
00314
00315 int t;
00316 if (this->CheckRecordLimit(n) == true) {
00317 MSG("JobC",Msg::kWarning) <<
00318 "Record limit exceeded at "<<n<<" records." << endl;
00319 return false;
00320 }
00321 if (this->CheckTimeLimit(&t) == true) {
00322 MSG("JobC",Msg::kWarning) <<
00323 "Time limit exceeded at "<<t<<" seconds." << endl;
00324 return false;
00325 }
00326 if (gsSIGHUP) {
00327 MSG("JobC",Msg::kWarning) <<
00328 "Process received SIGHUP.\n" << endl;
00329 return false;
00330 }
00331 if (gsSIGUSR1) {
00332 int run, snarl;
00333 MsgService::Instance()->GetCurrentRunSnarl(run,snarl);
00334 cout << flush;
00335 cerr << "JobCEnv: Process " << gSystem->GetPid()
00336 << " received SIGUSR1 after "
00337 << n << " record sets,"
00338 << endl
00339 <<" last processed run " << run << " snarl " << snarl
00340 << flush << endl;
00341 ProcInfo_t pi;
00342 gSystem->GetProcInfo(&pi);
00343 cerr << " CPU: user " << pi.fCpuUser << "s, sys "
00344 << pi.fCpuSys << "s, "
00345 << " Mem: res " << pi.fMemResident
00346 << "k, virtual " << pi.fMemVirtual << "k "
00347 << flush << endl;
00348
00349 gsSIGUSR1 = false;
00350 }
00351 return true;
00352 }
00353
00354
00355
00356 bool JobCEnv::IsBatch() const { return fIsBatch; }
00357
00358
00359
00360 JobCEnv& JobCEnv::Instance()
00361 {
00362 if (fInstance) return *fInstance;
00363 return JobCEnv::Instance(0,0);
00364 }
00365
00366
00367
00368 JobCEnv& JobCEnv::Instance(int argc, char** argv)
00369 {
00370 if (fInstance) return *fInstance;
00371
00372
00373 static JobCEnv::Cleaner c;
00374 c.ClassIsUsed();
00375
00376 fInstance = new JobCEnv(argc, argv);
00377 return *fInstance;
00378 }
00379
00380
00381
00382 int JobCEnv::RunRootApp()
00383 {
00384
00385
00386
00387 if (fRootEnv) {
00388 int r = fRootEnv->RunTheApp();
00389
00390 JobCleaner::Instance().Reap();
00391 return r;
00392 }
00393 return 0;
00394 }
00395
00396
00397
00398 void JobCEnv::ProcessCommandLine(int argc, char *const *argv)
00399 {
00400
00401
00402
00403
00404 int c;
00405
00406 #ifndef MACOSX
00407 optind = 0;
00408 #else
00409 optind = 1;
00410 #endif
00411
00412 #ifdef IRIX6
00413 getoptreset();
00414 #endif
00415 while ((c = getopt(argc, argv, "bs:nqlt:r:x:hH:d:u:p:o:v:")) != GETOPTDONE) {
00416 MSG("JobC",Msg::kDebug) << "Processing job command-line option argument: " << c << endl;
00417 switch (c) {
00418 case 'b': break;
00419 case 's': break;
00420 case 'q': break;
00421 case 'n': break;
00422 case 'l': break;
00423 case 't': this->SetTimeLimit(optarg); break;
00424 case 'r': fRecordLimit = atoi(optarg); break;
00425 case 'x':
00426 this->AddMacroFile(optarg);
00427 break;
00428 case 'h':
00429 MSG("JobC",Msg::kInfo)
00430 << " usage: " << argv[0]
00431 << " -bnq -H<modules> -x<file>"
00432 << " -d<url> -u<user> -p<passwd> -t'<time>' -r[n]"
00433 << " -o<filename> <filenames...>\n"
00434 << " -b: Run in batch mode without graphics.\n"
00435 << " -n: Do not execute logon and logoff macros.\n"
00436 << " -q: Exit after processing command line macro files.\n"
00437 << " -h: Print this friendly help message.\n"
00438 << " -H: Print help for modules in list.\n"
00439 << " -x: Specifies a Job Control Macro to load.\n"
00440 << " Multiple instances of '-x' are allowed.\n"
00441 << " -d: Supply database URL (replaces ENV_TSQL_URL)\n"
00442 << " -u: Supply database user (replaces ENV_TSQL_USER)\n"
00443 << " -p: Supply database password (replaces ENV_TSQL_PSWD)\n"
00444 << " -t: Specify job time limit. Eg. -t'10 minutes'\n"
00445 << " -r: Specify limit on number of records to process.\n"
00446 << " -o: Set the name of the default output file.\n"
00447 << " -v: Set JobC message verbosity [V,D,I,W,E,F].\n";
00448 exit(1);
00449 case 'H': fModuleHelpList = optarg; break;
00450 case 'd': if (optarg) JobCEnvSetenv("ENV_TSQL_URL", optarg); break;
00451 case 'u': if (optarg) JobCEnvSetenv("ENV_TSQL_USER",optarg); break;
00452 case 'p': if (optarg) JobCEnvSetenv("ENV_TSQL_PSWD",optarg); break;
00453 case 'o': fDfltOutFile = optarg; break;
00454 case 'v':
00455 {
00456 Msg::LogLevel_t lvl = Msg::kInfo;
00457 switch (optarg[0]) {
00458 case 'V': case 'v': lvl = Msg::kVerbose; break;
00459 case 'D': case 'd': lvl = Msg::kDebug; break;
00460 case 'I': case 'i': lvl = Msg::kInfo; break;
00461 case 'W': case 'w': lvl = Msg::kWarning; break;
00462 case 'E': case 'e': lvl = Msg::kError; break;
00463 case 'F': case 'f': lvl = Msg::kFatal; break;
00464 default:
00465 MSG("JobC",Msg::kWarning)
00466 << "Can not interpret -v level '" << optarg << "'." << endl;
00467 }
00468 MsgStream *s = MsgService::Instance()->GetStream("JobC");
00469 if (s) s->SetLogLevel(lvl);
00470 else
00471 MSG("JobC",Msg::kWarning)
00472 << "Can not find JobC message stream." << endl;
00473 break;
00474 }
00475 default:
00476 MSG("JobC",Msg::kInfo)
00477 << " getopt returned unexpected character code " << c << "." << endl;
00478 break;
00479 }
00480 }
00481
00482
00483
00484
00485
00486
00487 for (int i=optind; i<argc; ++i) {
00488 int len = strlen(argv[i]);
00489 if (strcmp(argv[i]+len-5,".root")==0) {
00490 this->AddDataFile(argv[i]);
00491 MSG("JobC",Msg::kDebug)
00492 << "JobCEnv::ProcessCommandLine() added data file: "
00493 << argv[i] << endl;
00494 }
00495 else if ( IsArgMacroFile(argv[i]) != "" ) {
00496 MSG("JobC",Msg::kDebug)
00497 << "JobCEnv::ProcessCommandLine() saw macro script: "
00498 << argv[i] << endl;
00499 }
00500 else {
00501 DIR* d = opendir(argv[i]);
00502 if (d) {
00503
00504 closedir(d);
00505 MSG("JobC",Msg::kDebug)
00506 << "JobCEnv::ProcessCommandLine() saw directory: "
00507 << argv[i] << endl;
00508 }
00509 else {
00510 MSG("JobC",Msg::kInfo)
00511 << "JobCEnv::ProcessCommandLine() unrecognizable arg: "
00512 << argv[i] << endl;
00513 }
00514 }
00515 }
00516
00517 }
00518
00519
00520
00521 void JobCEnv::AddDataFile(const char *filename)
00522 {
00523
00524
00525
00526 assert(filename);
00527 string s(filename);
00528 fDataFileList.push_back(s);
00529 }
00530
00531
00532
00533 void JobCEnv::AddMacroFile(const char *filelist)
00534 {
00535
00536
00537
00538 const char *p;
00539 for (p=filelist; *p!='\0';) {
00540 for (; *p==' ' && *p!='\0'; ++p);
00541 if (*p!='\0') {
00542 string s;
00543 s = "";
00544 for (; *p!=' ' && *p!='\0'; ++p) s += *p;
00545 if (s.length()>0) fMacroFileList.push_back(s);
00546 }
00547 }
00548 }
00549