]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
Update master to aliroot
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
index 698b08f25985bd58dd91ec583ce4c6d05c0bb108..da09ba583c2bc643664a8d6cc03f1b3d0acf519d 100644 (file)
@@ -20,7 +20,7 @@
 /// @date   26 Nov 2008
 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
 ///
-/// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
+/// The AliHLTGlobalTriggerComponent class applies the global HLT trigger to all
 /// trigger information produced by components deriving from AliHLTTrigger.
 
 #include "AliHLTGlobalTriggerComponent.h"
 #include "TRegexp.h"
 #include "TClonesArray.h"
 #include "TObjString.h"
-#include "TSystem.h"
+#include "TString.h"
 #include "TInterpreter.h"
 #include "TDatime.h"
 #include "TClass.h"
+#include "TNamed.h"
+#include "TRandom3.h"
 #include <fstream>
 #include <cerrno>
 #include <cassert>
@@ -70,15 +72,23 @@ AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
        fTrigger(NULL),
        fDebugMode(false),
        fRuntimeCompile(true),
-       fSkipCTPCounters(false),
        fDeleteCodeFile(false),
+       fMakeSoftwareTriggers(true),
        fCodeFileName(),
        fClassName(),
        fCTPDecisions(NULL),
        fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
        fBufferSizeMultiplier(1.),
        fIncludePaths(TObjString::Class()),
-       fIncludeFiles(TObjString::Class())
+       fIncludeFiles(TObjString::Class()),
+       fLibStateAtLoad(),
+       fBits(0),
+       fDataEventsOnly(true),
+       fMonitorPeriod(-1),
+       fUniqueID(0),
+       fSoftwareTrigger(true, "SOFTWARE"),
+       fTotalEventCounter(0),
+       fCDH(NULL)
 {
   // Default constructor.
   
@@ -99,6 +109,13 @@ AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
 }
 
 
+void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
+{
+  // Returns the kAliHLTDataTypeGlobalTrigger type as output.
+  list.push_back(kAliHLTDataTypeGlobalTrigger);
+}
+
+
 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
 {
   // Returns the output data size estimate.
@@ -116,10 +133,16 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   fClassName = "";
   fCodeFileName = "";
   fDeleteCodeFile = false;
+  fMakeSoftwareTriggers = true;
   const char* configFileName = NULL;
   const char* codeFileName = NULL;
   fIncludePaths.Clear();
   fIncludeFiles.Clear();
+  SetBit(kIncludeInput);
+  fDataEventsOnly = true;
+  UInt_t randomSeed = 0;
+  bool randomSeedSet = false;
+  fCDH = NULL;
   
   for (int i = 0; i < argc; i++)
   {
@@ -148,7 +171,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
         HLTError("The include path was not specified." );
         return -EINVAL;
       }
-      new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
+      try
+      {
+        new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the fIncludePaths array.");
+        return -ENOMEM;
+      }
       i++;
       continue;
     }
@@ -160,7 +191,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
         HLTError("The include file name was not specified." );
         return -EINVAL;
       }
-      new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
+      try
+      {
+        new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the fIncludeFiles array.");
+        return -ENOMEM;
+      }
       i++;
       continue;
     }
@@ -208,10 +247,114 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
     if (strcmp(argv[i], "-skipctp") == 0)
     {
       HLTInfo("Skipping CTP counters in trigger decision");
-      fSkipCTPCounters=true;
+      SetBit(kSkipCTP);
       continue;
     }
-        
+
+    if (strcmp(argv[i], "-forward-input") == 0)
+    {
+      HLTInfo("Forwarding input objects and trigger decisions");
+      SetBit(kForwardInput);
+      SetBit(kIncludeShort);
+      SetBit(kIncludeInput, false);
+      continue;
+    }
+
+    if (strstr(argv[i], "-include-input") == argv[i])
+    {
+      SetBit(kForwardInput,false);
+      TString param=argv[i];
+      param.ReplaceAll("-include-input", "");
+      if (param.CompareTo("=none")==0) 
+      {
+        HLTInfo("skipping objects and trigger decisions");
+        SetBit(kIncludeShort, false);
+        SetBit(kIncludeInput, false);
+      }
+      else if (param.CompareTo("=short")==0) 
+      {
+        HLTInfo("including short info on objects and trigger decisions");
+        SetBit(kIncludeShort);
+        SetBit(kIncludeInput, false);
+      }
+      else if (param.CompareTo("=both")==0) 
+      {
+        HLTInfo("including input objects, trigger decisions and short info");
+        SetBit(kIncludeShort);
+        SetBit(kIncludeInput);
+      }
+      else if (param.CompareTo("=objects")==0 || param.IsNull())
+      {
+        HLTInfo("including input objects and trigger decisions");
+        SetBit(kIncludeShort, false);
+        SetBit(kIncludeInput);
+      }
+      else
+      {
+        HLTError("unknown parameter '%s' for argument '-include-input'", param.Data());
+      }
+      continue;
+    }
+
+    if (strcmp(argv[i], "-process-all-events") == 0)
+    {
+      fDataEventsOnly = false;
+      continue;
+    }
+
+    if (strstr(argv[i], "-monitoring") == argv[i])
+    {
+      TString param=argv[i];
+      param.ReplaceAll("-monitoring", "");
+      if (param.IsNull()) 
+      {
+       // -monitoring
+       // enable monitoring trigger for all events
+       fMonitorPeriod=0;
+      } else {
+       // -monitoring=n
+       // enable monitoring trigger once every n seconds
+       param.ReplaceAll("=", "");
+       if (param.IsDigit()) {
+         fMonitorPeriod=param.Atoi();
+       } else {
+         HLTError("expecting number as parameter for argument '-monitoring=', got %s, skipping monitoring trigger", param.Data());
+       }
+      }
+      continue;
+    }
+
+    if (strcmp(argv[i], "-dont-make-software-triggers") == 0)
+    {
+      fMakeSoftwareTriggers = false;
+      continue;
+    }
+    if (strcmp(argv[i], "-randomseed") == 0)
+    {
+      if (randomSeedSet)
+      {
+        HLTWarning("The random seed was already specified previously with the option -randomseed."
+                   "Will replace the previous value of %d with the new one.",
+                   randomSeed
+        );
+      }
+      if (argc <= i+1)
+      {
+        HLTError("The number to use as the seed was not specified for the -randomseed option." );
+        return -EINVAL;
+      }
+      TString numstr = argv[i+1];
+      if (not numstr.IsDigit())
+      {
+        HLTError("The number specified in the -randomseed option is not a valid decimal integer." );
+        return -EINVAL;
+      }
+      randomSeed = numstr.Atoi();
+      randomSeedSet = true;
+      i++;
+      continue;
+    }
+    
     HLTError("Unknown option '%s'.", argv[i]);
     return -EINVAL;
   } // for loop
@@ -250,7 +393,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   }
   if (result != 0) return result;
   
-  fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
+  try
+  {
+    fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
+    return -ENOMEM;
+  }
   if (fTrigger == NULL)
   {
     HLTError("Could not create a new instance of '%s'.", fClassName.Data());
@@ -258,6 +409,7 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   }
   
   fTrigger->FillFromMenu(*menu);
+  if (fTrigger->CallFailed()) return -EPROTO;
 
   // setup the CTP accounting in AliHLTComponent
   SetupCTPData();
@@ -266,6 +418,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   SetDescription(menu->DefaultDescription());
   SetTriggerDomain(menu->DefaultTriggerDomain());
   
+  // Initialise the random number generator seed value.
+  // NOTE: The GenerateTrigger method called above will set the fUniqueID value
+  // with a random value based on a GUID that should be unique across the system.
+  // This is then used as the seed to the random number generator if the -randomseed
+  // option is not used.
+  if (not randomSeedSet) randomSeed = fUniqueID;
+  gRandom->SetSeed(randomSeed);
+  
+  fTotalEventCounter = 0;
   return 0;
 }
 
@@ -285,13 +446,14 @@ Int_t AliHLTGlobalTriggerComponent::DoDeinit()
     delete fCTPDecisions;
   }
   fCTPDecisions=NULL;
+  fCDH = NULL;
   
   Int_t result = UnloadTriggerClass(fCodeFileName);
   if (result != 0) return result;
   
   if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
-    fCodeFileName.ReplaceAll(".cxx", "*");
-    TString command="rm "; command+=fCodeFileName;
+    TString command="rm -f ";
+    command+=fCodeFileName + " " + TString(fCodeFileName).ReplaceAll(".cxx", "_cxx.d");
     gSystem->Exec(command);
   }
   fCodeFileName="";
@@ -304,8 +466,17 @@ Int_t AliHLTGlobalTriggerComponent::DoDeinit()
 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
 {
   // Creates a new object instance.
-  
-  return new AliHLTGlobalTriggerComponent;
+  AliHLTComponent* comp = NULL;
+  try
+  {
+    comp = new AliHLTGlobalTriggerComponent;
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for a new instance of AliHLTGlobalTriggerComponent.");
+    return NULL;
+  }
+  return comp;
 }
 
 
@@ -321,21 +492,34 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
 
   AliHLTUInt32_t eventType=0;
   if (!IsDataEvent(&eventType)) {
-    if (eventType==gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant, 0);
-    return 0;
+    if (fDataEventsOnly)
+    {
+      if (eventType == gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant);
+      IgnoreEvent();  // dont generate any trigger decision.
+      return 0;
+    }
+  }
+  
+  fCDH = NULL;  // have to reset this in case ExtractTriggerData fails.
+  int triggerSuccess=ExtractTriggerData(*GetTriggerData(), NULL, NULL, &fCDH, NULL, true);
+  if(triggerSuccess<0){
+    HLTError("Couldn't extract CDH from trigger data: %s", strerror(-triggerSuccess));
+    return -EPROTO;
   }
-
   // Copy the trigger counters in case we need to set them back to their original
   // value because the PushBack method fails with ENOSPC.
   TArrayL64 originalCounters = fTrigger->GetCounters();
+  if (fTrigger->CallFailed()) return -EPROTO;
   
   fTrigger->NewEvent();
+  if (fTrigger->CallFailed()) return -EPROTO;
   
   // Fill in the input data.
   const TObject* obj = GetFirstInputObject();
   while (obj != NULL)
   {
     fTrigger->Add(obj, GetDataType(), GetSpecification());
+    if (fTrigger->CallFailed()) return -EPROTO;
     obj = GetNextInputObject();
   }
 
@@ -344,59 +528,163 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
   if (pCTPData) {
     AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
   }
-
+  
+  bool softwareTriggerIsValid = FillSoftwareTrigger();
+  if (softwareTriggerIsValid)
+  {
+    fTrigger->Add(&fSoftwareTrigger, kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
+  }
+  
   // Calculate the global trigger result and trigger domain, then create and push
   // back the new global trigger decision object.
   TString description;
   AliHLTTriggerDomain triggerDomain;
-  bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
+  bool triggerResult = false;
+  bool matchedItems = fTrigger->CalculateTriggerDecision(triggerResult, triggerDomain, description);
+  if (fTrigger->CallFailed()) return -EPROTO;
   AliHLTGlobalTriggerDecision decision(
       triggerResult,
       // The following will cause the decision to be generated with default values
       // (set in fTriggerDomain and fDescription) if the trigger result is false.
-      (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
-      (triggerResult == true) ? description.Data() : GetDescription()
+      (matchedItems == true) ? triggerDomain : GetTriggerDomain(),
+      (matchedItems == true) ? description.Data() : GetDescription()
     );
 
-  // mask the readout list according to the CTP trigger
-  // if the classes have been initialized (mask non-zero)
-  if (pCTPData && pCTPData->Mask()) {
-    AliHLTEventDDL eventDDL=pCTPData->ReadoutList(*GetTriggerData());
-    AliHLTReadoutList ctpreadout(eventDDL);
-    ctpreadout.Enable(AliHLTReadoutList::kHLT);
-    AliHLTReadoutList maskedList=decision.ReadoutList();
-    maskedList.AndEq(ctpreadout);
-    decision.ReadoutList(maskedList);
-  }
-
-  decision.SetCounters(fTrigger->GetCounters(), GetEventCount()+1);
-  static UInt_t lastTime=0;
-  TDatime time;
-  if (time.Get()-lastTime>5) {
-    lastTime=time.Get();
-    PrintStatistics(fTrigger);
-  }
+  decision.SetUniqueID(fUniqueID);
+  decision.SetCounters(fTrigger->GetCounters(), fTotalEventCounter+1);
+  if (fTrigger->CallFailed()) return -EPROTO;
+  
+  TClonesArray shortInfo(TNamed::Class(), GetNumberOfInputBlocks());
   
-  // Add the input objects used to the global decision.
+  // Add the input objects used to make the global decision.
   obj = GetFirstInputObject();
   while (obj != NULL)
   {
-    if (obj->IsA() == AliHLTTriggerDecision::Class())
+    const AliHLTTriggerDecision* intrig = dynamic_cast<const AliHLTTriggerDecision*>(obj);
+    
+    if (TestBit(kForwardInput)) Forward(obj);
+    
+    if (TestBit(kIncludeInput))
     {
-      decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
+      if (intrig != NULL)
+      {
+         decision.AddTriggerInput(*intrig);
+      }
+      else
+      {
+        // The const_cast should be safe in this case because the list of inputObjects
+        // will be added to the global decision with AddInputObjectRef, which only
+        // modifies the kCanDelete bit and nothing else.
+        // This is necessary since GetFirstInputObject only returns const objects.
+        decision.AddInputObjectRef( const_cast<TObject*>(obj) );
+      }
     }
-    else
+    
+    if (TestBit(kIncludeShort))
     {
-      decision.AddInputObject(obj);
+      int entries = shortInfo.GetEntriesFast();
+      try
+      {
+        new (shortInfo[entries]) TNamed(obj->GetName(), obj->GetTitle());
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the short list of input objects.");
+        return -ENOMEM;
+      }
+      if (intrig != NULL)
+      {
+        shortInfo[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
+        shortInfo[entries]->SetBit(BIT(15), intrig->Result());
+      }
     }
+
     obj = GetNextInputObject();
   }
+  if (TestBit(kIncludeShort)) decision.AddInputObjectRef(&shortInfo);
+  
+  // The const_cast should be safe in this case because AddInputObjectRef just
+  // modifies the kCanDelete bit and nothing else.
+  if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObjectRef(const_cast<AliHLTCTPData*>(CTPData()));
+  
+  if (softwareTriggerIsValid and TestBit(kIncludeInput)) decision.AddTriggerInput(fSoftwareTrigger);
+  
+  static UInt_t lastTime=0;
+  TDatime time;
+  if (time.Get()-lastTime>60)
+  {
+    lastTime=time.Get();
+    PrintStatistics(fTrigger, kHLTLogImportant);
+  }
+  else if (eventType==gkAliEventTypeEndOfRun)
+  {
+    PrintStatistics(fTrigger, kHLTLogImportant);
+  }
+  
+  // add readout filter to event done data
+  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
 
-  if (!fSkipCTPCounters && CTPData()) decision.AddInputObject(CTPData());
+  // add monitoring filter to event done data if enabled by setting
+  // a monitoring period >=0: -1 means off, 0 means for every event
+  // configured by argument '-monitoring[=n]'
+  if (fMonitorPeriod>=0) {
+    static UInt_t lastMonitorEvent=0;
 
-  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
-  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
-  if (TriggerEvent(&decision) == -ENOSPC)
+    AliHLTTriggerDomain monitoringFilter(decision.TriggerDomain());
+    if (decision.Result() &&
+       int(time.Get()-lastMonitorEvent)>fMonitorPeriod) {
+      lastMonitorEvent=time.Get();
+      // add monitoring event command for triggered events
+      CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
+    } else {
+      // empty filter list if events are not triggered
+      // or within the monitoring interval
+      monitoringFilter.Clear();
+    }
+    // add monitoring filter list
+    CreateEventDoneReadoutFilter(monitoringFilter, 4);
+  }
+  
+  // Mask the readout list according to the CTP trigger
+  // if the classes have been initialized (mask non-zero).
+  // If we are dealing with a software trigger on the other hand then
+  // mask with the participating detector list.
+  // In both cases we must make sure that HLT is part of the readout mask.
+  AliHLTReadoutList readoutlist = decision.ReadoutList();
+  AliHLTReadoutList readoutMask;
+  if (CTPData() != NULL and CTPData()->Mask() != 0x0)
+  {
+    readoutMask = CTPData()->ReadoutList(*GetTriggerData());
+    readoutMask.Enable(AliHLTReadoutList::kHLT);
+  }
+  else if (softwareTriggerIsValid)
+  {
+    UInt_t detectors = fCDH.GetSubDetectors();
+    readoutMask = AliHLTReadoutList(Int_t(detectors | AliHLTReadoutList::kHLT));
+  }
+  readoutlist.AndEq(readoutMask);
+  decision.ReadoutList(readoutlist); // override the readout list with the masked one.
+    
+  // Also check whether the final readout list equals a full readout of detectors
+  // irrespective of HLT.
+  // Calculate the difference between the input and output list (xor)
+  // and check if any bits are set (ignoring HLT).
+  AliHLTReadoutList::EDetectorId minDetector = ( readoutlist ^ readoutMask ).GetFirstUsedDetector();
+  // Create the readout list specification word:
+  // Bit 0:    Original Data Present (bit 15 of CDH status & error bit to be set)
+  // Bit 1-31: Reserved for future use
+  AliHLTUInt32_t spec = 0x0;
+  if ( AliHLTReadoutList::kNoDetector == minDetector || AliHLTReadoutList::kHLT == minDetector )  // Any bits set after XOR?
+  {
+    spec |=  (AliHLTUInt32_t) 0x1;
+  }
+  else
+  {
+    spec &= ~((AliHLTUInt32_t) 0x1);
+  }
+  SetReadoutListSpecBits(spec);
+
+  if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -ENOSPC)
   {
     // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
     // returned the "no buffer space" error code. Also remember to set the trigger counters
@@ -405,8 +693,11 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
     fBufferSizeConst += 1024*1024;
     fBufferSizeMultiplier *= 2.;
     fTrigger->SetCounters(originalCounters);
+    if (fTrigger->CallFailed()) return -EPROTO;
     return -ENOSPC;
   }
+  
+  ++fTotalEventCounter;
   return 0;
 }
 
@@ -431,7 +722,16 @@ int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char*
   result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
   if (result != 0) return result;
   
-  AliHLTGlobalTrigger* trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
+  AliHLTGlobalTrigger* trigger = NULL;
+  try
+  {
+    trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
+    return -ENOMEM;
+  }
   if (trigger == NULL)
   {
     HLTError("Could not create a new instance of '%s'.", className.Data());
@@ -439,8 +739,8 @@ int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char*
     UnloadTriggerClass(codeFileName);
     if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
     {
-      codeFileName.ReplaceAll(".cxx", "*");
-      TString command="rm "; command+=codeFileName;
+      TString command="rm -f ";
+      command+=codeFileName + " " + TString(codeFileName).ReplaceAll(".cxx", "_cxx.d");
       gSystem->Exec(command);
     }
     return -EIO;
@@ -454,6 +754,7 @@ int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char*
   
   fTrigger = trigger;
   fTrigger->FillFromMenu(*menu);
+  if (fTrigger->CallFailed()) return -EPROTO;
 
   // Set the default values from the trigger menu.
   SetDescription(menu->DefaultDescription());
@@ -463,8 +764,8 @@ int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char*
   UnloadTriggerClass(fCodeFileName);
   if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
   {
-    fCodeFileName.ReplaceAll(".cxx", "*");
-    TString command="rm "; command+=fCodeFileName;
+    TString command="rm -f ";
+    command+=fCodeFileName + " " + TString(fCodeFileName).ReplaceAll(".cxx", "_cxx.d");
     gSystem->Exec(command);
   }
   fCodeFileName = codeFileName;
@@ -479,26 +780,7 @@ int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const Ali
   // Loads the trigger menu object from the CDB path.
   
   HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
-  if (AliCDBManager::Instance() == NULL)
-  {
-    HLTError("CDB manager object not found.");
-    return -EIO;
-  }
-  AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
-  if (store == NULL)
-  {
-    HLTError("Could not get the the default storage for the CDB.");
-    return -EIO;
-  }
-  Int_t version = store->GetLatestVersion(cdbPath, GetRunNo());
-  Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version);
-  AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion);
-  if (entry == NULL)
-  {
-    HLTError("Could not get the CDB entry for \"%s\".", cdbPath);
-    return -EIO;
-  }
-  TObject* obj = entry->GetObject();
+  TObject* obj = LoadAndExtractOCDBObject(cdbPath);
   if (obj == NULL)
   {
     HLTError("Configuration object for \"%s\" is missing.", cdbPath);
@@ -516,6 +798,38 @@ int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const Ali
 }
 
 
+void AliHLTGlobalTriggerComponent::GenerateFileName(TString& name, TString& filename)
+{
+  // Creates a unique file name for the generated code.
+  
+  TUUID guid = GenerateGUID();
+  union
+  {
+    UChar_t buf[16];
+    UInt_t bufAsInt[4];
+  };
+  guid.GetUUID(buf);
+  fUniqueID = bufAsInt[0];
+  TString guidstr = guid.AsString();
+  // Replace '-' with '_' in string.
+  for (int i = 0; i < guidstr.Length(); ++i)
+  {
+    if (guidstr[i] == '-') guidstr[i] = '_';
+  }
+  name = "AliHLTGlobalTriggerImpl_";
+  name += guidstr;
+  filename = name + ".cxx";
+
+  // For good measure, check that the file names are not used. If they are then regenerate.
+  fstream file(filename.Data(), ios_base::in);
+  if (file.good())
+  {
+    file.close();
+    GenerateFileName(name, filename);
+  }
+}
+
+
 int AliHLTGlobalTriggerComponent::GenerateTrigger(
     const AliHLTTriggerMenu* menu, TString& name, TString& filename,
     const TClonesArray& includePaths, const TClonesArray& includeFiles
@@ -524,21 +838,10 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   // Generates the global trigger class that will implement the specified trigger menu.
   // See header for more details.
   
-  HLTDebug("Generating custom HLT trigger class named %s using trigger menu %p.", ((void*)menu), name.Data());
-  
-  // Create a new UUID and replace the '-' characters with '_' to make it a valid
-  // C++ symbol name.
-  TUUID uuid;
-  TString uuidstr = uuid.AsString();
-  for (Int_t i = 0; i < uuidstr.Length(); i++)
-  {
-    if (uuidstr[i] == '-') uuidstr[i] = '_';
-  }
-  
-  // Create the name of the new class.
-  name = "AliHLTGlobalTriggerImpl_";
-  name += uuidstr;
-  filename = name + ".cxx";
+  GenerateFileName(name, filename);
+  HLTDebug("Generating custom HLT trigger class named %s, in file %s, using trigger menu %p.",
+    name.Data(), filename.Data(), ((void*)menu)
+  );
   
   // Open a text file to write the code and generate the new class.
   fstream code(filename.Data(), ios_base::out | ios_base::trunc);
@@ -554,8 +857,10 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   
   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
   code << "#include <cstring>" << endl;
+  code << "#include \"TClass.h\"" << endl;
   code << "#include \"TString.h\"" << endl;
   code << "#include \"TClonesArray.h\"" << endl;
+  code << "#include \"TRandom3.h\"" << endl;
   code << "#include \"AliHLTLogging.h\"" << endl;
   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
@@ -666,23 +971,49 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
     code << "    HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
   }
   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
+  // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
+  // Have to use the TClass system for extra protection.
+  code << "      if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
+  code << "      if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
   code << "      if (symbol == NULL) continue;" << endl;
   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
   {
     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
-    code << "      if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl;
+    code << "      if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
     if (fDebugMode)
     {
       code << "        HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
-              " symbol->Name(), symbol->BlockType().AsString().Data()));" << endl;
+              " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
     }
     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
     code << "        continue;" << endl;
     code << "      }" << endl;
   }
   code << "    }" << endl;
+  // The following is an optimisation where symbols without any assignment operators
+  // are treated as constant and only initialised in FillFromMenu rather than reseting
+  // them in the NewEvent method.
+  // Note: we putting this initialisation into the constructor can lead to seg faults
+  // under CINT interpretation. Thus we must put it into the FillFromMenu method instead.
+  for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
+  {
+    AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    if (TString(symbol->AssignExpression()) != "") continue;
+    if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) continue;
+    // CINT has problems with the implicit equals operator for complex types, so if
+    // the type has an equals operater we need to write the operator call explicitly.
+    TClass* clas = TClass::GetClass(symbol->Type());
+    if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
+    {
+      code << "    " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
+    }
+    else
+    {
+      code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
+    }
+  }
   if (fDebugMode)
   {
     code << "    HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
@@ -702,8 +1033,12 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
   {
     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    // The following is an optimisation. If the symbol does not have an assignment expression
+    // then it is effectively a constant symbol and can be initialised earlier and only once.
+    // In this case we initialise it in the FillFromMenu method instead.
+    if (TString(symbol->AssignExpression()) == "") continue;
     // CINT has problems with the implicit equals operator for complex types, so if
-    // the type has a equals operater we need to write the operator call explicitly.
+    // the type has an equals operater we need to write the operator call explicitly.
     TClass* clas = TClass::GetClass(symbol->Type());
     if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
     {
@@ -725,7 +1060,25 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   code << "  }" << endl;
   
   // Generate the Add method.
-  code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  bool haveAssignments = false;
+  for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
+  {
+    // First check if we have any symbols with assignment expressions.
+    // This is needed to get rid of the on the fly compilation warning about '_object_' not being used.
+    AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    TString expr = symbol->AssignExpression();
+    if (expr == "") continue; // Skip entries that have no assignment expression.
+    haveAssignments = true;
+    break;
+  }
+  if (haveAssignments or fDebugMode)
+  {
+    code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  }
+  else
+  {
+    code << "  virtual void Add(const TObject* /*_object_*/, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  }
   if (fDebugMode)
   {
     code << "#ifdef __CINT__" << endl;
@@ -765,14 +1118,17 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
              << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
       }
     }
-    code << "    const " << symbol->ObjectClass() << "* " << symbol->Name()
+    // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
+    // Have to use the TClass system for extra protection.
+    code << "    const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
+    code << "    if (_object_->InheritsFrom(" << symbol->ObjectClass() << "::Class())) " << symbol->Name()
          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
          << "*>(_object_);" << endl;
     code << "    if (" << symbol->Name() << "_object_ != NULL && ";
     if (isTrigDecision)
     {
       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
-           << symbol->Name() << "\") == 0 && ";
+           << symbol->RealName() << "\") == 0 && ";
     }
     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
     TString fullname = symbol->Name();
@@ -820,7 +1176,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   // positive results. Again, if no trailing operators are used in the individual
   // merging expressions then the default domain operator is placed between two
   // expression fragments.
-  code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
+  code << "  virtual bool CalculateTriggerDecision(bool& _trigger_result_, AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
   if (fDebugMode)
   {
     code << "#ifdef __CINT__" << endl;
@@ -924,10 +1280,22 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
       code << "    if (" << triggerCondition << ") {" << endl;
       code << "      ++fCounter[" << i << "];" << endl;
       const char* indentation = "";
-      if (item->PreScalar() != 0)
+      // Generate the code to handle the prescalar and scale-down
+      bool havePrescalar = item->PreScalar() != 0;
+      bool haveScaledown = item->ScaleDown() < 1;
+      if (havePrescalar or haveScaledown) 
       {
         indentation = "  ";
-        code << "      if ((fCounter[" << i << "] % " << item->PreScalar() << ") == 1) {" << endl;
+        code << "      if (";
+        if (havePrescalar) code << "(fCounter[" << i << "] % " << item->PreScalar() << ") == 1";
+        if (havePrescalar and haveScaledown) code << " && ";
+        if (haveScaledown)
+        {
+          std::streamsize oldprecision = code.precision(17);
+          code << "gRandom->Rndm() < " << item->ScaleDown();
+          code.precision(oldprecision);
+        }
+        code << ") {" << endl;
       }
       code << indentation << "      _item_result_ = true;" << endl;
       if (fDebugMode)
@@ -935,7 +1303,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
         code << indentation << "      HLTDebug(Form(\"Matched trigger condition " << i
              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
       }
-      if (item->PreScalar() != 0)
+      if (havePrescalar or haveScaledown)
       {
         code << "      }" << endl;
       }
@@ -954,33 +1322,19 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
       }
       else
       {
-        bool switchWillBeEmpty = true;
-        for (size_t k = 0; k < m; k++)
-        {
-          if (conditionOperator[k] == "") continue;
-          switchWillBeEmpty = false;
-        }
-        if (switchWillBeEmpty)
+        if (conditionOperator[m-1] == "")
         {
           code << "    _group_result_ = _group_result_ "
                << menu->DefaultConditionOperator() << " _item_result_;" << endl;
         }
         else
         {
-          code << "    switch(_previous_match_) {" << endl;
-          for (size_t k = 0; k < m; k++)
-          {
-            if (conditionOperator[k] == "") continue;
-            code << "    case " << k << ": _group_result_ = _group_result_ "
-                 << conditionOperator[k] << " _item_result_; break;" << endl;
-          }
-          code << "    default: _group_result_ = _group_result_ "
-               << menu->DefaultConditionOperator() << " _item_result_;" << endl;
-          code << "    }" << endl;
+          code << "    _group_result_ = _group_result_ "
+               << conditionOperator[m-1] << " _item_result_;" << endl;
         }
         code << "    if (_item_result_) {" << endl;
         code << "      if (_trigger_matched_) {" << endl;
-        switchWillBeEmpty = true;
+        bool switchWillBeEmpty = true;
         for (size_t k = 0; k < m; k++)
         {
           if (domainOperator[k] == "") continue;
@@ -1028,11 +1382,33 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
       }
     }
+    bool methodReturnResult = true;
+    if (priorityGroup[n].size() > 0)
+    {
+      const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][0]);
+      methodReturnResult = item->DefaultResult();
+    }
+    // Check to see if the items of the group all have the same default result.
+    // If not then warn the user since only the first item's value will be used.
+    for (size_t m = 1; m < priorityGroup[n].size(); m++)
+    {
+      const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][m]);
+      if (item->DefaultResult() != methodReturnResult)
+      {
+        HLTWarning("Found items with different default results set for priority group %d."
+                   "Will only use the value from the first item.",
+                   item->Priority()
+                  );
+        break;
+      }
+    }
+    code << "      _trigger_result_ = " << (methodReturnResult ? "true" : "false") << ";" << endl;
     code << "      return true;" << endl;
     code << "    }" << endl;
   }
   code << "    _domain_.Clear();" << endl;
   code << "    _description_ = \"\";" << endl;
+  code << "    _trigger_result_ = " << (menu->DefaultResult() ? "true" : "false") << ";" << endl;
   code << "    return false;" << endl;
   code << "  }" << endl;
   
@@ -1084,7 +1460,12 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass(
   HLTDebug("Loading HLT trigger class from file '%s'.", filename);
   
   TString compiler = gSystem->GetBuildCompilerVersion();
-  if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
+  if (fRuntimeCompile 
+      && (compiler.Contains("gcc") 
+         || compiler.Contains("icc") 
+         || compiler.Contains("clang")
+         || compiler.Contains("c++")
+         ))
   {
     TString includePath;
 #if defined(PKGINCLUDEDIR)
@@ -1125,6 +1506,9 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass(
   }
   else
   {
+    // Store the library state to be checked later in UnloadTriggerClass.
+    fLibStateAtLoad = gSystem->GetLibraries();
+    
     // If we do not support the compiler then try interpret the class instead.
     TString cmd = ".L ";
     cmd += filename;
@@ -1151,14 +1535,43 @@ int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
   HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
   
   TString compiler = gSystem->GetBuildCompilerVersion();
-  if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
+  if (fRuntimeCompile)
   {
+    // Generate the library name.
     TString libname = filename;
     Ssiz_t dotpos = libname.Last('.');
     if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
     libname += ".";
     libname += gSystem->GetSoExt();
     
+    // This is a workaround for a problem with unloading shared libraries in ROOT.
+    // If the trigger logic library is loaded before the libAliHLTHOMER.so library
+    // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
+    // call all the subsequent libraries get unloded. This means that any objects created
+    // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
+    // since the executable code has been unloaded.
+    // We need to check if there are any more libraries loaded after the class we
+    // are unloading and in that case don't unload the class.
+    TString libstring = gSystem->GetLibraries();
+    TString token, lastlib;
+    Ssiz_t from = 0;
+    Int_t numOfLibs = 0, posOfLib = -1;
+    while (libstring.Tokenize(token, from, " "))
+    {
+      ++numOfLibs;
+      lastlib = token;
+      if (token.Contains(libname)) posOfLib = numOfLibs;
+    }
+    if (numOfLibs != posOfLib)
+    {
+      HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
+          " library '%s' since another library '%s' was loaded afterwards. Trying to"
+          " unload this library will remove the others and lead to serious memory faults.",
+          libname.Data(), lastlib.Data()
+      ));
+      return 0;
+    }
+    
     char* path = NULL;
     int result = 0;
     if ((path = gSystem->DynamicPathName(libname)) != NULL)
@@ -1170,7 +1583,30 @@ int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
   }
   else
   {
-    // If we do not support the compiler then try interpret the class instead.
+    // This is again a workaround for the problem with unloading files in ROOT.
+    // If the trigger logic class is loaded before the libAliHLTHOMER.so library
+    // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
+    // call all the subsequent libraries get unloded.
+    // We need to check if the list of loaded libraries has changed since the last
+    // call to LoadTriggerClass. If it has then don't unload the class.
+    if (fLibStateAtLoad != gSystem->GetLibraries())
+    {
+      TString libstring = gSystem->GetLibraries();
+      TString token;
+      Ssiz_t from = 0;
+      while (libstring.Tokenize(token, from, " "))
+      {
+        if (not fLibStateAtLoad.Contains(token)) break;
+      }
+      HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
+          " '%s' since another library '%s' was loaded afterwards. Trying to unload"
+          " this file will remove the other library and lead to serious memory faults.",
+          filename, token.Data()
+      ));
+      return 0;
+    }
+  
+    // If we did not compile the trigger logic then remove the interpreted class.
     TString cmd = ".U ";
     cmd += filename;
     Int_t errorcode = TInterpreter::kNoError;
@@ -1204,12 +1640,33 @@ int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArra
 }
 
 
+namespace
+{
+  /**
+   * Helper routine to compare two trigger menu symbols to see if b is a subset of a.
+   * \returns true if b is a subset of a or they are unrelated.
+   */
+  bool AliHLTCheckForContainment(const AliHLTTriggerMenuSymbol* a, const AliHLTTriggerMenuSymbol* b)
+  {
+    TString bstr = b->Name();
+    return bstr.Contains(a->Name());
+  }
+
+} // end of namespace
+
+
 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
 {
   // Builds the list of symbols to use in the custom global trigger menu
   // implementation class.
   // See header for more details.
   
+  // Note: when we build the symbol list we must use the symbol name as returned
+  // by the Name() method and not the RealName() method when using FindSymbol.
+  // This is so that we avoid problems with the generated code not compiling
+  // because names like "abc-xyz" and "abc_xyz" are synonymous.
+  // Name() returns the converted C++ symbol name as used in the generated code.
+  
   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
   {
     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
@@ -1218,11 +1675,21 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu,
       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
       return -EIO;
     }
-    new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
+    try
+    {
+      new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate more memory for the symbols list when adding a trigger menu symbol.");
+      return -ENOMEM;
+    }
   }
+  Int_t initialEntryCount = list.GetEntriesFast();
   
-  TRegexp exp("[_a-zA-Z][-_a-zA-Z0-9]*");
-  TRegexp hexexp("x[a-fA-F0-9]+");
+  // Note: the \\. must not be the first element in the character class, otherwise
+  // it is interpreted as an "any character" dot symbol.
+  TRegexp exp("[_a-zA-Z][-\\._a-zA-Z0-9]*");
   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
   {
     const AliHLTTriggerMenuItem* item = menu->Item(i);
@@ -1264,21 +1731,76 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu,
         // Ignore iso646.h and other keywords.
         continue;
       }
+      
+      // We need to handle the special case where the symbol contains a dot.
+      // In C++ this is a dereferencing operator. So we need to check if the
+      // current symbol we are handling starts with the same string as any of
+      // the existing symbols defined manually in the symbols table.
+      // If we do find such a case then revert to treating the dot as an operator
+      // rather than part of the symbol name. i.e. skip adding the automatic symbol.
+      bool dereferencedSymbol = false;
+      for (int j = 0; j < initialEntryCount; j++)
+      {
+        const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(j) );
+        if (symbol == NULL) continue;
+        TString symstr = symbol->Name();
+        symstr += ".";
+        if (s.BeginsWith(symstr))
+        {
+          dereferencedSymbol = true;
+          break;
+        }
+      }
+      if (dereferencedSymbol) continue;
 
-      if (FindSymbol(s.Data(), list) == -1)
+      // Need to create the symbols first and check if its name is in the list
+      // before actually adding it to the symbols list.
+      AliHLTTriggerMenuSymbol newSymbol;
+      newSymbol.Name(s.Data());
+      newSymbol.Type("bool");
+      newSymbol.ObjectClass("AliHLTTriggerDecision");
+      newSymbol.AssignExpression("this->Result()");
+      newSymbol.DefaultValue("false");
+      if (FindSymbol(newSymbol.Name(), list) == -1)
       {
-        AliHLTTriggerMenuSymbol newSymbol;
-        newSymbol.Name(s.Data());
-        newSymbol.Type("bool");
-        newSymbol.ObjectClass("AliHLTTriggerDecision");
-        newSymbol.AssignExpression("this->Result()");
-        newSymbol.DefaultValue("false");
-        new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
+        try
+        {
+          new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
+        }
+        catch (const std::bad_alloc&)
+        {
+          HLTError("Could not allocate more memory for the symbols list when adding a trigger name symbol.");
+          return -ENOMEM;
+        }
       }
     }
     while (start < str.Length());
   }
   
+  // This last part is necessary to make sure that symbols are replaced in the
+  // trigger condition and domain merging expressions in a greedy manner.
+  // I.e. we need to make sure that if one symbol's string representation is
+  // contained inside another (string subset) that the longer symbol name is
+  // always first in the symbols list.
+  // This will work because the symbol table is traversed from first to last
+  // element and TString::ReplaceAll is used to replace the substrings inside
+  // the AliHLTGlobalTriggerComponent::GenerateTrigger method.
+  std::vector<AliHLTTriggerMenuSymbol*> orderedList;
+  for (Int_t i = 0; i < list.GetEntriesFast(); i++)
+  {
+    orderedList.push_back( static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i)) );
+  }
+  std::sort(orderedList.begin(), orderedList.end(), AliHLTCheckForContainment);
+  //std::sort(orderedList.begin(), orderedList.end());
+  // Now swap values around according to the orderedList.
+  for (Int_t i = 0; i < list.GetEntriesFast(); i++)
+  {
+    AliHLTTriggerMenuSymbol* target = static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i));
+    AliHLTTriggerMenuSymbol tmp = *target;
+    *target = *orderedList[i];
+    *orderedList[i] = tmp;
+  }
+  
   return 0;
 }
 
@@ -1339,12 +1861,47 @@ bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
 }
 
 
+bool AliHLTGlobalTriggerComponent::FillSoftwareTrigger()
+{
+  // Fills the fSoftwareTrigger structure.
+  
+  UChar_t l1msg = fCDH.GetL1TriggerMessage();
+  if ((l1msg & 0x1) == 0x0) return false;  // skip physics events.
+  // From here on everything must be a software trigger.
+  if (((l1msg >> 2) & 0xF) == 0xE)
+  {
+    fSoftwareTrigger.Name("START_OF_DATA");
+    fSoftwareTrigger.Description("Generated internal start of data trigger.");
+  }
+  else if (((l1msg >> 2) & 0xF) == 0xF)
+  {
+    fSoftwareTrigger.Name("END_OF_DATA");
+    fSoftwareTrigger.Description("Generated internal end of data trigger.");
+  }
+  else if (((l1msg >> 6) & 0x1) == 0x1)
+  {
+    fSoftwareTrigger.Name("CALIBRATION");
+    fSoftwareTrigger.Description("Generated internal calibration trigger.");
+  }
+  else
+  {
+    fSoftwareTrigger.Name("SOFTWARE");
+    fSoftwareTrigger.Description("Generated internal software trigger.");
+  }
+  UInt_t detectors = fCDH.GetSubDetectors();
+  fSoftwareTrigger.ReadoutList( AliHLTReadoutList(Int_t(detectors)) );
+  return true;
+}
+
+
 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
 {
   // print some statistics
-  int totalEvents=GetEventCount()+offset;
-  for (int i=0; i<pTrigger->GetCounters().GetSize(); i++) {
-    ULong64_t count=pTrigger->GetCounters()[i];
+  int totalEvents=fTotalEventCounter+offset;
+  const TArrayL64& counters = pTrigger->GetCounters();
+  if (pTrigger->CallFailed()) return -EPROTO;
+  for (int i = 0; i < counters.GetSize(); i++) {
+    ULong64_t count = counters[i];
     float ratio=0;
     if (totalEvents>0) ratio=100*(float)count/totalEvents;
     HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
@@ -1357,16 +1914,32 @@ int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger,
   // add trigger decisions for the valid CTP classes
   if (!pCTPData || !pTrigger) return 0;
 
-  AliHLTUInt64_t triggerMask=pCTPData->Mask();
-  AliHLTUInt64_t bit0=0x1;
+  AliHLTTriggerMask_t triggerMask=pCTPData->Mask();
+  AliHLTTriggerMask_t bit0(0x1);
   if (!fCTPDecisions) {
-    fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
+    try
+    {
+      fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate memory for the CTP decisions array.");
+      return -ENOMEM;
+    }
     if (!fCTPDecisions) return -ENOMEM;
 
-    fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
+    try
+    {
+      fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate more memory for the CTP decisions array.");
+      return -ENOMEM;
+    }
     for (int i=0; i<gkNCTPTriggerClasses; i++) {
       const char* name=pCTPData->Name(i);
-      if (triggerMask&(bit0<<i) && name) {
+      if ( (triggerMask&(bit0<<i)).any() && name) {
        AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
        assert(pDecision);
        if (!pDecision) {
@@ -1381,20 +1954,27 @@ int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger,
 
   for (int i=0; i<gkNCTPTriggerClasses; i++) {
     const char* name=pCTPData->Name(i);
-    if ((triggerMask&(bit0<<i))==0 || name==NULL) continue;
+    if ((triggerMask&(bit0<<i)).none() || name==NULL) continue;
     AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
     HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
     if (!pDecision) return -ENOENT;
 
     bool result=false;
-    if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
-    else result=pCTPData->EvaluateCTPTriggerClass(name);
+    // 13 March 2010 - Optimisation:
+    // Dont use the EvaluateCTPTriggerClass method, which uses slow TFormula objects.
+    AliHLTTriggerMask_t triggers = 0;
+    if (trigData) triggers = pCTPData->ActiveTriggers(*trigData);
+    else triggers = pCTPData->Triggers();
+    result = (triggers&(bit0<<i)).any() ? true : false;
+    //if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
+    //else result=pCTPData->EvaluateCTPTriggerClass(name);
     pDecision->Result(result);
     pDecision->TriggerDomain().Clear();
     if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
     else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
 
     pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
+    if (pTrigger->CallFailed()) return -EPROTO;
   }
 
   return 0;