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