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