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