Added a feature test macro for sa_restorer field
[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       sigemptyset(&sac.sa_mask);
176       sac.sa_flags = 0;
177       
178       // The sa_restorer field is Not POSIX and obsolete.
179       // This is for compilation on other systems
180       #if defined(__linux) && \
181           (defined(__i386__) || defined(__x86_64__)) && \
182            defined(__GNUC__)
183       sac.sa_restorer= NULL;
184       #endif
185       sigaction(SIGCHLD, &sac, NULL);
186   
187       int s;
188       if (fTestMode)
189       {
190         s = execlp("alitestproc", "alitestproc", TString::Format("%d", run).Data(), (char*) 0);
191       }
192       else
193       {
194         Int_t procPID = gSystem->GetPid();
195         TString logFile = Form("%s/reco/log/run%d_%d.log",
196              gSystem->Getenv("ONLINERECO_BASE_DIR"),
197              run,
198             (Int_t)procPID);
199         Info("DoStart","Reconstruction log will be written to %s",logFile.Data());
200         gSystem->RedirectOutput(logFile.Data());
201
202         gSystem->cd(Form("%s/reco",gSystem->Getenv("ONLINERECO_BASE_DIR")));
203
204         TString gdcs;
205         if (RetrieveGRP(run,gdcs) <= 0 || gdcs.IsNull()) 
206           gSystem->Exit(1);
207
208         gSystem->Setenv("DATE_RUN_NUMBER", Form("%d", run));
209         // Setting CDB
210         //      AliCDBManager * man = AliCDBManager::Instance();
211         //      man->SetDefaultStorage("local:///local/cdb");
212         //      man->SetSpecificStorage("GRP/GRP/Data",
213         //                            Form("local://%s",gSystem->pwd()));
214         //      man->SetSpecificStorage("GRP/CTP/Config",
215         //                            Form("local://%s",gSystem->pwd()));
216         //      man->SetSpecificStorage("ACORDE/Align/Data",
217         //                              "local://$ALICE_ROOT/OCDB");
218
219         gSystem->mkdir(Form("run%d_%d", run, (Int_t)procPID));
220         gSystem->cd(Form("run%d_%d", run, (Int_t)procPID));
221
222         TString recMacroPath(gSystem->Getenv("ONLINERECO_MACRO"));
223         if (recMacroPath.IsNull()) {
224           recMacroPath = "$ALICE_ROOT/MONITOR/rec.C";
225         }
226
227         s = execlp("alieve",
228              "alieve",
229              "-q",
230              Form("%s(\"mem://@*:\")", gSystem->ExpandPathName(recMacroPath.Data())),
231              (char*) 0);
232
233         gSystem->Exec(Form("rm -rf %s/reco/run%d_%d",gSystem->Getenv("ONLINERECO_BASE_DIR"),run,(Int_t)procPID));
234       }
235
236       if (s == -1)
237       {
238         perror("execlp failed - this will not end well");
239         gSystem->Exit(1);
240       }
241     }
242   }
243   else
244   {
245     Error("DoStart", "Process already running.");
246   }
247 }
248
249 void AliOnlineReco::KillPid(Int_t pid)
250 {
251   // Terminate process given by pid.
252
253   // Send terminate signal to process ...
254
255   if (fTestMode)
256   {
257     kill(pid, SIGTERM);
258   }
259   else
260   {
261     // alieve will auto-destruct on SIGUSR1
262     kill(pid, SIGUSR1);
263   }
264 }
265
266 void AliOnlineReco::StartAutoRunTimer(Int_t run)
267 {
268   // Start timer for given run.
269   // If an auto-started run is already active, this call is ignored.
270   // If timer is already active, it is restarted.
271
272   if (fAutoRunRunning)
273     return;
274
275   fAutoRunTimer->Reset();
276   fAutoRunTimer->TurnOn();
277   fAutoRunScheduled = run;
278
279   Info("StartAutoRunTimer", "Scheduling run %d for auto-display.", run);
280 }
281
282 void AliOnlineReco::StopAutoRunTimer()
283 {
284   // Stop auto-run timer.
285
286   fAutoRunTimer->TurnOff();
287   fAutoRunScheduled = 0;
288 }
289
290 void AliOnlineReco::AutoRunTimerTimeout()
291 {
292   // Slot called on auto-timer timeout.
293
294   Int_t run = fAutoRunScheduled;
295
296   StopAutoRunTimer();
297
298   mIntInt_i i = fRun2PidMap.find(run);
299
300   if (i == fRun2PidMap.end())
301   {
302     Warning("AutoRunTimerTimeout", "run no longer active.");
303     return;
304   }
305
306   Info("AutoRunTimerTimeout", "Starting display for run %d.", run);
307
308   StartAliEve(i);
309   fAutoRunRunning = run;
310 }
311
312 //------------------------------------------------------------------------------
313 // Handlers of DIM signals.
314 //------------------------------------------------------------------------------
315
316 void AliOnlineReco::StartOfRun(Int_t run)
317 {
318   // Slot called from DIM handler on start of run.
319
320   mIntInt_i i = fRun2PidMap.find(run);
321   if (i == fRun2PidMap.end())
322   {
323     fRun2PidMap[run] = 0;
324     fRunList->AddEntrySort(TString::Format("%d", run), run);
325     fRunList->Layout();
326
327     if (fAutoRun->IsOn())
328     {
329       StartAutoRunTimer(run);
330     }
331   }
332   else
333   {
334     Error("StartOfRun", "Run %d already registered.", run);
335   }
336 }
337
338 void AliOnlineReco::EndOfRun(Int_t run)
339 {
340   // Slot called from DIM handler on stop of run.
341
342   mIntInt_i i = fRun2PidMap.find(run);
343   if (i != fRun2PidMap.end())
344   {
345     Int_t pid = i->second;
346     fRunList->RemoveEntry(run);
347     fRunList->Layout();
348     fRun2PidMap.erase(i);
349     if (pid)
350     {
351       KillPid(pid);
352     }
353     gClient->NeedRedraw(fRunList);
354
355     if (fAutoRunRunning == run)
356     {
357       fAutoRunRunning = 0;
358     }
359   }
360   else
361   {
362     Error("EndOfRun", "Run %d not registered.", run);
363   }
364 }
365
366 //------------------------------------------------------------------------------
367 // Handlers of OS signals.
368 //------------------------------------------------------------------------------
369
370 void AliOnlineReco::ChildProcTerm(Int_t pid, Int_t status)
371 {
372   // Slot called on termination of child process.
373  
374   printf("child process termination pid=%d, status=%d...\n", pid, status);
375
376   mIntInt_i i = FindMapEntryByPid(pid);
377   if (i != fRun2PidMap.end())
378   {
379     Int_t run = i->first;
380     fRunList->RemoveEntry(run);
381     if (status == 0)
382     {
383       fRunList->AddEntrySort(TString::Format("%-20d -- PROCESSED", run), run);
384     }
385     else
386     {
387       fRunList->AddEntrySort(TString::Format("%-20d -- PROCESSED [%d]", run, status), run);
388     }
389     fRunList->Layout();
390     i->second = 0;
391
392     if (fAutoRunRunning == run && fAutoRun->IsOn())
393     {
394       fAutoRunRunning = 0;
395       StartAutoRunTimer(run);
396     }
397     else
398     {
399       fAutoRunRunning = 0;
400     }
401   }
402   else
403   {
404     Warning("ChildProcTerm", "Process with pid=%d not registered.", pid);
405   }
406 }
407
408 //------------------------------------------------------------------------------
409 // Handlers of button signals.
410 //------------------------------------------------------------------------------
411
412 void AliOnlineReco::DoAutoRun()
413 {
414   // Slot called from auto-run check-box.
415
416   Bool_t autoRun = fAutoRun->IsOn();
417
418   if (autoRun)
419     fStartButt->SetEnabled(kFALSE);
420   else
421     fStartButt->SetEnabled(kTRUE);    
422 }
423
424 void AliOnlineReco::DoStart()
425 {
426   // Slot called from Start button.
427
428   Int_t run = fRunList->GetSelected();
429   mIntInt_i i = fRun2PidMap.find(run);
430
431   if (i == fRun2PidMap.end())
432   {
433     Error("DoStart", "no selection");
434     return;
435   }
436
437   StartAliEve(i);
438 }
439
440 void AliOnlineReco::DoStop()
441 {
442   // Slot called from Stop button.
443
444   Int_t run = fRunList->GetSelected();
445   mIntInt_i i = fRun2PidMap.find(run);
446
447   if (i == fRun2PidMap.end())
448   {
449     Error("DoStop", "no selection");
450     return;
451   }
452
453   Int_t pid = i->second;
454   if (pid)
455   {
456     KillPid(pid);
457   }
458   else
459   {
460     Error("DoStop", "Process not running.");
461   }
462 }
463
464 void AliOnlineReco::DoExit()
465 {
466   // Slot called from Exit button.
467
468   gSystem->ExitLoop();
469 }
470
471 void AliOnlineReco::CloseWindow()
472 {
473   // Virtual method called when window-manager close-window button is pressed.
474
475   gSystem->ExitLoop();
476 }
477
478 Int_t AliOnlineReco::RetrieveGRP(UInt_t run, TString &gdc)
479 {
480   // Retrieve GRP entry for given run from aldaqdb.
481
482   TString dbHost = gSystem->Getenv("ONLINERECO_DB_HOST");
483   if (dbHost.IsNull())
484   {
485     dbHost = "aldaqdb";
486   }
487
488   TString dbPort = gSystem->Getenv("ONLINERECO_DB_PORT");
489   if (dbPort.IsNull())
490   {
491     dbPort = "0";
492   }
493
494   TString dbName = gSystem->Getenv("ONLINERECO_DB_NAME");
495   if (dbName.IsNull())
496   {
497     dbName = "LOGBOOK";
498   }
499
500   TString user = gSystem->Getenv("ONLINERECO_DB_USER");
501   if (user.IsNull())
502   {
503     user = "logbook";
504   }
505
506   TString password = gSystem->Getenv("ONLINERECO_DB_PASSWORD");
507   if (password.IsNull())
508   {
509     password = "alice";
510   }
511
512   Int_t ret=AliGRPPreprocessor::ReceivePromptRecoParameters(run, dbHost.Data(),
513             dbPort.Atoi(), dbName.Data(),
514             user.Data(), password.Data(),
515             Form("local://%s",gSystem->pwd()),
516             gdc);
517
518   if(ret>0) Info("RetrieveGRP","Last run of the same type is: %d",ret);
519   else if(ret==0) Warning("RetrieveGRP","No previous run of the same type found");
520   else if(ret<0) Error("Retrieve","Error code while retrieving GRP parameters returned: %d",ret);
521   return(ret);
522 }