]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
Fixes for coverity
[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 AliHLTGlobalTriggerComponent 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 "AliRawDataHeader.h"
36 #include "TUUID.h"
37 #include "TROOT.h"
38 #include "TSystem.h"
39 #include "TRegexp.h"
40 #include "TClonesArray.h"
41 #include "TObjString.h"
42 #include "TString.h"
43 #include "TInterpreter.h"
44 #include "TDatime.h"
45 #include "TClass.h"
46 #include "TNamed.h"
47 #include "TRandom3.h"
48 #include <fstream>
49 #include <cerrno>
50 #include <cassert>
51 #include <vector>
52 #include <algorithm>
53
54 ClassImp(AliHLTGlobalTriggerComponent)
55
56 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
57
58
59 namespace
60 {
61   /**
62    * This method is used as a comparison functor with the STL sort routines.
63    */
64   bool AliHLTDescendingNumbers(UInt_t a, UInt_t b)
65   {
66     return a > b;
67   }
68 } // end of namespace
69
70
71 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
72         AliHLTTrigger(),
73         fTrigger(NULL),
74         fDebugMode(false),
75         fRuntimeCompile(true),
76         fDeleteCodeFile(false),
77         fMakeSoftwareTriggers(true),
78         fCodeFileName(),
79         fClassName(),
80         fCTPDecisions(NULL),
81         fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
82         fBufferSizeMultiplier(1.),
83         fIncludePaths(TObjString::Class()),
84         fIncludeFiles(TObjString::Class()),
85         fLibStateAtLoad(),
86         fBits(0),
87         fDataEventsOnly(true),
88         fMonitorPeriod(-1),
89         fUniqueID(0),
90         fSoftwareTrigger(true, "SOFTWARE"),
91         fTotalEventCounter(0),
92         fCDH(NULL)
93 {
94   // Default constructor.
95   
96   ClearInfoForNewEvent(false);
97 }
98
99
100 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
101 {
102   // Default destructor.
103   
104   if (fTrigger != NULL) delete fTrigger;
105
106   if (fCTPDecisions) {
107     fCTPDecisions->Delete();
108     delete fCTPDecisions;
109   }
110 }
111
112
113 void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
114 {
115   // Returns the kAliHLTDataTypeGlobalTrigger type as output.
116   list.push_back(kAliHLTDataTypeGlobalTrigger);
117 }
118
119
120 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
121 {
122   // Returns the output data size estimate.
123
124   constBase = fBufferSizeConst;
125   inputMultiplier = fBufferSizeMultiplier;
126 }
127
128
129 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
130 {
131   // Initialises the global trigger component.
132   
133   fDebugMode = false;
134   fClassName = "";
135   fCodeFileName = "";
136   fDeleteCodeFile = false;
137   fMakeSoftwareTriggers = true;
138   const char* configFileName = NULL;
139   const char* codeFileName = NULL;
140   fIncludePaths.Clear();
141   fIncludeFiles.Clear();
142   SetBit(kIncludeInput);
143   fDataEventsOnly = true;
144   UInt_t randomSeed = 0;
145   bool randomSeedSet = false;
146   fCDH = NULL;
147   
148   for (int i = 0; i < argc; i++)
149   {
150     if (strcmp(argv[i], "-config") == 0)
151     {
152       if (configFileName != NULL)
153       {
154         HLTWarning("Trigger configuration macro was already specified."
155                    " Will replace previous value given by -config."
156         );
157       }
158       if (argc <= i+1)
159       {
160         HLTError("The trigger configuration macro filename was not specified." );
161         return -EINVAL;
162       }
163       configFileName = argv[i+1];
164       i++;
165       continue;
166     }
167     
168     if (strcmp(argv[i], "-includepath") == 0)
169     {
170       if (argc <= i+1)
171       {
172         HLTError("The include path was not specified." );
173         return -EINVAL;
174       }
175       try
176       {
177         new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
178       }
179       catch (const std::bad_alloc&)
180       {
181         HLTError("Could not allocate more memory for the fIncludePaths array.");
182         return -ENOMEM;
183       }
184       i++;
185       continue;
186     }
187     
188     if (strcmp(argv[i], "-include") == 0)
189     {
190       if (argc <= i+1)
191       {
192         HLTError("The include file name was not specified." );
193         return -EINVAL;
194       }
195       try
196       {
197         new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
198       }
199       catch (const std::bad_alloc&)
200       {
201         HLTError("Could not allocate more memory for the fIncludeFiles array.");
202         return -ENOMEM;
203       }
204       i++;
205       continue;
206     }
207     
208     if (strcmp(argv[i], "-debug") == 0)
209     {
210       if (fDebugMode == true)
211       {
212         HLTWarning("The debug flag was already specified. Ignoring this instance.");
213       }
214       fDebugMode = true;
215       continue;
216     }
217     
218     if (strcmp(argv[i], "-cint") == 0)
219     {
220       fRuntimeCompile = false;
221       continue;
222     }
223     
224     if (strcmp(argv[i], "-usecode") == 0)
225     {
226       if (codeFileName != NULL)
227       {
228         HLTWarning("Custom trigger code file was already specified."
229                    " Will replace previous value given by -usecode."
230         );
231       }
232       if (argc <= i+1)
233       {
234         HLTError("The custom trigger code filename was not specified." );
235         return -EINVAL;
236       }
237       codeFileName = argv[i+1];
238       if (argc <= i+2)
239       {
240         HLTError("The custom trigger class name was not specified." );
241         return -EINVAL;
242       }
243       fClassName = argv[i+2];
244       i += 2;
245       continue;
246     }
247
248     if (strcmp(argv[i], "-skipctp") == 0)
249     {
250       HLTInfo("Skipping CTP counters in trigger decision");
251       SetBit(kSkipCTP);
252       continue;
253     }
254
255     if (strcmp(argv[i], "-forward-input") == 0)
256     {
257       HLTInfo("Forwarding input objects and trigger decisions");
258       SetBit(kForwardInput);
259       SetBit(kIncludeShort);
260       SetBit(kIncludeInput, false);
261       continue;
262     }
263
264     if (strstr(argv[i], "-include-input") == argv[i])
265     {
266       SetBit(kForwardInput,false);
267       TString param=argv[i];
268       param.ReplaceAll("-include-input", "");
269       if (param.CompareTo("=none")==0) 
270       {
271         HLTInfo("skipping objects and trigger decisions");
272         SetBit(kIncludeShort, false);
273         SetBit(kIncludeInput, false);
274       }
275       else if (param.CompareTo("=short")==0) 
276       {
277         HLTInfo("including short info on objects and trigger decisions");
278         SetBit(kIncludeShort);
279         SetBit(kIncludeInput, false);
280       }
281       else if (param.CompareTo("=both")==0) 
282       {
283         HLTInfo("including input objects, trigger decisions and short info");
284         SetBit(kIncludeShort);
285         SetBit(kIncludeInput);
286       }
287       else if (param.CompareTo("=objects")==0 || param.IsNull())
288       {
289         HLTInfo("including input objects and trigger decisions");
290         SetBit(kIncludeShort, false);
291         SetBit(kIncludeInput);
292       }
293       else
294       {
295         HLTError("unknown parameter '%s' for argument '-include-input'", param.Data());
296       }
297       continue;
298     }
299
300     if (strcmp(argv[i], "-process-all-events") == 0)
301     {
302       fDataEventsOnly = false;
303       continue;
304     }
305
306     if (strstr(argv[i], "-monitoring") == argv[i])
307     {
308       TString param=argv[i];
309       param.ReplaceAll("-monitoring", "");
310       if (param.IsNull()) 
311       {
312         // -monitoring
313         // enable monitoring trigger for all events
314         fMonitorPeriod=0;
315       } else {
316         // -monitoring=n
317         // enable monitoring trigger once every n seconds
318         param.ReplaceAll("=", "");
319         if (param.IsDigit()) {
320           fMonitorPeriod=param.Atoi();
321         } else {
322           HLTError("expecting number as parameter for argument '-monitoring=', got %s, skipping monitoring trigger", param.Data());
323         }
324       }
325       continue;
326     }
327
328     if (strcmp(argv[i], "-dont-make-software-triggers") == 0)
329     {
330       fMakeSoftwareTriggers = false;
331       continue;
332     }
333     if (strcmp(argv[i], "-randomseed") == 0)
334     {
335       if (randomSeedSet)
336       {
337         HLTWarning("The random seed was already specified previously with the option -randomseed."
338                    "Will replace the previous value of %d with the new one.",
339                    randomSeed
340         );
341       }
342       if (argc <= i+1)
343       {
344         HLTError("The number to use as the seed was not specified for the -randomseed option." );
345         return -EINVAL;
346       }
347       TString numstr = argv[i+1];
348       if (not numstr.IsDigit())
349       {
350         HLTError("The number specified in the -randomseed option is not a valid decimal integer." );
351         return -EINVAL;
352       }
353       randomSeed = numstr.Atoi();
354       randomSeedSet = true;
355       i++;
356       continue;
357     }
358     
359     HLTError("Unknown option '%s'.", argv[i]);
360     return -EINVAL;
361   } // for loop
362   
363   const AliHLTTriggerMenu* menu = NULL;
364   if (configFileName != NULL)
365   {
366     TString cmd = ".x ";
367     cmd += configFileName;
368     gROOT->ProcessLine(cmd);
369     menu = AliHLTGlobalTriggerConfig::Menu();
370   }
371   
372   // Try load the trigger menu from the CDB if it is not loaded yet with the
373   // -config option
374   int result = -ENOENT;
375   if (menu == NULL)
376   {
377     result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu);
378   }
379   if (menu == NULL)
380   {
381     HLTError("No trigger menu configuration found or specified.");
382     return result;
383   }
384   
385   if (codeFileName == NULL)
386   {
387     result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles);
388     if (result == 0) fDeleteCodeFile = true;
389   }
390   else
391   {
392     result = LoadTriggerClass(codeFileName, fIncludePaths);
393     if (result == 0) fCodeFileName = codeFileName;
394   }
395   if (result != 0) return result;
396   
397   try
398   {
399     fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
400   }
401   catch (const std::bad_alloc&)
402   {
403     HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
404     return -ENOMEM;
405   }
406   if (fTrigger == NULL)
407   {
408     HLTError("Could not create a new instance of '%s'.", fClassName.Data());
409     return -EIO;
410   }
411   
412   fTrigger->FillFromMenu(*menu);
413   if (fTrigger->CallFailed()) return -EPROTO;
414
415   // setup the CTP accounting in AliHLTComponent
416   SetupCTPData();
417
418   // Set the default values from the trigger menu.
419   SetDescription(menu->DefaultDescription());
420   SetTriggerDomain(menu->DefaultTriggerDomain());
421   
422   // Initialise the random number generator seed value.
423   // NOTE: The GenerateTrigger method called above will set the fUniqueID value
424   // with a random value based on a GUID that should be unique across the system.
425   // This is then used as the seed to the random number generator if the -randomseed
426   // option is not used.
427   if (not randomSeedSet) randomSeed = fUniqueID;
428   gRandom->SetSeed(randomSeed);
429   
430   fTotalEventCounter = 0;
431   return 0;
432 }
433
434
435 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
436 {
437   // Cleans up the global trigger component.
438   
439   if (fTrigger != NULL)
440   {
441     delete fTrigger;
442     fTrigger = NULL;
443   }
444   
445   if (fCTPDecisions) {
446     fCTPDecisions->Delete();
447     delete fCTPDecisions;
448   }
449   fCTPDecisions=NULL;
450   fCDH = NULL;
451   
452   Int_t result = UnloadTriggerClass(fCodeFileName);
453   if (result != 0) return result;
454   
455   if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
456     fCodeFileName.ReplaceAll(".cxx", "*");
457     TString command="rm "; command+=fCodeFileName;
458     gSystem->Exec(command);
459   }
460   fCodeFileName="";
461   fDeleteCodeFile=false;
462
463   return 0;
464 }
465
466
467 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
468 {
469   // Creates a new object instance.
470   AliHLTComponent* comp = NULL;
471   try
472   {
473     comp = new AliHLTGlobalTriggerComponent;
474   }
475   catch (const std::bad_alloc&)
476   {
477     HLTError("Could not allocate memory for a new instance of AliHLTGlobalTriggerComponent.");
478     return NULL;
479   }
480   return comp;
481 }
482
483
484 int AliHLTGlobalTriggerComponent::DoTrigger()
485 {
486   // This method will apply the global trigger decision.
487
488   if (fTrigger == NULL)
489   {
490     HLTFatal("Global trigger implementation object is NULL!");
491     return -EIO;
492   }
493
494   AliHLTUInt32_t eventType=0;
495   if (!IsDataEvent(&eventType)) {
496     if (fDataEventsOnly)
497     {
498       if (eventType == gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant);
499       IgnoreEvent();  // dont generate any trigger decision.
500       return 0;
501     }
502   }
503   
504   fCDH = NULL;  // have to reset this in case ExtractTriggerData fails.
505   ExtractTriggerData(*GetTriggerData(), NULL, NULL, &fCDH, NULL);
506
507   // Copy the trigger counters in case we need to set them back to their original
508   // value because the PushBack method fails with ENOSPC.
509   TArrayL64 originalCounters = fTrigger->GetCounters();
510   if (fTrigger->CallFailed()) return -EPROTO;
511   
512   fTrigger->NewEvent();
513   if (fTrigger->CallFailed()) return -EPROTO;
514   
515   // Fill in the input data.
516   const TObject* obj = GetFirstInputObject();
517   while (obj != NULL)
518   {
519     fTrigger->Add(obj, GetDataType(), GetSpecification());
520     if (fTrigger->CallFailed()) return -EPROTO;
521     obj = GetNextInputObject();
522   }
523
524   // add trigger decisions for every CTP class
525   const AliHLTCTPData* pCTPData=CTPData();
526   if (pCTPData) {
527     AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
528   }
529   
530   bool softwareTriggerIsValid = FillSoftwareTrigger();
531   if (softwareTriggerIsValid)
532   {
533     fTrigger->Add(&fSoftwareTrigger, kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
534   }
535   
536   // Calculate the global trigger result and trigger domain, then create and push
537   // back the new global trigger decision object.
538   TString description;
539   AliHLTTriggerDomain triggerDomain;
540   bool triggerResult = false;
541   bool matchedItems = fTrigger->CalculateTriggerDecision(triggerResult, triggerDomain, description);
542   if (fTrigger->CallFailed()) return -EPROTO;
543   AliHLTGlobalTriggerDecision decision(
544       triggerResult,
545       // The following will cause the decision to be generated with default values
546       // (set in fTriggerDomain and fDescription) if the trigger result is false.
547       (matchedItems == true) ? triggerDomain : GetTriggerDomain(),
548       (matchedItems == true) ? description.Data() : GetDescription()
549     );
550
551   decision.SetUniqueID(fUniqueID);
552   decision.SetCounters(fTrigger->GetCounters(), fTotalEventCounter+1);
553   if (fTrigger->CallFailed()) return -EPROTO;
554   
555   TClonesArray shortInfo(TNamed::Class(), GetNumberOfInputBlocks());
556   
557   // Add the input objects used to make the global decision.
558   obj = GetFirstInputObject();
559   while (obj != NULL)
560   {
561     const AliHLTTriggerDecision* intrig = dynamic_cast<const AliHLTTriggerDecision*>(obj);
562     
563     if (TestBit(kForwardInput)) Forward(obj);
564     
565     if (TestBit(kIncludeInput))
566     {
567       if (intrig != NULL)
568       {
569          decision.AddTriggerInput(*intrig);
570       }
571       else
572       {
573         // The const_cast should be safe in this case because the list of inputObjects
574         // will be added to the global decision with AddInputObjectRef, which only
575         // modifies the kCanDelete bit and nothing else.
576         // This is necessary since GetFirstInputObject only returns const objects.
577         decision.AddInputObjectRef( const_cast<TObject*>(obj) );
578       }
579     }
580     
581     if (TestBit(kIncludeShort))
582     {
583       int entries = shortInfo.GetEntriesFast();
584       try
585       {
586         new (shortInfo[entries]) TNamed(obj->GetName(), obj->GetTitle());
587       }
588       catch (const std::bad_alloc&)
589       {
590         HLTError("Could not allocate more memory for the short list of input objects.");
591         return -ENOMEM;
592       }
593       if (intrig != NULL)
594       {
595         shortInfo[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
596         shortInfo[entries]->SetBit(BIT(15), intrig->Result());
597       }
598     }
599
600     obj = GetNextInputObject();
601   }
602   if (TestBit(kIncludeShort)) decision.AddInputObjectRef(&shortInfo);
603   
604   // The const_cast should be safe in this case because AddInputObjectRef just
605   // modifies the kCanDelete bit and nothing else.
606   if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObjectRef(const_cast<AliHLTCTPData*>(CTPData()));
607   
608   if (softwareTriggerIsValid and TestBit(kIncludeInput)) decision.AddTriggerInput(fSoftwareTrigger);
609   
610   static UInt_t lastTime=0;
611   TDatime time;
612   if (time.Get()-lastTime>60)
613   {
614     lastTime=time.Get();
615     PrintStatistics(fTrigger, kHLTLogImportant);
616   }
617   else if (eventType==gkAliEventTypeEndOfRun)
618   {
619     PrintStatistics(fTrigger, kHLTLogImportant);
620   }
621   
622   // add readout filter to event done data
623   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
624
625   // add monitoring filter to event done data if enabled by setting
626   // a monitoring period >=0: -1 means off, 0 means for every event
627   // configured by argument '-monitoring[=n]'
628   if (fMonitorPeriod>=0) {
629     static UInt_t lastMonitorEvent=0;
630
631     AliHLTTriggerDomain monitoringFilter(decision.TriggerDomain());
632     if (decision.Result() &&
633         int(time.Get()-lastMonitorEvent)>fMonitorPeriod) {
634       lastMonitorEvent=time.Get();
635       // add monitoring event command for triggered events
636       CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
637     } else {
638       // empty filter list if events are not triggered
639       // or within the monitoring interval
640       monitoringFilter.Clear();
641     }
642     // add monitoring filter list
643     CreateEventDoneReadoutFilter(monitoringFilter, 4);
644   }
645   
646   // Mask the readout list according to the CTP trigger
647   // if the classes have been initialized (mask non-zero).
648   // If we are dealing with a software trigger on the other hand then
649   // mask with the participating detector list.
650   // In both cases we must make sure that HLT is part of the readout mask.
651   if (CTPData() != NULL and CTPData()->Mask() != 0x0)
652   {
653     AliHLTReadoutList readoutlist = decision.ReadoutList();
654     AliHLTReadoutList ctpreadout = CTPData()->ReadoutList(*GetTriggerData());
655     ctpreadout.Enable(AliHLTReadoutList::kHLT);
656     readoutlist.AndEq(ctpreadout);
657     decision.ReadoutList(readoutlist); // override the readout list with the masked one.
658   }
659   else if (softwareTriggerIsValid)
660   {
661     assert(fCDH != NULL);
662     AliHLTReadoutList readoutlist = decision.ReadoutList();
663     UInt_t detectors = fCDH->GetSubDetectors();
664     AliHLTReadoutList softwareReadout(Int_t(detectors | AliHLTReadoutList::kHLT));
665     readoutlist.AndEq(softwareReadout);
666     decision.ReadoutList(readoutlist); // override the readout list with the masked one.
667   }
668
669   if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -ENOSPC)
670   {
671     // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
672     // returned the "no buffer space" error code. Also remember to set the trigger counters
673     // back to what they were, otherwise triggers will be double counted when we try to reprocess
674     // this event with larger buffers.
675     fBufferSizeConst += 1024*1024;
676     fBufferSizeMultiplier *= 2.;
677     fTrigger->SetCounters(originalCounters);
678     if (fTrigger->CallFailed()) return -EPROTO;
679     return -ENOSPC;
680   }
681   
682   ++fTotalEventCounter;
683   return 0;
684 }
685
686
687 int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId)
688 {
689   // Reconfigure the component by loading the trigger menu and recreating the
690   // trigger logic class.
691   
692   const char* path = fgkTriggerMenuCDBPath;
693   const char* id = "(unknown)";
694   if (cdbEntry != NULL) path = cdbEntry;
695   if (chainId != NULL and chainId[0] != '\0') id = chainId;
696   HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id);
697   
698   const AliHLTTriggerMenu* menu = NULL;
699   int result = LoadTriggerMenu(path, menu);
700   if (result != 0) return result;
701   
702   TString className;
703   TString codeFileName;
704   result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
705   if (result != 0) return result;
706   
707   AliHLTGlobalTrigger* trigger = NULL;
708   try
709   {
710     trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
711   }
712   catch (const std::bad_alloc&)
713   {
714     HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
715     return -ENOMEM;
716   }
717   if (trigger == NULL)
718   {
719     HLTError("Could not create a new instance of '%s'.", className.Data());
720     // Make sure to cleanup after the new code file.
721     UnloadTriggerClass(codeFileName);
722     if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
723     {
724       codeFileName.ReplaceAll(".cxx", "*");
725       TString command="rm "; command+=codeFileName;
726       gSystem->Exec(command);
727     }
728     return -EIO;
729   }
730   
731   if (fTrigger != NULL)
732   {
733     delete fTrigger;
734     fTrigger = NULL;
735   }
736   
737   fTrigger = trigger;
738   fTrigger->FillFromMenu(*menu);
739   if (fTrigger->CallFailed()) return -EPROTO;
740
741   // Set the default values from the trigger menu.
742   SetDescription(menu->DefaultDescription());
743   SetTriggerDomain(menu->DefaultTriggerDomain());
744   
745   // Cleanup the old class code.
746   UnloadTriggerClass(fCodeFileName);
747   if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
748   {
749     fCodeFileName.ReplaceAll(".cxx", "*");
750     TString command="rm "; command+=fCodeFileName;
751     gSystem->Exec(command);
752   }
753   fCodeFileName = codeFileName;
754   fDeleteCodeFile = true;  // Since we generated a new class.
755   
756   return 0;
757 }
758
759
760 int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu)
761 {
762   // Loads the trigger menu object from the CDB path.
763   
764   HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
765   if (AliCDBManager::Instance() == NULL)
766   {
767     HLTError("CDB manager object not found.");
768     return -EIO;
769   }
770   AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
771   if (store == NULL)
772   {
773     HLTError("Could not get the the default storage for the CDB.");
774     return -EIO;
775   }
776   Int_t version = store->GetLatestVersion(cdbPath, GetRunNo());
777   if (version < 0)
778   {
779     HLTError("Could not find an entry in the CDB for \"%s\".", cdbPath);
780     return -EIO;
781   }
782   Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version);
783   AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion);
784   if (entry == NULL)
785   {
786     HLTError("Could not get the CDB entry for \"%s\".", cdbPath);
787     return -EIO;
788   }
789   TObject* obj = entry->GetObject();
790   if (obj == NULL)
791   {
792     HLTError("Configuration object for \"%s\" is missing.", cdbPath);
793     return -ENOENT;
794   }
795   if (obj->IsA() != AliHLTTriggerMenu::Class())
796   {
797     HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
798              cdbPath, obj->ClassName()
799     );
800     return -EPROTO;
801   }
802   menu = static_cast<AliHLTTriggerMenu*>(obj);
803   return 0;
804 }
805
806
807 void AliHLTGlobalTriggerComponent::GenerateFileName(TString& name, TString& filename)
808 {
809   // Creates a unique file name for the generated code.
810   
811   TUUID guid = GenerateGUID();
812   union
813   {
814     UChar_t buf[16];
815     UInt_t bufAsInt[4];
816   };
817   guid.GetUUID(buf);
818   fUniqueID = bufAsInt[0];
819   TString guidstr = guid.AsString();
820   // Replace '-' with '_' in string.
821   for (int i = 0; i < guidstr.Length(); ++i)
822   {
823     if (guidstr[i] == '-') guidstr[i] = '_';
824   }
825   name = "AliHLTGlobalTriggerImpl_";
826   name += guidstr;
827   filename = name + ".cxx";
828
829   // For good measure, check that the file names are not used. If they are then regenerate.
830   fstream file(filename.Data(), ios_base::in);
831   if (file.good())
832   {
833     file.close();
834     GenerateFileName(name, filename);
835   }
836 }
837
838
839 int AliHLTGlobalTriggerComponent::GenerateTrigger(
840     const AliHLTTriggerMenu* menu, TString& name, TString& filename,
841     const TClonesArray& includePaths, const TClonesArray& includeFiles
842   )
843 {
844   // Generates the global trigger class that will implement the specified trigger menu.
845   // See header for more details.
846   
847   GenerateFileName(name, filename);
848   HLTDebug("Generating custom HLT trigger class named %s, in file %s, using trigger menu %p.",
849     name.Data(), filename.Data(), ((void*)menu)
850   );
851   
852   // Open a text file to write the code and generate the new class.
853   fstream code(filename.Data(), ios_base::out | ios_base::trunc);
854   if (not code.good())
855   {
856     HLTError("Could not open file '%s' for writing.", filename.Data());
857     return -EIO;
858   }
859   
860   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
861   int result = BuildSymbolList(menu, symbols);
862   if (result != 0) return result;
863   
864   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
865   code << "#include <cstring>" << endl;
866   code << "#include \"TClass.h\"" << endl;
867   code << "#include \"TString.h\"" << endl;
868   code << "#include \"TClonesArray.h\"" << endl;
869   code << "#include \"TRandom3.h\"" << endl;
870   code << "#include \"AliHLTLogging.h\"" << endl;
871   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
872   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
873   code << "#include \"AliHLTDomainEntry.h\"" << endl;
874   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
875   code << "#include \"AliHLTReadoutList.h\"" << endl;
876   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
877   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
878   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
879   
880   // Add any include files that were specified on the command line.
881   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
882   {
883     TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
884     code << "#include \"" << file.Data() << "\"" << endl;
885   }
886   
887   if (fDebugMode)
888   {
889     code << "#else" << endl;
890     code << "const char* gFunctionName = \"???\";" << endl;
891     code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl;
892   }
893   code << "#endif" << endl;
894   
895   code << "class " << name << " :" << endl;
896   // Add appropriate #ifdef sections since we need to prevent inheritance from
897   // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor
898   // multiple levels of inheritance. Neither of the following schemes worked:
899   //
900   // 1)  class AliHLTGlobalTrigger : public AliHLTLogging {};
901   //     class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {};
902   //
903   // 2)  class AliHLTGlobalTrigger {};
904   //     class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {};
905   //
906   // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT
907   // interpreter. But we anyway have to call the global trigger implementation class
908   // through the AliHLTGlobalTriggerWrapper so this is not such a problem.
909   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
910   code << "  public AliHLTGlobalTrigger," << endl;
911   code << "#endif" << endl;
912   code << "  public AliHLTLogging" << endl;
913   code << "{" << endl;
914   code << "public:" << endl;
915   
916   // Generate constructor method.
917   code << "  " << name << "() :" << endl;
918   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
919   code << "    AliHLTGlobalTrigger()," << endl;
920   code << "#endif" << endl;
921   code << "    AliHLTLogging()";
922   // Write the symbols in the trigger menu in the initialisation list.
923   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
924   {
925     code << "," << endl;
926     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
927     code << "    " << symbol->Name() << "()," << endl;
928     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
929     {
930       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
931     }
932     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
933   }
934   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
935   {
936     code << "," << endl << "    fMenuItemDescription" << i << "()";
937   }
938   code << endl << "  {" << endl;
939   if (fDebugMode)
940   {
941     code << "#ifdef __CINT__" << endl;
942     code << "    gFunctionName = \"" << name.Data() <<"\";" << endl;
943     code << "#endif" << endl;
944     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
945     code << "    HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl;
946   }
947   code << "  }" << endl;
948   
949   code << "  virtual ~" << name << "() {" << endl;
950   if (fDebugMode)
951   {
952     code << "#ifdef __CINT__" << endl;
953     code << "    gFunctionName = \"~" << name.Data() << "\";" << endl;
954     code << "#endif" << endl;
955     code << "    HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl;
956   }
957   code << "  }" << endl;
958   
959   // Generate the FillFromMenu method.
960   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
961   if (fDebugMode)
962   {
963     code << "#ifdef __CINT__" << endl;
964     code << "    gFunctionName = \"FillFromMenu\";" << endl;
965     code << "#endif" << endl;
966     code << "    HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl;
967   }
968   code << "    fCounter.Set(menu.NumberOfItems());" << endl;
969   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
970   {
971     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
972          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
973   }
974   if (fDebugMode)
975   {
976     code << "    HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl;
977     code << "    HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
978   }
979   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
980   // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
981   // Have to use the TClass system for extra protection.
982   code << "      if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
983   code << "      if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
984   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
985            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
986   code << "      if (symbol == NULL) continue;" << endl;
987   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
988   {
989     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
990     code << "      if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
991     if (fDebugMode)
992     {
993       code << "        HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
994               " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
995     }
996     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
997     code << "        continue;" << endl;
998     code << "      }" << endl;
999   }
1000   code << "    }" << endl;
1001   // The following is an optimisation where symbols without any assignment operators
1002   // are treated as constant and only initialised in FillFromMenu rather than reseting
1003   // them in the NewEvent method.
1004   // Note: we putting this initialisation into the constructor can lead to seg faults
1005   // under CINT interpretation. Thus we must put it into the FillFromMenu method instead.
1006   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1007   {
1008     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1009     if (TString(symbol->AssignExpression()) != "") continue;
1010     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) continue;
1011     // CINT has problems with the implicit equals operator for complex types, so if
1012     // the type has an equals operater we need to write the operator call explicitly.
1013     TClass* clas = TClass::GetClass(symbol->Type());
1014     if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
1015     {
1016       code << "    " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
1017     }
1018     else
1019     {
1020       code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1021     }
1022   }
1023   if (fDebugMode)
1024   {
1025     code << "    HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
1026   }
1027   code << "  }" << endl;
1028   
1029   // Generate the NewEvent method.
1030   code << "  virtual void NewEvent() {" << endl;
1031   if (fDebugMode)
1032   {
1033     code << "#ifdef __CINT__" << endl;
1034     code << "    gFunctionName = \"NewEvent\";" << endl;
1035     code << "#endif" << endl;
1036     code << "    HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl;
1037   }
1038   // Write code to initialise the symbols in the trigger menu to their default values.
1039   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1040   {
1041     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1042     // The following is an optimisation. If the symbol does not have an assignment expression
1043     // then it is effectively a constant symbol and can be initialised earlier and only once.
1044     // In this case we initialise it in the FillFromMenu method instead.
1045     if (TString(symbol->AssignExpression()) == "") continue;
1046     // CINT has problems with the implicit equals operator for complex types, so if
1047     // the type has an equals operater we need to write the operator call explicitly.
1048     TClass* clas = TClass::GetClass(symbol->Type());
1049     if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
1050     {
1051       code << "    " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
1052     }
1053     else
1054     {
1055       code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1056     }
1057     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1058     {
1059       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
1060     }
1061   }
1062   if (fDebugMode)
1063   {
1064     code << "    HLTDebug(Form(\"Finished initialising variables.\"));" << endl;
1065   }
1066   code << "  }" << endl;
1067   
1068   // Generate the Add method.
1069   bool haveAssignments = false;
1070   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1071   {
1072     // First check if we have any symbols with assignment expressions.
1073     // This is needed to get rid of the on the fly compilation warning about '_object_' not being used.
1074     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1075     TString expr = symbol->AssignExpression();
1076     if (expr == "") continue; // Skip entries that have no assignment expression.
1077     haveAssignments = true;
1078     break;
1079   }
1080   if (haveAssignments or fDebugMode)
1081   {
1082     code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1083   }
1084   else
1085   {
1086     code << "  virtual void Add(const TObject* /*_object_*/, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1087   }
1088   if (fDebugMode)
1089   {
1090     code << "#ifdef __CINT__" << endl;
1091     code << "    gFunctionName = \"Add\";" << endl;
1092     code << "#endif" << endl;
1093   }
1094   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
1095   if (fDebugMode)
1096   {
1097     code << "    HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block"
1098             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
1099             " _type_spec_.AsString().Data(), this));" << endl;
1100     code << "    _object_->Print();" << endl;
1101     code << "    bool _object_assigned_ = false;" << endl;
1102   }
1103   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1104   {
1105     // Write code to check if the block type, specification and class name is correct.
1106     // Then write code to assign the variable from the input object.
1107     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1108     TString expr = symbol->AssignExpression();
1109     if (expr == "") continue; // Skip entries that have no assignment expression.
1110     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
1111     if (fDebugMode)
1112     {
1113       if (isTrigDecision)
1114       {
1115         code << "    HLTDebug(Form(\"Trying to match input object to class '"
1116              << symbol->ObjectClass() << "', trigger name '" << symbol->RealName()
1117              << "' and block type '%s'\", " << symbol->Name()
1118              << "DomainEntry.AsString().Data()));" << endl;
1119       }
1120       else
1121       {
1122         code << "    HLTDebug(Form(\"Trying to match input object to class '"
1123              << symbol->ObjectClass() << "' and block type '%s'\", "
1124              << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
1125       }
1126     }
1127     // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
1128     // Have to use the TClass system for extra protection.
1129     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
1130     code << "    if (_object_->InheritsFrom(" << symbol->ObjectClass() << "::Class())) " << symbol->Name()
1131          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
1132          << "*>(_object_);" << endl;
1133     code << "    if (" << symbol->Name() << "_object_ != NULL && ";
1134     if (isTrigDecision)
1135     {
1136       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
1137            << symbol->RealName() << "\") == 0 && ";
1138     }
1139     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
1140     TString fullname = symbol->Name();
1141     fullname += "_object_";
1142     expr.ReplaceAll("this", fullname);
1143     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
1144     if (isTrigDecision)
1145     {
1146       code << "      this->" << symbol->Name() << "TriggerDomain = "
1147            << fullname.Data() << "->TriggerDomain();" << endl;
1148     }
1149     if (fDebugMode)
1150     {
1151       code << "      HLTDebug(Form(\"Added TObject %p with class name '%s' to variable "
1152            << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl;
1153       code << "      _object_assigned_ = true;" << endl;
1154     }
1155     code << "    }" << endl;
1156   }
1157   if (fDebugMode)
1158   {
1159     code << "    if (! _object_assigned_) {" << endl;
1160     code << "      HLTDebug(Form(\"Did not assign TObject %p"
1161             " with class name '%s' to any variable.\", _object_, _object_->ClassName()));"
1162          << endl;
1163     code << "    }" << endl;
1164   }
1165   code << "  }" << endl;
1166   
1167   // Generate the CalculateTriggerDecision method.
1168   // This requires code to be generated that checks which items in the trigger menu
1169   // have their conditions asserted and then the trigger domain is generated from
1170   // those fired items.
1171   // The processing will start from the highest priority trigger group and stop
1172   // after at least one trigger from the current priority group being processed
1173   // is positive. For each priority group all the trigger menu items are checked.
1174   // Their combined trigger condition expression must be true for the trigger priority
1175   // group to be triggered positive. The full condition expression is formed by
1176   // concatenating the individual condition expressions. If no trailing operators are
1177   // used in the individual expressions then the default condition operator is placed
1178   // between two concatenated condition expressions.
1179   // If a trigger priority group has at least one trigger fired then the trigger domain
1180   // is calculated such that it will give the same result as the concatenated trigger
1181   // domain merging expressions for all the individual trigger menu items with
1182   // positive results. Again, if no trailing operators are used in the individual
1183   // merging expressions then the default domain operator is placed between two
1184   // expression fragments.
1185   code << "  virtual bool CalculateTriggerDecision(bool& _trigger_result_, AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
1186   if (fDebugMode)
1187   {
1188     code << "#ifdef __CINT__" << endl;
1189     code << "    gFunctionName = \"CalculateTriggerDecision\";" << endl;
1190     code << "#endif" << endl;
1191     code << "    HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl;
1192   }
1193   
1194   // Build a list of priorities used in the trigger menu.
1195   std::vector<UInt_t> priorities;
1196   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1197   {
1198     const AliHLTTriggerMenuItem* item = menu->Item(i);
1199     bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end();
1200     if (priorityNotInList) priorities.push_back(item->Priority());
1201   }
1202   std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers);
1203   // From the priority list, build the priority groups in the correct order,
1204   // i.e. highest priority first.
1205   // The priority group is a list of vectors of integers. The integers are the
1206   // index numbers into the trigger menu item list for the items which form part
1207   // of the priority group.
1208   std::vector<std::vector<Int_t> > priorityGroup;
1209   priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector<Int_t>());
1210   for (size_t n = 0; n < priorities.size(); n++)
1211   {
1212     UInt_t priority = priorities[n];
1213     for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1214     {
1215       const AliHLTTriggerMenuItem* item = menu->Item(i);
1216       if (item->Priority() == priority) priorityGroup[n].push_back(i);
1217     }
1218   }
1219   
1220   for (size_t n = 0; n < priorityGroup.size(); n++)
1221   {
1222     if (fDebugMode)
1223     {
1224       code << "    HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl;
1225     }
1226     code << "    ";
1227     if (n == 0) code << "UInt_t ";
1228     code << "_previous_match_ = 0xFFFFFFFF;" << endl;
1229     code << "    ";
1230     if (n == 0) code << "bool ";
1231     code << "_trigger_matched_ = false;" << endl;
1232     code << "    ";
1233     if (n == 0) code << "bool ";
1234     code << "_group_result_ = false;" << endl;
1235     std::vector<TString> conditionOperator;
1236     conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString(""));
1237     std::vector<TString> domainOperator;
1238     domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString(""));
1239     for (size_t m = 0; m < priorityGroup[n].size(); m++)
1240     {
1241       UInt_t i = priorityGroup[n][m];
1242       const AliHLTTriggerMenuItem* item = menu->Item(i);
1243       TString triggerCondition = item->TriggerCondition();
1244       TString mergeExpr = item->MergeExpression();
1245       // Replace the symbols found in the trigger condition and merging expressions
1246       // with appropriate compilable versions.
1247       for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
1248       {
1249         AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
1250         bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0;
1251         if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1252         {
1253           TString newname = symbol->Name();
1254           newname += "TriggerDomain";
1255           mergeExpr.ReplaceAll(symbol->RealName(), newname);
1256         }
1257         else
1258         {
1259           if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name());
1260         }
1261         if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name());
1262       }
1263       // We allow the trigger conditions and merging expressions to have trailing operators.
1264       // Thus, we need to extract the operators and cleanup the expressions so that they will
1265       // compile. This means that we silently ignore the trailing operator if not needed.
1266       if (ExtractedOperator(triggerCondition, conditionOperator[m]))
1267       {
1268         // If the trailing operator is the same as the default operator then reset
1269         // the value in the operator list so that the default is used in the generated
1270         // code. This creates more compact code.
1271         if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = "";
1272       }
1273       if (ExtractedOperator(mergeExpr, domainOperator[m]))
1274       {
1275         if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = "";
1276       }
1277       if (fDebugMode)
1278       {
1279         code << "    HLTDebug(Form(\"Trying trigger condition " << i
1280              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));"
1281              << endl;
1282       }
1283       code << "    ";
1284       if (n == 0 and m == 0) code << "bool ";
1285       code << "_item_result_ = false;" << endl;
1286       code << "    if (" << triggerCondition << ") {" << endl;
1287       code << "      ++fCounter[" << i << "];" << endl;
1288       const char* indentation = "";
1289       // Generate the code to handle the prescalar and scale-down
1290       bool havePrescalar = item->PreScalar() != 0;
1291       bool haveScaledown = item->ScaleDown() < 1;
1292       if (havePrescalar or haveScaledown) 
1293       {
1294         indentation = "  ";
1295         code << "      if (";
1296         if (havePrescalar) code << "(fCounter[" << i << "] % " << item->PreScalar() << ") == 1";
1297         if (havePrescalar and haveScaledown) code << " && ";
1298         if (haveScaledown)
1299         {
1300           std::streamsize oldprecision = code.precision(17);
1301           code << "gRandom->Rndm() < " << item->ScaleDown();
1302           code.precision(oldprecision);
1303         }
1304         code << ") {" << endl;
1305       }
1306       code << indentation << "      _item_result_ = true;" << endl;
1307       if (fDebugMode)
1308       {
1309         code << indentation << "      HLTDebug(Form(\"Matched trigger condition " << i
1310              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
1311       }
1312       if (havePrescalar or haveScaledown)
1313       {
1314         code << "      }" << endl;
1315       }
1316       code << "    }" << endl;
1317       if (m == 0)
1318       {
1319         // Since this is the first item of the trigger group,
1320         // the generated trigger logic can be simplified a little.
1321         code << "    _group_result_ = _item_result_;" << endl;
1322         code << "    if (_item_result_) {" << endl;
1323         code << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
1324         code << "      _description_ = fMenuItemDescription" << i << ";" << endl;
1325         code << "      _previous_match_ = " << i << ";" << endl;
1326         code << "      _trigger_matched_ = true;" << endl;
1327         code << "    }" << endl;
1328       }
1329       else
1330       {
1331         if (conditionOperator[m-1] == "")
1332         {
1333           code << "    _group_result_ = _group_result_ "
1334                << menu->DefaultConditionOperator() << " _item_result_;" << endl;
1335         }
1336         else
1337         {
1338           code << "    _group_result_ = _group_result_ "
1339                << conditionOperator[m-1] << " _item_result_;" << endl;
1340         }
1341         code << "    if (_item_result_) {" << endl;
1342         code << "      if (_trigger_matched_) {" << endl;
1343         bool switchWillBeEmpty = true;
1344         for (size_t k = 0; k < m; k++)
1345         {
1346           if (domainOperator[k] == "") continue;
1347           switchWillBeEmpty = false;
1348         }
1349         if (switchWillBeEmpty)
1350         {
1351           code << "        _domain_ = _domain_ " << menu->DefaultDomainOperator() << " "
1352                << mergeExpr.Data() << ";" << endl;
1353         }
1354         else
1355         {
1356           code << "        switch(_previous_match_) {" << endl;
1357           for (size_t k = 0; k < m; k++)
1358           {
1359             if (domainOperator[k] == "") continue;
1360             code << "        case " << k << ": _domain_ = _domain_ "
1361                  << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl;
1362           }
1363           code << "        default: _domain_ = _domain_ "
1364                << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl;
1365           code << "        }" << endl;
1366         }
1367         code << "        _description_ += \",\";" << endl;
1368         code << "        _description_ += fMenuItemDescription" << i << ";" << endl;
1369         code << "      } else {" << endl;
1370         code << "        _domain_ = " << mergeExpr.Data() << ";" << endl;
1371         code << "        _description_ = fMenuItemDescription" << i << ";" << endl;
1372         code << "      }" << endl;
1373         code << "      _previous_match_ = " << i << ";" << endl;
1374         code << "      _trigger_matched_ = true;" << endl;
1375         code << "    }" << endl;
1376       }
1377     }
1378     code << "    if (_group_result_) {" << endl;
1379     if (fDebugMode)
1380     {
1381       if (n < priorities.size() - 1)
1382       {
1383         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n]
1384              << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl;
1385       }
1386       else
1387       {
1388         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
1389       }
1390     }
1391     bool methodReturnResult = true;
1392     if (priorityGroup[n].size() > 0)
1393     {
1394       const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][0]);
1395       methodReturnResult = item->DefaultResult();
1396     }
1397     // Check to see if the items of the group all have the same default result.
1398     // If not then warn the user since only the first item's value will be used.
1399     for (size_t m = 1; m < priorityGroup[n].size(); m++)
1400     {
1401       const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][m]);
1402       if (item->DefaultResult() != methodReturnResult)
1403       {
1404         HLTWarning("Found items with different default results set for priority group %d."
1405                    "Will only use the value from the first item.",
1406                    item->Priority()
1407                   );
1408         break;
1409       }
1410     }
1411     code << "      _trigger_result_ = " << (methodReturnResult ? "true" : "false") << ";" << endl;
1412     code << "      return true;" << endl;
1413     code << "    }" << endl;
1414   }
1415   code << "    _domain_.Clear();" << endl;
1416   code << "    _description_ = \"\";" << endl;
1417   code << "    _trigger_result_ = " << (menu->DefaultResult() ? "true" : "false") << ";" << endl;
1418   code << "    return false;" << endl;
1419   code << "  }" << endl;
1420   
1421   // Generate getter and setter methods for the counters.
1422   code << "  const TArrayL64& GetCounters() const { return fCounter; }" << endl;
1423   code << "  void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl;
1424   
1425   code << "private:" << endl;
1426   // Add the symbols in the trigger menu to the list of private variables.
1427   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1428   {
1429     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1430     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
1431     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1432     {
1433       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
1434     }
1435     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
1436   }
1437   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1438   {
1439     code << "  TString fMenuItemDescription" << i << ";" << endl;
1440   }
1441   code << "  TArrayL64 fCounter;" << endl;
1442   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1443   code << "  ClassDef(" << name.Data() << ", 0)" << endl;
1444   code << "#else" << endl;
1445   code << "  virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl;
1446   code << "#endif" << endl;
1447   code << "};" << endl;
1448   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1449   code << "ClassImp(" << name.Data() << ")" << endl;
1450   code << "#endif" << endl;
1451   
1452   code.close();
1453   
1454   // Now we need to compile and load the new class.
1455   result = LoadTriggerClass(filename, includePaths);
1456   return result;
1457 }
1458
1459
1460 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
1461     const char* filename, const TClonesArray& includePaths
1462   )
1463 {
1464   // Loads the code for a custom global trigger class implementation on the fly.
1465   
1466   HLTDebug("Loading HLT trigger class from file '%s'.", filename);
1467   
1468   TString compiler = gSystem->GetBuildCompilerVersion();
1469   if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1470   {
1471     TString includePath;
1472 #if defined(PKGINCLUDEDIR)
1473     // this is especially for the HLT build system where the package is installed
1474     // in a specific directory including proper treatment of include files
1475     includePath.Form("-I%s", PKGINCLUDEDIR);
1476 #else
1477     // the default AliRoot behavior, all include files can be found in the
1478     // $ALICE_ROOT subfolders
1479     includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
1480 #endif
1481     // Add any include paths that were specified on the command line.
1482     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
1483     {
1484       TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
1485       includePath += " -I";
1486       includePath += path;
1487     }
1488     HLTDebug("using include settings: %s", includePath.Data());
1489     gSystem->SetIncludePath(includePath);
1490     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
1491     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
1492     
1493     int result = kTRUE;
1494     if (fDebugMode)
1495     {
1496       result = gSystem->CompileMacro(filename, "g");
1497     }
1498     else
1499     {
1500       result = gSystem->CompileMacro(filename, "O");
1501     }
1502     if (result != kTRUE)
1503     {
1504       HLTFatal("Could not compile and load global trigger menu implementation.");
1505       return -ENOENT;
1506     }
1507   }
1508   else
1509   {
1510     // Store the library state to be checked later in UnloadTriggerClass.
1511     fLibStateAtLoad = gSystem->GetLibraries();
1512     
1513     // If we do not support the compiler then try interpret the class instead.
1514     TString cmd = ".L ";
1515     cmd += filename;
1516     Int_t errorcode = TInterpreter::kNoError;
1517     gROOT->ProcessLine(cmd, &errorcode);
1518     if (errorcode != TInterpreter::kNoError)
1519     {
1520       HLTFatal("Could not load interpreted global trigger menu implementation"
1521                " (Interpreter error code = %d).",
1522                errorcode
1523       );
1524       return -ENOENT;
1525     }
1526   }
1527   
1528   return 0;
1529 }
1530
1531
1532 int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
1533 {
1534   // Unloads the code previously loaded by LoadTriggerClass.
1535   
1536   HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
1537   
1538   TString compiler = gSystem->GetBuildCompilerVersion();
1539   if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1540   {
1541     // Generate the library name.
1542     TString libname = filename;
1543     Ssiz_t dotpos = libname.Last('.');
1544     if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
1545     libname += ".";
1546     libname += gSystem->GetSoExt();
1547     
1548     // This is a workaround for a problem with unloading shared libraries in ROOT.
1549     // If the trigger logic library is loaded before the libAliHLTHOMER.so library
1550     // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1551     // call all the subsequent libraries get unloded. This means that any objects created
1552     // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
1553     // since the executable code has been unloaded.
1554     // We need to check if there are any more libraries loaded after the class we
1555     // are unloading and in that case don't unload the class.
1556     TString libstring = gSystem->GetLibraries();
1557     TString token, lastlib;
1558     Ssiz_t from = 0;
1559     Int_t numOfLibs = 0, posOfLib = -1;
1560     while (libstring.Tokenize(token, from, " "))
1561     {
1562       ++numOfLibs;
1563       lastlib = token;
1564       if (token.Contains(libname)) posOfLib = numOfLibs;
1565     }
1566     if (numOfLibs != posOfLib)
1567     {
1568       HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
1569           " library '%s' since another library '%s' was loaded afterwards. Trying to"
1570           " unload this library will remove the others and lead to serious memory faults.",
1571           libname.Data(), lastlib.Data()
1572       ));
1573       return 0;
1574     }
1575     
1576     char* path = NULL;
1577     int result = 0;
1578     if ((path = gSystem->DynamicPathName(libname)) != NULL)
1579     {
1580       result = gInterpreter->UnloadFile(path);
1581       delete [] path;
1582     }
1583     if (result != TInterpreter::kNoError) return -ENOENT;
1584   }
1585   else
1586   {
1587     // This is again a workaround for the problem with unloading files in ROOT.
1588     // If the trigger logic class is loaded before the libAliHLTHOMER.so library
1589     // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1590     // call all the subsequent libraries get unloded.
1591     // We need to check if the list of loaded libraries has changed since the last
1592     // call to LoadTriggerClass. If it has then don't unload the class.
1593     if (fLibStateAtLoad != gSystem->GetLibraries())
1594     {
1595       TString libstring = gSystem->GetLibraries();
1596       TString token;
1597       Ssiz_t from = 0;
1598       while (libstring.Tokenize(token, from, " "))
1599       {
1600         if (not fLibStateAtLoad.Contains(token)) break;
1601       }
1602       HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
1603           " '%s' since another library '%s' was loaded afterwards. Trying to unload"
1604           " this file will remove the other library and lead to serious memory faults.",
1605           filename, token.Data()
1606       ));
1607       return 0;
1608     }
1609   
1610     // If we did not compile the trigger logic then remove the interpreted class.
1611     TString cmd = ".U ";
1612     cmd += filename;
1613     Int_t errorcode = TInterpreter::kNoError;
1614     gROOT->ProcessLine(cmd, &errorcode);
1615     if (errorcode != TInterpreter::kNoError)
1616     {
1617       HLTFatal("Could not unload interpreted global trigger menu implementation"
1618                " (Interpreter error code = %d).",
1619                errorcode
1620       );
1621       return -ENOENT;
1622     }
1623   }
1624   
1625   return 0;
1626 }
1627
1628
1629 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
1630 {
1631   // Searches for the named symbol in the given list.
1632   // See header for more details.
1633   
1634   for (int i = 0; i < list.GetEntriesFast(); i++)
1635   {
1636     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
1637     if (symbol == NULL) continue;
1638     if (strcmp(symbol->Name(), name) == 0) return i;
1639   }
1640   return -1;
1641 }
1642
1643
1644 namespace
1645 {
1646   /**
1647    * Helper routine to compare two trigger menu symbols to see if b is a subset of a.
1648    * \returns true if b is a subset of a or they are unrelated.
1649    */
1650   bool AliHLTCheckForContainment(const AliHLTTriggerMenuSymbol* a, const AliHLTTriggerMenuSymbol* b)
1651   {
1652     TString bstr = b->Name();
1653     return bstr.Contains(a->Name());
1654   }
1655
1656 } // end of namespace
1657
1658
1659 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
1660 {
1661   // Builds the list of symbols to use in the custom global trigger menu
1662   // implementation class.
1663   // See header for more details.
1664   
1665   // Note: when we build the symbol list we must use the symbol name as returned
1666   // by the Name() method and not the RealName() method when using FindSymbol.
1667   // This is so that we avoid problems with the generated code not compiling
1668   // because names like "abc-xyz" and "abc_xyz" are synonymous.
1669   // Name() returns the converted C++ symbol name as used in the generated code.
1670   
1671   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
1672   {
1673     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
1674     if (FindSymbol(symbol->Name(), list) != -1)
1675     {
1676       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
1677       return -EIO;
1678     }
1679     try
1680     {
1681       new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
1682     }
1683     catch (const std::bad_alloc&)
1684     {
1685       HLTError("Could not allocate more memory for the symbols list when adding a trigger menu symbol.");
1686       return -ENOMEM;
1687     }
1688   }
1689   Int_t initialEntryCount = list.GetEntriesFast();
1690   
1691   // Note: the \\. must not be the first element in the character class, otherwise
1692   // it is interpreted as an "any character" dot symbol.
1693   TRegexp exp("[_a-zA-Z][-\\._a-zA-Z0-9]*");
1694   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1695   {
1696     const AliHLTTriggerMenuItem* item = menu->Item(i);
1697     TString str = item->TriggerCondition();
1698     Ssiz_t start = 0;
1699     do
1700     {
1701       Ssiz_t length = 0;
1702       Ssiz_t pos = exp.Index(str, &length, start);
1703       if (pos == kNPOS) break;
1704       start = pos+length;
1705       
1706       // Check if there is a numerical character before the found
1707       // regular expression. If so, then the symbol is not a valid one
1708       // and should be skipped.
1709       if (pos > 0)
1710       {
1711         bool notValid = false;
1712         switch (str[pos-1])
1713         {
1714         case '0': case '1': case '2': case '3': case '4':
1715         case '5': case '6': case '7': case '8': case '9':
1716           notValid = true;
1717           break;
1718         default:
1719           notValid = false;
1720           break;
1721         }
1722         if (notValid) continue;
1723       }
1724       TString s = str(pos, length);
1725       
1726       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1727           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1728           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
1729           s == "false"
1730          )
1731       {
1732         // Ignore iso646.h and other keywords.
1733         continue;
1734       }
1735       
1736       // We need to handle the special case where the symbol contains a dot.
1737       // In C++ this is a dereferencing operator. So we need to check if the
1738       // current symbol we are handling starts with the same string as any of
1739       // the existing symbols defined manually in the symbols table.
1740       // If we do find such a case then revert to treating the dot as an operator
1741       // rather than part of the symbol name. i.e. skip adding the automatic symbol.
1742       bool dereferencedSymbol = false;
1743       for (int j = 0; j < initialEntryCount; j++)
1744       {
1745         const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(j) );
1746         if (symbol == NULL) continue;
1747         TString symstr = symbol->Name();
1748         symstr += ".";
1749         if (s.BeginsWith(symstr))
1750         {
1751           dereferencedSymbol = true;
1752           break;
1753         }
1754       }
1755       if (dereferencedSymbol) continue;
1756
1757       // Need to create the symbols first and check if its name is in the list
1758       // before actually adding it to the symbols list.
1759       AliHLTTriggerMenuSymbol newSymbol;
1760       newSymbol.Name(s.Data());
1761       newSymbol.Type("bool");
1762       newSymbol.ObjectClass("AliHLTTriggerDecision");
1763       newSymbol.AssignExpression("this->Result()");
1764       newSymbol.DefaultValue("false");
1765       if (FindSymbol(newSymbol.Name(), list) == -1)
1766       {
1767         try
1768         {
1769           new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
1770         }
1771         catch (const std::bad_alloc&)
1772         {
1773           HLTError("Could not allocate more memory for the symbols list when adding a trigger name symbol.");
1774           return -ENOMEM;
1775         }
1776       }
1777     }
1778     while (start < str.Length());
1779   }
1780   
1781   // This last part is necessary to make sure that symbols are replaced in the
1782   // trigger condition and domain merging expressions in a greedy manner.
1783   // I.e. we need to make sure that if one symbol's string representation is
1784   // contained inside another (string subset) that the longer symbol name is
1785   // always first in the symbols list.
1786   // This will work because the symbol table is traversed from first to last
1787   // element and TString::ReplaceAll is used to replace the substrings inside
1788   // the AliHLTGlobalTriggerComponent::GenerateTrigger method.
1789   std::vector<AliHLTTriggerMenuSymbol*> orderedList;
1790   for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1791   {
1792     orderedList.push_back( static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i)) );
1793   }
1794   std::sort(orderedList.begin(), orderedList.end(), AliHLTCheckForContainment);
1795   //std::sort(orderedList.begin(), orderedList.end());
1796   // Now swap values around according to the orderedList.
1797   for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1798   {
1799     AliHLTTriggerMenuSymbol* target = static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i));
1800     AliHLTTriggerMenuSymbol tmp = *target;
1801     *target = *orderedList[i];
1802     *orderedList[i] = tmp;
1803   }
1804   
1805   return 0;
1806 }
1807
1808
1809 bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
1810 {
1811   // Extracts the trailing operator from the expression.
1812   
1813   Ssiz_t i = 0;
1814   // First skip the trailing whitespace.
1815   bool whitespace = true;
1816   for (i = expr.Length()-1; i >= 0 and whitespace; i--)
1817   {
1818     switch (expr[i])
1819     {
1820     case ' ': case '\t': case '\r': case '\n':
1821       whitespace = true;
1822       break;
1823     default:
1824       whitespace = false;
1825     }
1826   }
1827   if (i < 0 or whitespace) return false;
1828   
1829   // Now find the first whitespace character before the trailing symbol.
1830   bool nonwhitespace = true;
1831   for (; i >= 0 and nonwhitespace; i--)
1832   {
1833     switch (expr[i])
1834     {
1835     case ' ': case '\t': case '\r': case '\n':
1836       nonwhitespace = false;
1837       break;
1838     default:
1839       nonwhitespace = true;
1840     }
1841   }
1842   if (i < 0 or nonwhitespace) return false;
1843   
1844   // Extract the last symbols and check if it is a valid operator.
1845   TString s = expr;
1846   s.Remove(0, i+2);
1847   if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1848       s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1849       s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or
1850       s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or
1851       s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or
1852       s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or
1853       s == "%" or s == ">" or s == "<" or s == ">=" or s == "<="
1854      )
1855   {
1856     expr.Remove(i+1);
1857     op = s;
1858     return true;
1859   }
1860   
1861   return false;
1862 }
1863
1864
1865 bool AliHLTGlobalTriggerComponent::FillSoftwareTrigger()
1866 {
1867   // Fills the fSoftwareTrigger structure.
1868   
1869   if (fCDH == NULL) return false;
1870   UChar_t l1msg = fCDH->GetL1TriggerMessage();
1871   if ((l1msg & 0x1) == 0x0) return false;  // skip physics events.
1872   // From here on everything must be a software trigger.
1873   if (((l1msg >> 2) & 0xF) == 0xE)
1874   {
1875     fSoftwareTrigger.Name("START_OF_DATA");
1876     fSoftwareTrigger.Description("Generated internal start of data trigger.");
1877   }
1878   else if (((l1msg >> 2) & 0xF) == 0xF)
1879   {
1880     fSoftwareTrigger.Name("END_OF_DATA");
1881     fSoftwareTrigger.Description("Generated internal end of data trigger.");
1882   }
1883   else if (((l1msg >> 6) & 0x1) == 0x1)
1884   {
1885     fSoftwareTrigger.Name("CALIBRATION");
1886     fSoftwareTrigger.Description("Generated internal calibration trigger.");
1887   }
1888   else
1889   {
1890     fSoftwareTrigger.Name("SOFTWARE");
1891     fSoftwareTrigger.Description("Generated internal software trigger.");
1892   }
1893   UInt_t detectors = fCDH->GetSubDetectors();
1894   fSoftwareTrigger.ReadoutList( AliHLTReadoutList(Int_t(detectors)) );
1895   return true;
1896 }
1897
1898
1899 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
1900 {
1901   // print some statistics
1902   int totalEvents=fTotalEventCounter+offset;
1903   const TArrayL64& counters = pTrigger->GetCounters();
1904   if (pTrigger->CallFailed()) return -EPROTO;
1905   for (int i = 0; i < counters.GetSize(); i++) {
1906     ULong64_t count = counters[i];
1907     float ratio=0;
1908     if (totalEvents>0) ratio=100*(float)count/totalEvents;
1909     HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
1910   }
1911   return 0;
1912 }
1913
1914 int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger, const AliHLTCTPData* pCTPData, const AliHLTComponentTriggerData* trigData)
1915 {
1916   // add trigger decisions for the valid CTP classes
1917   if (!pCTPData || !pTrigger) return 0;
1918
1919   AliHLTUInt64_t triggerMask=pCTPData->Mask();
1920   AliHLTUInt64_t bit0=0x1;
1921   if (!fCTPDecisions) {
1922     try
1923     {
1924       fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
1925     }
1926     catch (const std::bad_alloc&)
1927     {
1928       HLTError("Could not allocate memory for the CTP decisions array.");
1929       return -ENOMEM;
1930     }
1931     if (!fCTPDecisions) return -ENOMEM;
1932
1933     try
1934     {
1935       fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
1936     }
1937     catch (const std::bad_alloc&)
1938     {
1939       HLTError("Could not allocate more memory for the CTP decisions array.");
1940       return -ENOMEM;
1941     }
1942     for (int i=0; i<gkNCTPTriggerClasses; i++) {
1943       const char* name=pCTPData->Name(i);
1944       if (triggerMask&(bit0<<i) && name) {
1945         AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1946         assert(pDecision);
1947         if (!pDecision) {
1948           delete fCTPDecisions;
1949           fCTPDecisions=NULL;
1950           return -ENOENT;
1951         }
1952         pDecision->Name(name);
1953       }
1954     }
1955   }
1956
1957   for (int i=0; i<gkNCTPTriggerClasses; i++) {
1958     const char* name=pCTPData->Name(i);
1959     if ((triggerMask&(bit0<<i))==0 || name==NULL) continue;
1960     AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1961     HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
1962     if (!pDecision) return -ENOENT;
1963
1964     bool result=false;
1965     // 13 March 2010 - Optimisation:
1966     // Dont use the EvaluateCTPTriggerClass method, which uses slow TFormula objects.
1967     AliHLTUInt64_t triggers = 0;
1968     if (trigData) triggers = pCTPData->ActiveTriggers(*trigData);
1969     else triggers = pCTPData->Triggers();
1970     result = (triggers&((AliHLTUInt64_t)0x1<<i)) ? true : false;
1971     //if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
1972     //else result=pCTPData->EvaluateCTPTriggerClass(name);
1973     pDecision->Result(result);
1974     pDecision->TriggerDomain().Clear();
1975     if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
1976     else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
1977
1978     pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
1979     if (pTrigger->CallFailed()) return -EPROTO;
1980   }
1981
1982   return 0;
1983 }