80498331460dacf3a53794f95c205f94eb44fe64
[u/mrichter/AliRoot.git] / MONITOR / AliOnlineReco.cxx
1 // @(#)root/eve:$Id$
2 // Author: Matevz Tadel 2007
3
4 /**************************************************************************
5  * Copyright(c) 1998-2008, ALICE Experiment at CERN, all rights reserved. *)
6  * See http://aliceinfo.cern.ch/Offline/AliRoot/License.html for          *
7  * full copyright notice.                                                 *
8  **************************************************************************/
9
10 #include "AliOnlineReco.h"
11 #include "AliChildProcTerminator.h"
12 #include "AliDimIntNotifier.h"
13 #include "AliCDBManager.h"
14 #include "AliGRPPreprocessor.h"
15
16 #include <TTimer.h>
17
18 #include <TGListBox.h>
19 #include <TGButton.h>
20
21 #include <TInterpreter.h>
22 #include <TROOT.h>
23
24 #include <unistd.h>
25 #include <signal.h>
26
27 //______________________________________________________________________________
28 // Full description of AliOnlineReco
29 //
30
31 ClassImp(AliOnlineReco)
32
33 AliOnlineReco::AliOnlineReco() :
34   TGMainFrame(gClient->GetRoot(), 400, 400),
35
36   fRunList(0), fAutoRun(0), fStartButt(0), fStopButt(0), fExitButt(0),
37   fAutoRunTimer(0), fAutoRunScheduled(0), fAutoRunRunning(0),
38   fRun2PidMap(),
39   fTestMode(kFALSE),
40   fDoExit(kFALSE)
41 {
42   // Constructor.
43
44   // GUI components.
45   fRunList = new TGListBox(this);
46   AddFrame(fRunList, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY));
47
48   TGHorizontalFrame *hf = new TGHorizontalFrame(this, 1, 20);
49
50   fAutoRun = new TGCheckButton(hf, "AutoRun");
51   hf->AddFrame(fAutoRun, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY));
52   fAutoRun->Connect("Clicked()", "AliOnlineReco", this, "DoAutoRun()");
53
54   fStartButt = new TGTextButton(hf, "Start");
55   hf->AddFrame(fStartButt, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY));
56   fStartButt->Connect("Clicked()", "AliOnlineReco", this, "DoStart()");
57
58   fStopButt = new TGTextButton(hf, "Stop");
59   hf->AddFrame(fStopButt, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY));
60   fStopButt->Connect("Clicked()", "AliOnlineReco", this, "DoStop()");
61
62   fExitButt = new TGTextButton(hf, "Exit");
63   hf->AddFrame(fExitButt, new TGLayoutHints(kLHintsNormal | kLHintsExpandX | kLHintsExpandY));
64   fExitButt->Connect("Clicked()", "AliOnlineReco", this, "DoExit()");
65
66   AddFrame(hf, new TGLayoutHints(kLHintsNormal | kLHintsExpandX));
67
68   MapSubwindows();
69   Layout();
70   SetWindowName("Alice Online Reconstruction");
71
72   // DIM interface.  
73   for (Int_t i = 0; i < 5; ++i)
74   {
75     if (i == 0)
76     {
77       fSOR[i] = new AliDimIntNotifier("/LOGBOOK/SUBSCRIBE/DAQ_SOR_PHYSICS");
78       fEOR[i] = new AliDimIntNotifier("/LOGBOOK/SUBSCRIBE/DAQ_EOR_PHYSICS");
79     }
80     else
81     {
82       fSOR[i] = new AliDimIntNotifier(Form("/LOGBOOK/SUBSCRIBE/DAQ_SOR_PHYSICS_%d", i));
83       fEOR[i] = new AliDimIntNotifier(Form("/LOGBOOK/SUBSCRIBE/DAQ_EOR_PHYSICS_%d", i));
84     }
85
86     fSOR[i]->Connect("DimMessage(Int_t)", "AliOnlineReco", this, "StartOfRun(Int_t)");
87     fEOR[i]->Connect("DimMessage(Int_t)", "AliOnlineReco", this, "EndOfRun(Int_t)");
88   }
89
90   const Int_t autoRunDelay = 10; // should go to config
91   fAutoRunTimer = new TTimer(autoRunDelay * 1000l);
92   fAutoRunTimer->Connect("Timeout()", "AliOnlineReco", this, "AutoRunTimerTimeout()");
93
94   // OS Signal handlers
95   // ROOT's TSignalHAndler works not SIGCHLD ...
96   AliChildProcTerminator::Instance()->Connect("ChildProcTerm(Int_t,Int_t)", "AliOnlineReco", this, "ChildProcTerm(Int_t,Int_t)");
97   
98   // we need this by OnExit() to kill next process child after another
99   Connect("ChildProcTerm(Int_t,Int_t)", "AliOnlineReco", this, "ExitLoopChildProcTerm()");
100 }
101
102 AliOnlineReco::~AliOnlineReco()
103 {
104   // Destructor.
105
106   delete fAutoRunTimer;
107 }
108
109 Int_t AliOnlineReco::GetLastRun() const
110 {
111   // Returns the last started run.
112
113   return fRun2PidMap.empty() ? 0 : fRun2PidMap.rbegin()->first;
114 }
115
116 Bool_t AliOnlineReco::GetAutoRunMode() const
117 {
118   // Return state of auto-run flag.
119
120   return fAutoRun->IsOn();
121 }
122
123 void AliOnlineReco::SetAutoRunMode(Bool_t ar)
124 {
125   // Set auto-run flag.
126
127   if (ar == fAutoRun->IsOn())
128     return;
129
130   fAutoRun->SetState(ar ? kButtonDown : kButtonUp, kTRUE);
131 }
132
133 //------------------------------------------------------------------------------
134 // Private methods
135 //------------------------------------------------------------------------------
136
137 AliOnlineReco::mIntInt_i AliOnlineReco::FindMapEntryByPid(Int_t pid)
138 {
139   // Find run-to-pid map iterator by pid.
140   // Requires iteration over map.
141
142   for (mIntInt_i i = fRun2PidMap.begin(); i != fRun2PidMap.end(); ++i)
143   {
144     if (i->second == pid)
145       return i;
146   }
147
148   return fRun2PidMap.end();
149 }
150
151 void AliOnlineReco::StartAliEve(mIntInt_i& mi)
152 {
153   // Start alieve to process run given my the run-pid entry.
154
155   Int_t run = mi->first;
156
157   if (mi->second == 0)
158   {
159     pid_t pid = fork();
160     if (pid == -1)
161     {
162       perror("DoStart -- Fork failed");
163       return;
164     }
165
166     if (pid)
167     {
168       mi->second = pid;
169       fRunList->RemoveEntry(run);
170       fRunList->AddEntrySort(TString::Format("%-20d -- RUNNING", run), run);
171       fRunList->Layout();
172     }
173     else
174     {
175       gCINTMutex = 0;
176
177       struct sigaction sac;
178       memset(&sac, 0, sizeof(sac));
179       sac.sa_handler = NULL;
180       sigemptyset(&sac.sa_mask);
181       sac.sa_flags = 0;
182       
183       // The sa_restorer field is Not POSIX and obsolete.
184       // This is for compilation on other systems
185       #if defined(__linux) && \
186           (defined(__i386__) || defined(__x86_64__)) && \
187            defined(__GNUC__)
188       sac.sa_restorer= NULL;
189       #endif
190       sigaction(SIGCHLD, &sac, NULL);
191   
192       int s;
193       if (fTestMode)
194       {
195         s = execlp("alitestproc", "alitestproc", TString::Format("%d", run).Data(), (char*) 0);
196       }
197       else
198       {
199         Int_t procPID = gSystem->GetPid();
200         TString logFile = Form("%s/reco/log/run%d_%d.log",
201              gSystem->Getenv("ONLINERECO_BASE_DIR"),
202              run,
203             (Int_t)procPID);
204         Info("DoStart","Reconstruction log will be written to %s",logFile.Data());
205         gSystem->RedirectOutput(logFile.Data());
206
207         gSystem->cd(Form("%s/reco",gSystem->Getenv("ONLINERECO_BASE_DIR")));
208
209         TString gdcs;
210         if (RetrieveGRP(run,gdcs) <= 0 || gdcs.IsNull()) 
211           gSystem->Exit(1);
212
213         gSystem->Setenv("DATE_RUN_NUMBER", Form("%d", run));
214         // Setting CDB
215         //      AliCDBManager * man = AliCDBManager::Instance();
216         //      man->SetDefaultStorage("local:///local/cdb");
217         //      man->SetSpecificStorage("GRP/GRP/Data",
218         //                            Form("local://%s",gSystem->pwd()));
219         //      man->SetSpecificStorage("GRP/CTP/Config",
220         //                            Form("local://%s",gSystem->pwd()));
221         //      man->SetSpecificStorage("ACORDE/Align/Data",
222         //                              "local://$ALICE_ROOT/OCDB");
223
224         gSystem->mkdir(Form("run%d_%d", run, (Int_t)procPID));
225         gSystem->cd(Form("run%d_%d", run, (Int_t)procPID));
226
227         TString recMacroPath(gSystem->Getenv("ONLINERECO_MACRO"));
228         if (recMacroPath.IsNull()) {
229           recMacroPath = "$ALICE_ROOT/MONITOR/rec.C";
230         }
231         
232         s = execlp("alieve",
233              "alieve",
234              "-q",
235              Form("%s(\"mem://@*:\")", gSystem->ExpandPathName(recMacroPath.Data())),
236              (char*) 0);
237
238         gSystem->Exec(Form("rm -rf %s/reco/run%d_%d",gSystem->Getenv("ONLINERECO_BASE_DIR"),run,(Int_t)procPID));
239       }
240
241       if (s == -1)
242       {
243         perror("execlp failed - this will not end well");
244         gSystem->Exit(1);
245       }
246     }
247   }
248   else
249   {
250     Error("DoStart", "Process already running.");
251   }
252 }
253
254 void AliOnlineReco::KillPid(Int_t pid)
255 {
256   // Terminate process given by pid.
257
258   // Send terminate signal to process ...
259
260   if (fTestMode)
261   {
262     kill(pid, SIGTERM);
263   }
264   else
265   {
266     // alieve will auto-destruct on SIGUSR1
267     kill(pid, SIGUSR1);
268   }
269 }
270
271 void AliOnlineReco::StartAutoRunTimer(Int_t run)
272 {
273   // Start timer for given run.
274   // If an auto-started run is already active, this call is ignored.
275   // If timer is already active, it is restarted.
276
277   if (fAutoRunRunning)
278     return;
279
280   fAutoRunTimer->Reset();
281   fAutoRunTimer->TurnOn();
282   fAutoRunScheduled = run;
283
284   Info("StartAutoRunTimer", "Scheduling run %d for auto-display.", run);
285 }
286
287 void AliOnlineReco::StopAutoRunTimer()
288 {
289   // Stop auto-run timer.
290
291   fAutoRunTimer->TurnOff();
292   fAutoRunScheduled = 0;
293 }
294
295 void AliOnlineReco::AutoRunTimerTimeout()
296 {
297   // Slot called on auto-timer timeout.
298
299   Int_t run = fAutoRunScheduled;
300
301   StopAutoRunTimer();
302
303   mIntInt_i i = fRun2PidMap.find(run);
304
305   if (i == fRun2PidMap.end())
306   {
307     Warning("AutoRunTimerTimeout", "run no longer active.");
308     return;
309   }
310
311   Info("AutoRunTimerTimeout", "Starting display for run %d.", run);
312
313   StartAliEve(i);
314   fAutoRunRunning = run;
315 }
316
317 //------------------------------------------------------------------------------
318 // Handlers of DIM signals.
319 //------------------------------------------------------------------------------
320
321 void AliOnlineReco::StartOfRun(Int_t run)
322 {
323   // Slot called from DIM handler on start of run.
324
325   mIntInt_i i = fRun2PidMap.find(run);
326   if (i == fRun2PidMap.end())
327   {
328     fRun2PidMap[run] = 0;
329     fRunList->AddEntrySort(TString::Format("%d", run), run);
330     fRunList->Layout();
331
332     if (fAutoRun->IsOn())
333     {
334       StartAutoRunTimer(run);
335     }
336   }
337   else
338   {
339     Error("StartOfRun", "Run %d already registered.", run);
340   }
341 }
342
343 void AliOnlineReco::EndOfRun(Int_t run)
344 {
345   // Slot called from DIM handler on stop of run.
346
347   mIntInt_i i = fRun2PidMap.find(run);
348   if (i != fRun2PidMap.end())
349   {
350     Int_t pid = i->second;
351     fRunList->RemoveEntry(run);
352     fRunList->Layout();
353     fRun2PidMap.erase(i);
354     if (pid)
355     {
356       KillPid(pid);
357     }
358     gClient->NeedRedraw(fRunList);
359
360     if (fAutoRunRunning == run)
361     {
362       fAutoRunRunning = 0;
363     }
364   }
365   else
366   {
367     Error("EndOfRun", "Run %d not registered.", run);
368   }
369 }
370
371 //------------------------------------------------------------------------------
372 // Handlers of OS signals.
373 //------------------------------------------------------------------------------
374
375 void AliOnlineReco::ChildProcTerm(Int_t pid, Int_t status)
376 {
377   // Slot called on termination of child process.
378  
379   printf("child process termination pid=%d, status=%d...\n", pid, status);
380
381   mIntInt_i i = FindMapEntryByPid(pid);
382   if (i != fRun2PidMap.end())
383   {
384     Int_t run = i->first;
385     fRunList->RemoveEntry(run);
386     if (status == 0)
387     {
388       fRunList->AddEntrySort(TString::Format("%-20d -- PROCESSED", run), run);
389     }
390     else
391     {
392       fRunList->AddEntrySort(TString::Format("%-20d -- PROCESSED [%d]", run, status), run);
393     }
394     fRunList->Layout();
395     fRun2PidMap.erase(i);
396
397     if (fAutoRunRunning == run && fAutoRun->IsOn())
398     {
399       fAutoRunRunning = 0;
400       StartAutoRunTimer(run);
401     }
402     else
403     {
404       fAutoRunRunning = 0;
405     }
406   }
407   else
408   {
409     Warning("ChildProcTerm", "Process with pid=%d not registered.", pid);
410   }
411  
412   Emit("ChildProcTerm(Int_t, Int_t)");
413 }
414
415 void AliOnlineReco::ExitLoopChildProcTerm()
416 {
417   if(fDoExit)
418     DoExit();
419 }
420
421 //------------------------------------------------------------------------------
422 // Handlers of button signals.
423 //------------------------------------------------------------------------------
424
425 void AliOnlineReco::DoAutoRun()
426 {
427   // Slot called from auto-run check-box.
428
429   Bool_t autoRun = fAutoRun->IsOn();
430
431   if (autoRun)
432     fStartButt->SetEnabled(kFALSE);
433   else
434     fStartButt->SetEnabled(kTRUE);    
435 }
436
437 void AliOnlineReco::DoStart()
438 {
439   // Slot called from Start button.
440
441   Int_t run = fRunList->GetSelected();
442   mIntInt_i i = fRun2PidMap.find(run);
443
444   if (i == fRun2PidMap.end())
445   {
446     Error("DoStart", "no selection");
447     return;
448   }
449
450   StartAliEve(i);
451 }
452
453 void AliOnlineReco::DoStop()
454 {
455   // Slot called from Stop button.
456
457   Int_t run = fRunList->GetSelected();
458   mIntInt_i i = fRun2PidMap.find(run);
459
460   if (i == fRun2PidMap.end())
461   {
462     Error("DoStop", "no selection");
463     return;
464   }
465
466   Int_t pid = i->second;
467   if (pid)
468   {
469     KillPid(pid);
470   }
471   else
472   {
473     Error("DoStop", "Process not running.");
474   }
475 }
476
477 void AliOnlineReco::DoExit()
478 {
479   // Slot called from Exit button or CloseWindow.
480   
481   // kill all started processes
482   Int_t pid;
483   
484   // disable all widgets & AutoRunTimer
485   // so that user does not initiate other GUI signals
486   if(!fDoExit){
487     fAutoRun->SetEnabled(kFALSE);
488     fStartButt->SetEnabled(kFALSE);
489     fStopButt->SetEnabled(kFALSE);
490     fExitButt->SetEnabled(kFALSE);
491       
492     StopAutoRunTimer();
493     fDoExit = kTRUE;
494     gROOT->SetInterrupt(kTRUE);
495   }
496   
497   gSystem->ProcessEvents();
498   
499   // clear runs std::map
500   for(mIntInt_i i = fRun2PidMap.begin(); i != fRun2PidMap.end(); i++)
501   {
502     pid = i->second;
503     
504     if(pid==0)
505     {
506       fRun2PidMap.erase(i); // if process is not started just remove it from map
507     }
508     else
509     {
510       // send kill signal to started process
511       KillPid(pid);
512       
513       // we need to exit loop to let ROOT process events list
514       // after kill signal above, process pid starts signal AliChildProcTerminator::ChildProcTerm(int, int)
515       // and arrives in AliOnlineReco::ChildProcTerm(int, int)
516       // after this we return in DoExit() to process next run
517       break;
518     }
519     
520   }
521   
522   // we can exit after we killed all processes
523   if(fRun2PidMap.empty() ) gSystem->ExitLoop();
524 }
525
526 void AliOnlineReco::CloseWindow()
527 {
528   // Virtual method called when window-manager close-window button is pressed.
529   
530   DoExit();
531   
532 }
533
534 Int_t AliOnlineReco::RetrieveGRP(UInt_t run, TString &gdc)
535 {
536   // Retrieve GRP entry for given run from aldaqdb.
537
538   TString dbHost = gSystem->Getenv("ONLINERECO_DB_HOST");
539   if (dbHost.IsNull())
540   {
541     dbHost = "aldaqdb";
542   }
543
544   TString dbPort = gSystem->Getenv("ONLINERECO_DB_PORT");
545   if (dbPort.IsNull())
546   {
547     dbPort = "0";
548   }
549
550   TString dbName = gSystem->Getenv("ONLINERECO_DB_NAME");
551   if (dbName.IsNull())
552   {
553     dbName = "LOGBOOK";
554   }
555
556   TString user = gSystem->Getenv("ONLINERECO_DB_USER");
557   if (user.IsNull())
558   {
559     user = "logbook";
560   }
561
562   TString password = gSystem->Getenv("ONLINERECO_DB_PASSWORD");
563   if (password.IsNull())
564   {
565     password = "alice";
566   }
567
568   Int_t ret=AliGRPPreprocessor::ReceivePromptRecoParameters(run, dbHost.Data(),
569             dbPort.Atoi(), dbName.Data(),
570             user.Data(), password.Data(),
571             Form("local://%s",gSystem->pwd()),
572             gdc);
573
574   if(ret>0) Info("RetrieveGRP","Last run of the same type is: %d",ret);
575   else if(ret==0) Warning("RetrieveGRP","No previous run of the same type found");
576   else if(ret<0) Error("Retrieve","Error code while retrieving GRP parameters returned: %d",ret);
577   return(ret);
578 }