bugfix: setting the monitoring event command in the EventDoneData only for the trigge...
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
1 // $Id$
2 /**************************************************************************
3  * This file is property of and copyright by the ALICE HLT Project        *
4  * ALICE Experiment at CERN, All rights reserved.                         *
5  *                                                                        *
6  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
7  *                  for The ALICE HLT Project.                            *
8  *                                                                        *
9  * Permission to use, copy, modify and distribute this software and its   *
10  * documentation strictly for non-commercial purposes is hereby granted   *
11  * without fee, provided that the above copyright notice appears in all   *
12  * copies and that both the copyright notice and this permission notice   *
13  * appear in the supporting documentation. The authors make no claims     *
14  * about the suitability of this software for any purpose. It is          *
15  * provided "as is" without express or implied warranty.                  *
16  **************************************************************************/
17
18 /// @file   AliHLTGlobalTriggerComponent.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
20 /// @date   26 Nov 2008
21 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
22 ///
23 /// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
24 /// trigger information produced by components deriving from AliHLTTrigger.
25
26 #include "AliHLTGlobalTriggerComponent.h"
27 #include "AliHLTGlobalTriggerDecision.h"
28 #include "AliHLTGlobalTrigger.h"
29 #include "AliHLTGlobalTriggerConfig.h"
30 #include "AliHLTTriggerMenu.h"
31 #include "AliHLTCTPData.h"
32 #include "AliCDBManager.h"
33 #include "AliCDBStorage.h"
34 #include "AliCDBEntry.h"
35 #include "TUUID.h"
36 #include "TROOT.h"
37 #include "TSystem.h"
38 #include "TRegexp.h"
39 #include "TClonesArray.h"
40 #include "TObjString.h"
41 #include "TString.h"
42 #include "TInterpreter.h"
43 #include "TDatime.h"
44 #include "TClass.h"
45 #include "TNamed.h"
46 #include <fstream>
47 #include <cerrno>
48 #include <cassert>
49 #include <vector>
50 #include <algorithm>
51
52 ClassImp(AliHLTGlobalTriggerComponent)
53
54 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
55
56
57 namespace
58 {
59   /**
60    * This method is used as a comparison functor with the STL sort routines.
61    */
62   bool AliHLTDescendingNumbers(UInt_t a, UInt_t b)
63   {
64     return a > b;
65   }
66 } // end of namespace
67
68
69 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
70         AliHLTTrigger(),
71         fTrigger(NULL),
72         fDebugMode(false),
73         fRuntimeCompile(true),
74         fDeleteCodeFile(false),
75         fCodeFileName(),
76         fClassName(),
77         fCTPDecisions(NULL),
78         fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
79         fBufferSizeMultiplier(1.),
80         fIncludePaths(TObjString::Class()),
81         fIncludeFiles(TObjString::Class()),
82         fLibStateAtLoad(),
83         fBits(0),
84         fDataEventsOnly(true)
85 {
86   // Default constructor.
87   
88   ClearInfoForNewEvent(false);
89 }
90
91
92 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
93 {
94   // Default destructor.
95   
96   if (fTrigger != NULL) delete fTrigger;
97
98   if (fCTPDecisions) {
99     fCTPDecisions->Delete();
100     delete fCTPDecisions;
101   }
102 }
103
104
105 void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
106 {
107   // Returns the kAliHLTDataTypeGlobalTrigger type as output.
108   list.push_back(kAliHLTDataTypeGlobalTrigger);
109 }
110
111
112 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
113 {
114   // Returns the output data size estimate.
115
116   constBase = fBufferSizeConst;
117   inputMultiplier = fBufferSizeMultiplier;
118 }
119
120
121 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
122 {
123   // Initialises the global trigger component.
124   
125   fDebugMode = false;
126   fClassName = "";
127   fCodeFileName = "";
128   fDeleteCodeFile = false;
129   const char* configFileName = NULL;
130   const char* codeFileName = NULL;
131   fIncludePaths.Clear();
132   fIncludeFiles.Clear();
133   SetBit(kIncludeInput);
134   fDataEventsOnly = true;
135   
136   for (int i = 0; i < argc; i++)
137   {
138     if (strcmp(argv[i], "-config") == 0)
139     {
140       if (configFileName != NULL)
141       {
142         HLTWarning("Trigger configuration macro was already specified."
143                    " Will replace previous value given by -config."
144         );
145       }
146       if (argc <= i+1)
147       {
148         HLTError("The trigger configuration macro filename was not specified." );
149         return -EINVAL;
150       }
151       configFileName = argv[i+1];
152       i++;
153       continue;
154     }
155     
156     if (strcmp(argv[i], "-includepath") == 0)
157     {
158       if (argc <= i+1)
159       {
160         HLTError("The include path was not specified." );
161         return -EINVAL;
162       }
163       new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
164       i++;
165       continue;
166     }
167     
168     if (strcmp(argv[i], "-include") == 0)
169     {
170       if (argc <= i+1)
171       {
172         HLTError("The include file name was not specified." );
173         return -EINVAL;
174       }
175       new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
176       i++;
177       continue;
178     }
179     
180     if (strcmp(argv[i], "-debug") == 0)
181     {
182       if (fDebugMode == true)
183       {
184         HLTWarning("The debug flag was already specified. Ignoring this instance.");
185       }
186       fDebugMode = true;
187       continue;
188     }
189     
190     if (strcmp(argv[i], "-cint") == 0)
191     {
192       fRuntimeCompile = false;
193       continue;
194     }
195     
196     if (strcmp(argv[i], "-usecode") == 0)
197     {
198       if (codeFileName != NULL)
199       {
200         HLTWarning("Custom trigger code file was already specified."
201                    " Will replace previous value given by -usecode."
202         );
203       }
204       if (argc <= i+1)
205       {
206         HLTError("The custom trigger code filename was not specified." );
207         return -EINVAL;
208       }
209       codeFileName = argv[i+1];
210       if (argc <= i+2)
211       {
212         HLTError("The custom trigger class name was not specified." );
213         return -EINVAL;
214       }
215       fClassName = argv[i+2];
216       i += 2;
217       continue;
218     }
219
220     if (strcmp(argv[i], "-skipctp") == 0)
221     {
222       HLTInfo("Skipping CTP counters in trigger decision");
223       SetBit(kSkipCTP);
224       continue;
225     }
226
227     if (strcmp(argv[i], "-forward-input") == 0)
228     {
229       HLTInfo("Forwarding input objects and trigger decisions");
230       SetBit(kForwardInput);
231       SetBit(kIncludeShort);
232       SetBit(kIncludeInput, false);
233       continue;
234     }
235
236     if (strstr(argv[i], "-include-input") == argv[i])
237     {
238       SetBit(kForwardInput,false);
239       TString param=argv[i];
240       param.ReplaceAll("-include-input", "");
241       if (param.CompareTo("=none")==0) 
242       {
243         HLTInfo("skipping objects and trigger decisions");
244         SetBit(kIncludeShort, false);
245         SetBit(kIncludeInput, false);
246       }
247       else if (param.CompareTo("=short")==0) 
248       {
249         HLTInfo("including short info on objects and trigger decisions");
250         SetBit(kIncludeShort);
251         SetBit(kIncludeInput, false);
252       }
253       else if (param.CompareTo("=both")==0) 
254       {
255         HLTInfo("including input objects, trigger decisions and short info");
256         SetBit(kIncludeShort);
257         SetBit(kIncludeInput);
258       }
259       else if (param.CompareTo("=objects")==0 || param.IsNull())
260       {
261         HLTInfo("including input objects and trigger decisions");
262         SetBit(kIncludeShort, false);
263         SetBit(kIncludeInput);
264       }
265       else
266       {
267         HLTError("unknown parameter '%s' for argument '-include-input'", param.Data());
268       }
269       continue;
270     }
271
272     if (strcmp(argv[i], "-process-all-events") == 0)
273     {
274       fDataEventsOnly = false;
275       continue;
276     }
277     
278     HLTError("Unknown option '%s'.", argv[i]);
279     return -EINVAL;
280   } // for loop
281   
282   const AliHLTTriggerMenu* menu = NULL;
283   if (configFileName != NULL)
284   {
285     TString cmd = ".x ";
286     cmd += configFileName;
287     gROOT->ProcessLine(cmd);
288     menu = AliHLTGlobalTriggerConfig::Menu();
289   }
290   
291   // Try load the trigger menu from the CDB if it is not loaded yet with the
292   // -config option
293   int result = -ENOENT;
294   if (menu == NULL)
295   {
296     result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu);
297   }
298   if (menu == NULL)
299   {
300     HLTError("No trigger menu configuration found or specified.");
301     return result;
302   }
303   
304   if (codeFileName == NULL)
305   {
306     result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles);
307     if (result == 0) fDeleteCodeFile = true;
308   }
309   else
310   {
311     result = LoadTriggerClass(codeFileName, fIncludePaths);
312     if (result == 0) fCodeFileName = codeFileName;
313   }
314   if (result != 0) return result;
315   
316   fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
317   if (fTrigger == NULL)
318   {
319     HLTError("Could not create a new instance of '%s'.", fClassName.Data());
320     return -EIO;
321   }
322   
323   fTrigger->FillFromMenu(*menu);
324   if (fTrigger->CallFailed()) return -EPROTO;
325
326   // setup the CTP accounting in AliHLTComponent
327   SetupCTPData();
328
329   // Set the default values from the trigger menu.
330   SetDescription(menu->DefaultDescription());
331   SetTriggerDomain(menu->DefaultTriggerDomain());
332   
333   return 0;
334 }
335
336
337 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
338 {
339   // Cleans up the global trigger component.
340   
341   if (fTrigger != NULL)
342   {
343     delete fTrigger;
344     fTrigger = NULL;
345   }
346   
347   if (fCTPDecisions) {
348     fCTPDecisions->Delete();
349     delete fCTPDecisions;
350   }
351   fCTPDecisions=NULL;
352   
353   Int_t result = UnloadTriggerClass(fCodeFileName);
354   if (result != 0) return result;
355   
356   if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
357     fCodeFileName.ReplaceAll(".cxx", "*");
358     TString command="rm "; command+=fCodeFileName;
359     gSystem->Exec(command);
360   }
361   fCodeFileName="";
362   fDeleteCodeFile=false;
363
364   return 0;
365 }
366
367
368 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
369 {
370   // Creates a new object instance.
371   
372   return new AliHLTGlobalTriggerComponent;
373 }
374
375
376 int AliHLTGlobalTriggerComponent::DoTrigger()
377 {
378   // This method will apply the global trigger decision.
379
380   if (fTrigger == NULL)
381   {
382     HLTFatal("Global trigger implementation object is NULL!");
383     return -EIO;
384   }
385
386   AliHLTUInt32_t eventType=0;
387   if (!IsDataEvent(&eventType)) {
388     if (eventType==gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant, 0);
389     if (fDataEventsOnly)
390     {
391       IgnoreEvent();
392       return 0;
393     }
394   }
395
396   // Copy the trigger counters in case we need to set them back to their original
397   // value because the PushBack method fails with ENOSPC.
398   TArrayL64 originalCounters = fTrigger->GetCounters();
399   if (fTrigger->CallFailed()) return -EPROTO;
400   
401   fTrigger->NewEvent();
402   if (fTrigger->CallFailed()) return -EPROTO;
403   
404   // Fill in the input data.
405   const TObject* obj = GetFirstInputObject();
406   while (obj != NULL)
407   {
408     fTrigger->Add(obj, GetDataType(), GetSpecification());
409     if (fTrigger->CallFailed()) return -EPROTO;
410     obj = GetNextInputObject();
411   }
412
413   // add trigger decisions for every CTP class
414   const AliHLTCTPData* pCTPData=CTPData();
415   if (pCTPData) {
416     AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
417   }
418
419   // Calculate the global trigger result and trigger domain, then create and push
420   // back the new global trigger decision object.
421   TString description;
422   AliHLTTriggerDomain triggerDomain;
423   bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
424   if (fTrigger->CallFailed()) return -EPROTO;
425   AliHLTGlobalTriggerDecision decision(
426       triggerResult,
427       // The following will cause the decision to be generated with default values
428       // (set in fTriggerDomain and fDescription) if the trigger result is false.
429       (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
430       (triggerResult == true) ? description.Data() : GetDescription()
431     );
432
433   // mask the readout list according to the CTP trigger
434   // if the classes have been initialized (mask non-zero)
435   if (pCTPData && pCTPData->Mask()) {
436     AliHLTEventDDL eventDDL=pCTPData->ReadoutList(*GetTriggerData());
437     AliHLTReadoutList ctpreadout(eventDDL);
438     ctpreadout.Enable(AliHLTReadoutList::kHLT);
439     AliHLTReadoutList maskedList=decision.ReadoutList();
440     maskedList.AndEq(ctpreadout);
441     decision.ReadoutList(maskedList);
442   }
443
444   decision.SetCounters(fTrigger->GetCounters(), GetEventCount()+1);
445   if (fTrigger->CallFailed()) return -EPROTO;
446   
447   static UInt_t lastTime=0;
448   TDatime time;
449   if (time.Get()-lastTime>60) {
450     lastTime=time.Get();
451     PrintStatistics(fTrigger, kHLTLogImportant);
452   }
453   
454   // Add the input objects used to the global decision.
455   TClonesArray* pShortInfo=NULL;
456   if (TestBit(kIncludeShort)) {
457     pShortInfo=new TClonesArray(TNamed::Class(), GetNumberOfInputBlocks());
458   }
459   obj = GetFirstInputObject();
460   while (obj != NULL)
461   {
462     if (TestBit(kForwardInput)) {
463       Forward(obj);
464     }
465     if (TestBit(kIncludeInput)) {
466     if (obj->IsA() == AliHLTTriggerDecision::Class())
467     {
468       decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
469     }
470     else
471     {
472       decision.AddInputObject(obj);
473     }
474     }
475
476     if (TestBit(kIncludeShort)) {
477       int entries=pShortInfo->GetEntriesFast();
478       new ((*pShortInfo)[entries]) TNamed(obj->GetName(), obj->GetTitle());
479       if (obj->IsA() == AliHLTTriggerDecision::Class()) {
480         (*pShortInfo)[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
481         (*pShortInfo)[entries]->SetBit(BIT(15), ((AliHLTTriggerDecision*)obj)->Result());
482       }
483     }
484
485     obj = GetNextInputObject();
486   }
487   if (pShortInfo) {
488     decision.AddInputObject(pShortInfo);
489     pShortInfo->Delete();
490     delete pShortInfo;
491     pShortInfo=NULL;
492   }
493
494   if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObject(CTPData());
495
496   // add readout filter to event done data
497   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
498   // add monitoring filter to event done data
499   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
500   if (decision.Result()) {
501     // add monitoring event command for triggered events
502     CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
503   }
504   if (TriggerEvent(&decision) == -ENOSPC)
505   {
506     // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
507     // returned the "no buffer space" error code. Also remember to set the trigger counters
508     // back to what they were, otherwise triggers will be double counted when we try to reprocess
509     // this event with larger buffers.
510     fBufferSizeConst += 1024*1024;
511     fBufferSizeMultiplier *= 2.;
512     fTrigger->SetCounters(originalCounters);
513     if (fTrigger->CallFailed()) return -EPROTO;
514     return -ENOSPC;
515   }
516   return 0;
517 }
518
519
520 int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId)
521 {
522   // Reconfigure the component by loading the trigger menu and recreating the
523   // trigger logic class.
524   
525   const char* path = fgkTriggerMenuCDBPath;
526   const char* id = "(unknown)";
527   if (cdbEntry != NULL) path = cdbEntry;
528   if (chainId != NULL and chainId[0] != '\0') id = chainId;
529   HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id);
530   
531   const AliHLTTriggerMenu* menu = NULL;
532   int result = LoadTriggerMenu(path, menu);
533   if (result != 0) return result;
534   
535   TString className;
536   TString codeFileName;
537   result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
538   if (result != 0) return result;
539   
540   AliHLTGlobalTrigger* trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
541   if (trigger == NULL)
542   {
543     HLTError("Could not create a new instance of '%s'.", className.Data());
544     // Make sure to cleanup after the new code file.
545     UnloadTriggerClass(codeFileName);
546     if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
547     {
548       codeFileName.ReplaceAll(".cxx", "*");
549       TString command="rm "; command+=codeFileName;
550       gSystem->Exec(command);
551     }
552     return -EIO;
553   }
554   
555   if (fTrigger != NULL)
556   {
557     delete fTrigger;
558     fTrigger = NULL;
559   }
560   
561   fTrigger = trigger;
562   fTrigger->FillFromMenu(*menu);
563   if (fTrigger->CallFailed()) return -EPROTO;
564
565   // Set the default values from the trigger menu.
566   SetDescription(menu->DefaultDescription());
567   SetTriggerDomain(menu->DefaultTriggerDomain());
568   
569   // Cleanup the old class code.
570   UnloadTriggerClass(fCodeFileName);
571   if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
572   {
573     fCodeFileName.ReplaceAll(".cxx", "*");
574     TString command="rm "; command+=fCodeFileName;
575     gSystem->Exec(command);
576   }
577   fCodeFileName = codeFileName;
578   fDeleteCodeFile = true;  // Since we generated a new class.
579   
580   return 0;
581 }
582
583
584 int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu)
585 {
586   // Loads the trigger menu object from the CDB path.
587   
588   HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
589   if (AliCDBManager::Instance() == NULL)
590   {
591     HLTError("CDB manager object not found.");
592     return -EIO;
593   }
594   AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
595   if (store == NULL)
596   {
597     HLTError("Could not get the the default storage for the CDB.");
598     return -EIO;
599   }
600   Int_t version = store->GetLatestVersion(cdbPath, GetRunNo());
601   Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version);
602   AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion);
603   if (entry == NULL)
604   {
605     HLTError("Could not get the CDB entry for \"%s\".", cdbPath);
606     return -EIO;
607   }
608   TObject* obj = entry->GetObject();
609   if (obj == NULL)
610   {
611     HLTError("Configuration object for \"%s\" is missing.", cdbPath);
612     return -ENOENT;
613   }
614   if (obj->IsA() != AliHLTTriggerMenu::Class())
615   {
616     HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
617              cdbPath, obj->ClassName()
618     );
619     return -EPROTO;
620   }
621   menu = static_cast<AliHLTTriggerMenu*>(obj);
622   return 0;
623 }
624
625
626 int AliHLTGlobalTriggerComponent::GenerateTrigger(
627     const AliHLTTriggerMenu* menu, TString& name, TString& filename,
628     const TClonesArray& includePaths, const TClonesArray& includeFiles
629   )
630 {
631   // Generates the global trigger class that will implement the specified trigger menu.
632   // See header for more details.
633   
634   HLTDebug("Generating custom HLT trigger class named %s using trigger menu %p.", ((void*)menu), name.Data());
635   
636   // Create a new UUID and replace the '-' characters with '_' to make it a valid
637   // C++ symbol name.
638   TUUID uuid;
639   TString uuidstr = uuid.AsString();
640   for (Int_t i = 0; i < uuidstr.Length(); i++)
641   {
642     if (uuidstr[i] == '-') uuidstr[i] = '_';
643   }
644   
645   // Create the name of the new class.
646   name = "AliHLTGlobalTriggerImpl_";
647   name += uuidstr;
648   filename = name + ".cxx";
649   
650   // Open a text file to write the code and generate the new class.
651   fstream code(filename.Data(), ios_base::out | ios_base::trunc);
652   if (not code.good())
653   {
654     HLTError("Could not open file '%s' for writing.", filename.Data());
655     return -EIO;
656   }
657   
658   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
659   int result = BuildSymbolList(menu, symbols);
660   if (result != 0) return result;
661   
662   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
663   code << "#include <cstring>" << endl;
664   code << "#include \"TString.h\"" << endl;
665   code << "#include \"TClonesArray.h\"" << endl;
666   code << "#include \"AliHLTLogging.h\"" << endl;
667   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
668   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
669   code << "#include \"AliHLTDomainEntry.h\"" << endl;
670   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
671   code << "#include \"AliHLTReadoutList.h\"" << endl;
672   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
673   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
674   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
675   
676   // Add any include files that were specified on the command line.
677   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
678   {
679     TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
680     code << "#include \"" << file.Data() << "\"" << endl;
681   }
682   
683   if (fDebugMode)
684   {
685     code << "#else" << endl;
686     code << "const char* gFunctionName = \"???\";" << endl;
687     code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl;
688   }
689   code << "#endif" << endl;
690   
691   code << "class " << name << " :" << endl;
692   // Add appropriate #ifdef sections since we need to prevent inheritance from
693   // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor
694   // multiple levels of inheritance. Neither of the following schemes worked:
695   //
696   // 1)  class AliHLTGlobalTrigger : public AliHLTLogging {};
697   //     class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {};
698   //
699   // 2)  class AliHLTGlobalTrigger {};
700   //     class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {};
701   //
702   // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT
703   // interpreter. But we anyway have to call the global trigger implementation class
704   // through the AliHLTGlobalTriggerWrapper so this is not such a problem.
705   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
706   code << "  public AliHLTGlobalTrigger," << endl;
707   code << "#endif" << endl;
708   code << "  public AliHLTLogging" << endl;
709   code << "{" << endl;
710   code << "public:" << endl;
711   
712   // Generate constructor method.
713   code << "  " << name << "() :" << endl;
714   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
715   code << "    AliHLTGlobalTrigger()," << endl;
716   code << "#endif" << endl;
717   code << "    AliHLTLogging()";
718   // Write the symbols in the trigger menu in the initialisation list.
719   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
720   {
721     code << "," << endl;
722     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
723     code << "    " << symbol->Name() << "()," << endl;
724     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
725     {
726       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
727     }
728     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
729   }
730   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
731   {
732     code << "," << endl << "    fMenuItemDescription" << i << "()";
733   }
734   code << endl << "  {" << endl;
735   if (fDebugMode)
736   {
737     code << "#ifdef __CINT__" << endl;
738     code << "    gFunctionName = \"" << name.Data() <<"\";" << endl;
739     code << "#endif" << endl;
740     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
741     code << "    HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl;
742   }
743   code << "  }" << endl;
744   
745   code << "  virtual ~" << name << "() {" << endl;
746   if (fDebugMode)
747   {
748     code << "#ifdef __CINT__" << endl;
749     code << "    gFunctionName = \"~" << name.Data() << "\";" << endl;
750     code << "#endif" << endl;
751     code << "    HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl;
752   }
753   code << "  }" << endl;
754   
755   // Generate the FillFromMenu method.
756   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
757   if (fDebugMode)
758   {
759     code << "#ifdef __CINT__" << endl;
760     code << "    gFunctionName = \"FillFromMenu\";" << endl;
761     code << "#endif" << endl;
762     code << "    HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl;
763   }
764   code << "    fCounter.Set(menu.NumberOfItems());" << endl;
765   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
766   {
767     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
768          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
769   }
770   if (fDebugMode)
771   {
772     code << "    HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl;
773     code << "    HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
774   }
775   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
776   // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
777   // Have to use the TClass system for extra protection.
778   code << "      if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
779   code << "      if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
780   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
781            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
782   code << "      if (symbol == NULL) continue;" << endl;
783   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
784   {
785     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
786     code << "      if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
787     if (fDebugMode)
788     {
789       code << "        HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
790               " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
791     }
792     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
793     code << "        continue;" << endl;
794     code << "      }" << endl;
795   }
796   code << "    }" << endl;
797   if (fDebugMode)
798   {
799     code << "    HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
800   }
801   code << "  }" << endl;
802   
803   // Generate the NewEvent method.
804   code << "  virtual void NewEvent() {" << endl;
805   if (fDebugMode)
806   {
807     code << "#ifdef __CINT__" << endl;
808     code << "    gFunctionName = \"NewEvent\";" << endl;
809     code << "#endif" << endl;
810     code << "    HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl;
811   }
812   // Write code to initialise the symbols in the trigger menu to their default values.
813   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
814   {
815     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
816     // CINT has problems with the implicit equals operator for complex types, so if
817     // the type has a equals operater we need to write the operator call explicitly.
818     TClass* clas = TClass::GetClass(symbol->Type());
819     if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
820     {
821       code << "    " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
822     }
823     else
824     {
825       code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
826     }
827     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
828     {
829       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
830     }
831   }
832   if (fDebugMode)
833   {
834     code << "    HLTDebug(Form(\"Finished initialising variables.\"));" << endl;
835   }
836   code << "  }" << endl;
837   
838   // Generate the Add method.
839   code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
840   if (fDebugMode)
841   {
842     code << "#ifdef __CINT__" << endl;
843     code << "    gFunctionName = \"Add\";" << endl;
844     code << "#endif" << endl;
845   }
846   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
847   if (fDebugMode)
848   {
849     code << "    HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block"
850             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
851             " _type_spec_.AsString().Data(), this));" << endl;
852     code << "    _object_->Print();" << endl;
853     code << "    bool _object_assigned_ = false;" << endl;
854   }
855   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
856   {
857     // Write code to check if the block type, specification and class name is correct.
858     // Then write code to assign the variable from the input object.
859     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
860     TString expr = symbol->AssignExpression();
861     if (expr == "") continue; // Skip entries that have no assignment expression.
862     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
863     if (fDebugMode)
864     {
865       if (isTrigDecision)
866       {
867         code << "    HLTDebug(Form(\"Trying to match input object to class '"
868              << symbol->ObjectClass() << "', trigger name '" << symbol->RealName()
869              << "' and block type '%s'\", " << symbol->Name()
870              << "DomainEntry.AsString().Data()));" << endl;
871       }
872       else
873       {
874         code << "    HLTDebug(Form(\"Trying to match input object to class '"
875              << symbol->ObjectClass() << "' and block type '%s'\", "
876              << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
877       }
878     }
879     // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
880     // Have to use the TClass system for extra protection.
881     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
882     code << "    if (_object_->IsA() == " << symbol->ObjectClass() << "::Class()) " << symbol->Name()
883          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
884          << "*>(_object_);" << endl;
885     code << "    if (" << symbol->Name() << "_object_ != NULL && ";
886     if (isTrigDecision)
887     {
888       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
889            << symbol->RealName() << "\") == 0 && ";
890     }
891     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
892     TString fullname = symbol->Name();
893     fullname += "_object_";
894     expr.ReplaceAll("this", fullname);
895     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
896     if (isTrigDecision)
897     {
898       code << "      this->" << symbol->Name() << "TriggerDomain = "
899            << fullname.Data() << "->TriggerDomain();" << endl;
900     }
901     if (fDebugMode)
902     {
903       code << "      HLTDebug(Form(\"Added TObject %p with class name '%s' to variable "
904            << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl;
905       code << "      _object_assigned_ = true;" << endl;
906     }
907     code << "    }" << endl;
908   }
909   if (fDebugMode)
910   {
911     code << "    if (! _object_assigned_) {" << endl;
912     code << "      HLTDebug(Form(\"Did not assign TObject %p"
913             " with class name '%s' to any variable.\", _object_, _object_->ClassName()));"
914          << endl;
915     code << "    }" << endl;
916   }
917   code << "  }" << endl;
918   
919   // Generate the CalculateTriggerDecision method.
920   // This requires code to be generated that checks which items in the trigger menu
921   // have their conditions asserted and then the trigger domain is generated from
922   // those fired items.
923   // The processing will start from the highest priority trigger group and stop
924   // after at least one trigger from the current priority group being processed
925   // is positive. For each priority group all the trigger menu items are checked.
926   // Their combined trigger condition expression must be true for the trigger priority
927   // group to be triggered positive. The full condition expression is formed by
928   // concatenating the individual condition expressions. If no trailing operators are
929   // used in the individual expressions then the default condition operator is placed
930   // between two concatenated condition expressions.
931   // If a trigger priority group has at least one trigger fired then the trigger domain
932   // is calculated such that it will give the same result as the concatenated trigger
933   // domain merging expressions for all the individual trigger menu items with
934   // positive results. Again, if no trailing operators are used in the individual
935   // merging expressions then the default domain operator is placed between two
936   // expression fragments.
937   code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
938   if (fDebugMode)
939   {
940     code << "#ifdef __CINT__" << endl;
941     code << "    gFunctionName = \"CalculateTriggerDecision\";" << endl;
942     code << "#endif" << endl;
943     code << "    HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl;
944   }
945   
946   // Build a list of priorities used in the trigger menu.
947   std::vector<UInt_t> priorities;
948   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
949   {
950     const AliHLTTriggerMenuItem* item = menu->Item(i);
951     bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end();
952     if (priorityNotInList) priorities.push_back(item->Priority());
953   }
954   std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers);
955   // From the priority list, build the priority groups in the correct order,
956   // i.e. highest priority first.
957   // The priority group is a list of vectors of integers. The integers are the
958   // index numbers into the trigger menu item list for the items which form part
959   // of the priority group.
960   std::vector<std::vector<Int_t> > priorityGroup;
961   priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector<Int_t>());
962   for (size_t n = 0; n < priorities.size(); n++)
963   {
964     UInt_t priority = priorities[n];
965     for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
966     {
967       const AliHLTTriggerMenuItem* item = menu->Item(i);
968       if (item->Priority() == priority) priorityGroup[n].push_back(i);
969     }
970   }
971   
972   for (size_t n = 0; n < priorityGroup.size(); n++)
973   {
974     if (fDebugMode)
975     {
976       code << "    HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl;
977     }
978     code << "    ";
979     if (n == 0) code << "UInt_t ";
980     code << "_previous_match_ = 0xFFFFFFFF;" << endl;
981     code << "    ";
982     if (n == 0) code << "bool ";
983     code << "_trigger_matched_ = false;" << endl;
984     code << "    ";
985     if (n == 0) code << "bool ";
986     code << "_group_result_ = false;" << endl;
987     std::vector<TString> conditionOperator;
988     conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString(""));
989     std::vector<TString> domainOperator;
990     domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString(""));
991     for (size_t m = 0; m < priorityGroup[n].size(); m++)
992     {
993       UInt_t i = priorityGroup[n][m];
994       const AliHLTTriggerMenuItem* item = menu->Item(i);
995       TString triggerCondition = item->TriggerCondition();
996       TString mergeExpr = item->MergeExpression();
997       // Replace the symbols found in the trigger condition and merging expressions
998       // with appropriate compilable versions.
999       for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
1000       {
1001         AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
1002         bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0;
1003         if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1004         {
1005           TString newname = symbol->Name();
1006           newname += "TriggerDomain";
1007           mergeExpr.ReplaceAll(symbol->RealName(), newname);
1008         }
1009         else
1010         {
1011           if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name());
1012         }
1013         if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name());
1014       }
1015       // We allow the trigger conditions and merging expressions to have trailing operators.
1016       // Thus, we need to extract the operators and cleanup the expressions so that they will
1017       // compile. This means that we silently ignore the trailing operator if not needed.
1018       if (ExtractedOperator(triggerCondition, conditionOperator[m]))
1019       {
1020         // If the trailing operator is the same as the default operator then reset
1021         // the value in the operator list so that the default is used in the generated
1022         // code. This creates more compact code.
1023         if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = "";
1024       }
1025       if (ExtractedOperator(mergeExpr, domainOperator[m]))
1026       {
1027         if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = "";
1028       }
1029       if (fDebugMode)
1030       {
1031         code << "    HLTDebug(Form(\"Trying trigger condition " << i
1032              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));"
1033              << endl;
1034       }
1035       code << "    ";
1036       if (n == 0 and m == 0) code << "bool ";
1037       code << "_item_result_ = false;" << endl;
1038       code << "    if (" << triggerCondition << ") {" << endl;
1039       code << "      ++fCounter[" << i << "];" << endl;
1040       const char* indentation = "";
1041       if (item->PreScalar() != 0)
1042       {
1043         indentation = "  ";
1044         code << "      if ((fCounter[" << i << "] % " << item->PreScalar() << ") == 1) {" << endl;
1045       }
1046       code << indentation << "      _item_result_ = true;" << endl;
1047       if (fDebugMode)
1048       {
1049         code << indentation << "      HLTDebug(Form(\"Matched trigger condition " << i
1050              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
1051       }
1052       if (item->PreScalar() != 0)
1053       {
1054         code << "      }" << endl;
1055       }
1056       code << "    }" << endl;
1057       if (m == 0)
1058       {
1059         // Since this is the first item of the trigger group,
1060         // the generated trigger logic can be simplified a little.
1061         code << "    _group_result_ = _item_result_;" << endl;
1062         code << "    if (_item_result_) {" << endl;
1063         code << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
1064         code << "      _description_ = fMenuItemDescription" << i << ";" << endl;
1065         code << "      _previous_match_ = " << i << ";" << endl;
1066         code << "      _trigger_matched_ = true;" << endl;
1067         code << "    }" << endl;
1068       }
1069       else
1070       {
1071         if (conditionOperator[m-1] == "")
1072         {
1073           code << "    _group_result_ = _group_result_ "
1074                << menu->DefaultConditionOperator() << " _item_result_;" << endl;
1075         }
1076         else
1077         {
1078           code << "    _group_result_ = _group_result_ "
1079                << conditionOperator[m-1] << " _item_result_;" << endl;
1080         }
1081         code << "    if (_item_result_) {" << endl;
1082         code << "      if (_trigger_matched_) {" << endl;
1083         bool switchWillBeEmpty = true;
1084         for (size_t k = 0; k < m; k++)
1085         {
1086           if (domainOperator[k] == "") continue;
1087           switchWillBeEmpty = false;
1088         }
1089         if (switchWillBeEmpty)
1090         {
1091           code << "        _domain_ = _domain_ " << menu->DefaultDomainOperator() << " "
1092                << mergeExpr.Data() << ";" << endl;
1093         }
1094         else
1095         {
1096           code << "        switch(_previous_match_) {" << endl;
1097           for (size_t k = 0; k < m; k++)
1098           {
1099             if (domainOperator[k] == "") continue;
1100             code << "        case " << k << ": _domain_ = _domain_ "
1101                  << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl;
1102           }
1103           code << "        default: _domain_ = _domain_ "
1104                << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl;
1105           code << "        }" << endl;
1106         }
1107         code << "        _description_ += \",\";" << endl;
1108         code << "        _description_ += fMenuItemDescription" << i << ";" << endl;
1109         code << "      } else {" << endl;
1110         code << "        _domain_ = " << mergeExpr.Data() << ";" << endl;
1111         code << "        _description_ = fMenuItemDescription" << i << ";" << endl;
1112         code << "      }" << endl;
1113         code << "      _previous_match_ = " << i << ";" << endl;
1114         code << "      _trigger_matched_ = true;" << endl;
1115         code << "    }" << endl;
1116       }
1117     }
1118     code << "    if (_group_result_) {" << endl;
1119     if (fDebugMode)
1120     {
1121       if (n < priorities.size() - 1)
1122       {
1123         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n]
1124              << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl;
1125       }
1126       else
1127       {
1128         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
1129       }
1130     }
1131     code << "      return true;" << endl;
1132     code << "    }" << endl;
1133   }
1134   code << "    _domain_.Clear();" << endl;
1135   code << "    _description_ = \"\";" << endl;
1136   code << "    return false;" << endl;
1137   code << "  }" << endl;
1138   
1139   // Generate getter and setter methods for the counters.
1140   code << "  const TArrayL64& GetCounters() const { return fCounter; }" << endl;
1141   code << "  void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl;
1142   
1143   code << "private:" << endl;
1144   // Add the symbols in the trigger menu to the list of private variables.
1145   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1146   {
1147     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1148     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
1149     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1150     {
1151       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
1152     }
1153     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
1154   }
1155   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1156   {
1157     code << "  TString fMenuItemDescription" << i << ";" << endl;
1158   }
1159   code << "  TArrayL64 fCounter;" << endl;
1160   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1161   code << "  ClassDef(" << name.Data() << ", 0)" << endl;
1162   code << "#else" << endl;
1163   code << "  virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl;
1164   code << "#endif" << endl;
1165   code << "};" << endl;
1166   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1167   code << "ClassImp(" << name.Data() << ")" << endl;
1168   code << "#endif" << endl;
1169   
1170   code.close();
1171   
1172   // Now we need to compile and load the new class.
1173   result = LoadTriggerClass(filename, includePaths);
1174   return result;
1175 }
1176
1177
1178 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
1179     const char* filename, const TClonesArray& includePaths
1180   )
1181 {
1182   // Loads the code for a custom global trigger class implementation on the fly.
1183   
1184   HLTDebug("Loading HLT trigger class from file '%s'.", filename);
1185   
1186   TString compiler = gSystem->GetBuildCompilerVersion();
1187   if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1188   {
1189     TString includePath;
1190 #if defined(PKGINCLUDEDIR)
1191     // this is especially for the HLT build system where the package is installed
1192     // in a specific directory including proper treatment of include files
1193     includePath.Form("-I%s", PKGINCLUDEDIR);
1194 #else
1195     // the default AliRoot behavior, all include files can be found in the
1196     // $ALICE_ROOT subfolders
1197     includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
1198 #endif
1199     // Add any include paths that were specified on the command line.
1200     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
1201     {
1202       TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
1203       includePath += " -I";
1204       includePath += path;
1205     }
1206     HLTDebug("using include settings: %s", includePath.Data());
1207     gSystem->SetIncludePath(includePath);
1208     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
1209     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
1210     
1211     int result = kTRUE;
1212     if (fDebugMode)
1213     {
1214       result = gSystem->CompileMacro(filename, "g");
1215     }
1216     else
1217     {
1218       result = gSystem->CompileMacro(filename, "O");
1219     }
1220     if (result != kTRUE)
1221     {
1222       HLTFatal("Could not compile and load global trigger menu implementation.");
1223       return -ENOENT;
1224     }
1225   }
1226   else
1227   {
1228     // Store the library state to be checked later in UnloadTriggerClass.
1229     fLibStateAtLoad = gSystem->GetLibraries();
1230     
1231     // If we do not support the compiler then try interpret the class instead.
1232     TString cmd = ".L ";
1233     cmd += filename;
1234     Int_t errorcode = TInterpreter::kNoError;
1235     gROOT->ProcessLine(cmd, &errorcode);
1236     if (errorcode != TInterpreter::kNoError)
1237     {
1238       HLTFatal("Could not load interpreted global trigger menu implementation"
1239                " (Interpreter error code = %d).",
1240                errorcode
1241       );
1242       return -ENOENT;
1243     }
1244   }
1245   
1246   return 0;
1247 }
1248
1249
1250 int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
1251 {
1252   // Unloads the code previously loaded by LoadTriggerClass.
1253   
1254   HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
1255   
1256   TString compiler = gSystem->GetBuildCompilerVersion();
1257   if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1258   {
1259     // Generate the library name.
1260     TString libname = filename;
1261     Ssiz_t dotpos = libname.Last('.');
1262     if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
1263     libname += ".";
1264     libname += gSystem->GetSoExt();
1265     
1266     // This is a workaround for a problem with unloading shared libraries in ROOT.
1267     // If the trigger logic library is loaded before the libAliHLTHOMER.so library
1268     // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1269     // call all the subsequent libraries get unloded. This means that any objects created
1270     // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
1271     // since the executable code has been unloaded.
1272     // We need to check if there are any more libraries loaded after the class we
1273     // are unloading and in that case don't unload the class.
1274     TString libstring = gSystem->GetLibraries();
1275     TString token, lastlib;
1276     Ssiz_t from = 0;
1277     Int_t numOfLibs = 0, posOfLib = -1;
1278     while (libstring.Tokenize(token, from, " "))
1279     {
1280       ++numOfLibs;
1281       lastlib = token;
1282       if (token.Contains(libname)) posOfLib = numOfLibs;
1283     }
1284     if (numOfLibs != posOfLib)
1285     {
1286       HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
1287           " library '%s' since another library '%s' was loaded afterwards. Trying to"
1288           " unload this library will remove the others and lead to serious memory faults.",
1289           libname.Data(), lastlib.Data()
1290       ));
1291       return 0;
1292     }
1293     
1294     char* path = NULL;
1295     int result = 0;
1296     if ((path = gSystem->DynamicPathName(libname)) != NULL)
1297     {
1298       result = gInterpreter->UnloadFile(path);
1299       delete [] path;
1300     }
1301     if (result != TInterpreter::kNoError) return -ENOENT;
1302   }
1303   else
1304   {
1305     // This is again a workaround for the problem with unloading files in ROOT.
1306     // If the trigger logic class is loaded before the libAliHLTHOMER.so library
1307     // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1308     // call all the subsequent libraries get unloded.
1309     // We need to check if the list of loaded libraries has changed since the last
1310     // call to LoadTriggerClass. If it has then don't unload the class.
1311     if (fLibStateAtLoad != gSystem->GetLibraries())
1312     {
1313       TString libstring = gSystem->GetLibraries();
1314       TString token;
1315       Ssiz_t from = 0;
1316       while (libstring.Tokenize(token, from, " "))
1317       {
1318         if (not fLibStateAtLoad.Contains(token)) break;
1319       }
1320       HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
1321           " '%s' since another library '%s' was loaded afterwards. Trying to unload"
1322           " this file will remove the other library and lead to serious memory faults.",
1323           filename, token.Data()
1324       ));
1325       return 0;
1326     }
1327   
1328     // If we did not compile the trigger logic then remove the interpreted class.
1329     TString cmd = ".U ";
1330     cmd += filename;
1331     Int_t errorcode = TInterpreter::kNoError;
1332     gROOT->ProcessLine(cmd, &errorcode);
1333     if (errorcode != TInterpreter::kNoError)
1334     {
1335       HLTFatal("Could not unload interpreted global trigger menu implementation"
1336                " (Interpreter error code = %d).",
1337                errorcode
1338       );
1339       return -ENOENT;
1340     }
1341   }
1342   
1343   return 0;
1344 }
1345
1346
1347 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
1348 {
1349   // Searches for the named symbol in the given list.
1350   // See header for more details.
1351   
1352   for (int i = 0; i < list.GetEntriesFast(); i++)
1353   {
1354     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
1355     if (symbol == NULL) continue;
1356     if (strcmp(symbol->Name(), name) == 0) return i;
1357   }
1358   return -1;
1359 }
1360
1361
1362 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
1363 {
1364   // Builds the list of symbols to use in the custom global trigger menu
1365   // implementation class.
1366   // See header for more details.
1367   
1368   // Note: when we build the symbol list we must use the symbol name as returned
1369   // by the Name() method and not the RealName() method when using FindSymbol.
1370   // This is so that we avoid problems with the generated code not compiling
1371   // because names like "abc-xyz" and "abc_xyz" are synonymous.
1372   // Name() returns the converted C++ symbol name as used in the generated code.
1373   
1374   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
1375   {
1376     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
1377     if (FindSymbol(symbol->Name(), list) != -1)
1378     {
1379       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
1380       return -EIO;
1381     }
1382     new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
1383   }
1384   
1385   TRegexp exp("[_a-zA-Z][-_a-zA-Z0-9]*");
1386   TRegexp hexexp("x[a-fA-F0-9]+");
1387   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1388   {
1389     const AliHLTTriggerMenuItem* item = menu->Item(i);
1390     TString str = item->TriggerCondition();
1391     Ssiz_t start = 0;
1392     do
1393     {
1394       Ssiz_t length = 0;
1395       Ssiz_t pos = exp.Index(str, &length, start);
1396       if (pos == kNPOS) break;
1397       start = pos+length;
1398       
1399       // Check if there is a numerical character before the found
1400       // regular expression. If so, then the symbol is not a valid one
1401       // and should be skipped.
1402       if (pos > 0)
1403       {
1404         bool notValid = false;
1405         switch (str[pos-1])
1406         {
1407         case '0': case '1': case '2': case '3': case '4':
1408         case '5': case '6': case '7': case '8': case '9':
1409           notValid = true;
1410           break;
1411         default:
1412           notValid = false;
1413           break;
1414         }
1415         if (notValid) continue;
1416       }
1417       TString s = str(pos, length);
1418       
1419       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1420           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1421           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
1422           s == "false"
1423          )
1424       {
1425         // Ignore iso646.h and other keywords.
1426         continue;
1427       }
1428
1429       // Need to create the symbols first and check if its name is in the list
1430       // before actually adding it to the symbols list.
1431       AliHLTTriggerMenuSymbol newSymbol;
1432       newSymbol.Name(s.Data());
1433       newSymbol.Type("bool");
1434       newSymbol.ObjectClass("AliHLTTriggerDecision");
1435       newSymbol.AssignExpression("this->Result()");
1436       newSymbol.DefaultValue("false");
1437       if (FindSymbol(newSymbol.Name(), list) == -1)
1438       {
1439         new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
1440       }
1441     }
1442     while (start < str.Length());
1443   }
1444   
1445   return 0;
1446 }
1447
1448
1449 bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
1450 {
1451   // Extracts the trailing operator from the expression.
1452   
1453   Ssiz_t i = 0;
1454   // First skip the trailing whitespace.
1455   bool whitespace = true;
1456   for (i = expr.Length()-1; i >= 0 and whitespace; i--)
1457   {
1458     switch (expr[i])
1459     {
1460     case ' ': case '\t': case '\r': case '\n':
1461       whitespace = true;
1462       break;
1463     default:
1464       whitespace = false;
1465     }
1466   }
1467   if (i < 0 or whitespace) return false;
1468   
1469   // Now find the first whitespace character before the trailing symbol.
1470   bool nonwhitespace = true;
1471   for (; i >= 0 and nonwhitespace; i--)
1472   {
1473     switch (expr[i])
1474     {
1475     case ' ': case '\t': case '\r': case '\n':
1476       nonwhitespace = false;
1477       break;
1478     default:
1479       nonwhitespace = true;
1480     }
1481   }
1482   if (i < 0 or nonwhitespace) return false;
1483   
1484   // Extract the last symbols and check if it is a valid operator.
1485   TString s = expr;
1486   s.Remove(0, i+2);
1487   if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1488       s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1489       s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or
1490       s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or
1491       s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or
1492       s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or
1493       s == "%" or s == ">" or s == "<" or s == ">=" or s == "<="
1494      )
1495   {
1496     expr.Remove(i+1);
1497     op = s;
1498     return true;
1499   }
1500   
1501   return false;
1502 }
1503
1504
1505 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
1506 {
1507   // print some statistics
1508   int totalEvents=GetEventCount()+offset;
1509   const TArrayL64& counters = pTrigger->GetCounters();
1510   if (pTrigger->CallFailed()) return -EPROTO;
1511   for (int i = 0; i < counters.GetSize(); i++) {
1512     ULong64_t count = counters[i];
1513     float ratio=0;
1514     if (totalEvents>0) ratio=100*(float)count/totalEvents;
1515     HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
1516   }
1517   return 0;
1518 }
1519
1520 int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger, const AliHLTCTPData* pCTPData, const AliHLTComponentTriggerData* trigData)
1521 {
1522   // add trigger decisions for the valid CTP classes
1523   if (!pCTPData || !pTrigger) return 0;
1524
1525   AliHLTUInt64_t triggerMask=pCTPData->Mask();
1526   AliHLTUInt64_t bit0=0x1;
1527   if (!fCTPDecisions) {
1528     fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
1529     if (!fCTPDecisions) return -ENOMEM;
1530
1531     fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
1532     for (int i=0; i<gkNCTPTriggerClasses; i++) {
1533       const char* name=pCTPData->Name(i);
1534       if (triggerMask&(bit0<<i) && name) {
1535         AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1536         assert(pDecision);
1537         if (!pDecision) {
1538           delete fCTPDecisions;
1539           fCTPDecisions=NULL;
1540           return -ENOENT;
1541         }
1542         pDecision->Name(name);
1543       }
1544     }
1545   }
1546
1547   for (int i=0; i<gkNCTPTriggerClasses; i++) {
1548     const char* name=pCTPData->Name(i);
1549     if ((triggerMask&(bit0<<i))==0 || name==NULL) continue;
1550     AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1551     HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
1552     if (!pDecision) return -ENOENT;
1553
1554     bool result=false;
1555     if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
1556     else result=pCTPData->EvaluateCTPTriggerClass(name);
1557     pDecision->Result(result);
1558     pDecision->TriggerDomain().Clear();
1559     if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
1560     else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
1561
1562     pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
1563     if (pTrigger->CallFailed()) return -EPROTO;
1564   }
1565
1566   return 0;
1567 }