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