// $Id: $ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * * * * Primary Authors: Artur Szostak * * for The ALICE HLT Project. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /// @file AliHLTGlobalTriggerWrapper.cxx /// @author Artur Szostak /// @date 28 Oct 2009 /// @brief Implementation of the AliHLTGlobalTriggerWrapper interface class. /// /// The AliHLTGlobalTriggerWrapper class is used to interface with an interpreted /// class deriving from AliHLTGlobalTrigger. This is used when the global trigger /// component is using CINT to interpret the trigger logic. The wrapper is necessary /// to be able to call interpreted code from compiled code. #include "AliHLTGlobalTriggerWrapper.h" #include "TArrayL64.h" #include "TClass.h" #include "TInterpreter.h" #include "TCint.h" ClassImp(AliHLTGlobalTriggerWrapper) namespace { /// Variable to store the error message if an error occured in CINT when interpreting code. TString gCINTErrorMessage = ""; /** * This routine is the callback for the CINT interpreter when it finds a syntax error * in the source code generated by the AliHLTGlobalTriggerComponent class. */ void AliHLTOnErrorInCINT(char* message) { gCINTErrorMessage += message; } } // end of namespace AliHLTGlobalTriggerWrapper::AliHLTGlobalTriggerWrapper(const char* classname) : AliHLTGlobalTrigger(), AliHLTLogging(), fClass(NULL), fObject(NULL), fFillFromMenuCall(), fNewEventCall(), fAddCall(), fCalculateTriggerDecisionCall(), fGetCountersCall(), fSetCountersCall(), fCallFailed(false) { // The default constructor. fClass = TClass::GetClass(classname); if (fClass == NULL) { HLTError("Could not find class information for '%s'.", classname); return; } fFillFromMenuCall.InitWithPrototype(fClass, "FillFromMenu", "const AliHLTTriggerMenu&"); if (not fFillFromMenuCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method FillFromMenu.", classname); return; } fNewEventCall.InitWithPrototype(fClass, "NewEvent", " "); // Must have single whitespace in last parameter or we get a segfault in G__interpret_func. if (not fNewEventCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method NewEvent.", classname); return; } fAddCall.InitWithPrototype(fClass, "Add", "const TObject*, const AliHLTComponentDataType&, AliHLTUInt32_t"); if (not fAddCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method Add.", classname); return; } fCalculateTriggerDecisionCall.InitWithPrototype(fClass, "CalculateTriggerDecision", "bool&, AliHLTTriggerDomain&, TString&"); if (not fCalculateTriggerDecisionCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method CalculateTriggerDecision.", classname); return; } fGetCountersCall.InitWithPrototype(fClass, "GetCounters", " "); // Must have single whitespace in last parameter or we get a segfault in G__interpret_func. if (not fGetCountersCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method GetCounters.", classname); return; } fSetCountersCall.InitWithPrototype(fClass, "SetCounters", "TArrayL64&"); if (not fSetCountersCall.IsValid()) { HLTError("Could not initialise method call object for class '%s' and method SetCounters.", classname); return; } fObject = fClass->New(); if (fObject == NULL) { HLTError("Could not create a new object of type '%s'.", classname); } // The following is a workaround for casting void* to void (*)(), i.e. a pointer to object to // a pointer to function. Unfortunately the G__set_errmsgcallback routine interface is defined // using a pointer to object so this workaround is necessary. // We check that the two types are the same size. If they are not then such an operation is // unsafe on the platform on which we are running and will not be performed. union { void* fPtr; void (*fFuncPtr)(char*); }; fFuncPtr = AliHLTOnErrorInCINT; if (sizeof(fPtr) == sizeof(fFuncPtr)) { gInterpreter->SetErrmsgcallback(fPtr); } else { HLTWarning("On this platform a pointer to function and pointer to object are different sizes." " For this reason we cannot use the G__set_errmsgcallback CINT API call in a safe way so all" " error messages generated by CINT will not be captured or logged in the HLT system." ); } } AliHLTGlobalTriggerWrapper::~AliHLTGlobalTriggerWrapper() { // Default destructor. fClass->Destructor(fObject); G__set_errmsgcallback(NULL); } void AliHLTGlobalTriggerWrapper::FillFromMenu(const AliHLTTriggerMenu& menu) { // Fills internal values from the trigger menu. fCallFailed = false; struct Params { const void* fMenu; } params; params.fMenu = &menu; fFillFromMenuCall.SetParamPtrs(¶ms, 1); gCINTErrorMessage = ""; fFillFromMenuCall.Execute(fObject); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); } } void AliHLTGlobalTriggerWrapper::NewEvent() { // Clears the internal buffers for a new event. fCallFailed = false; gCINTErrorMessage = ""; fNewEventCall.Execute(fObject); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); } } void AliHLTGlobalTriggerWrapper::Add( const TObject* object, const AliHLTComponentDataType& type, AliHLTUInt32_t spec ) { // Adds parameters from the object to the internal buffers and variables. fCallFailed = false; struct Params { const void* fObj; const void* fType; long fSpec; } params; params.fObj = object; params.fType = &type; params.fSpec = spec; fAddCall.SetParamPtrs(¶ms, 3); gCINTErrorMessage = ""; fAddCall.Execute(fObject); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); } } bool AliHLTGlobalTriggerWrapper::CalculateTriggerDecision(bool& triggerResult, AliHLTTriggerDomain& domain, TString& description) { // Calculates the global trigger decision. fCallFailed = false; struct Params { const void* fResult; const void* fDomain; const void* fDesc; } params; params.fResult = &triggerResult; params.fDomain = &domain; params.fDesc = &description; fCalculateTriggerDecisionCall.SetParamPtrs(¶ms, 3); Long_t retval; gCINTErrorMessage = ""; fCalculateTriggerDecisionCall.Execute(fObject, retval); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); return false; } return bool(retval); } const TArrayL64& AliHLTGlobalTriggerWrapper::GetCounters() const { // Returns the internal counter array. Long_t retval = 0x0; gCINTErrorMessage = ""; fGetCountersCall.Execute(fObject, retval); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); } static const TArrayL64 emptyArray; const TArrayL64* ptr = &emptyArray; // Make sure we do not return a NULL pointer. if (retval != 0x0) ptr = reinterpret_cast(retval); return *ptr; } void AliHLTGlobalTriggerWrapper::SetCounters(const TArrayL64& counters) { // Fills the internal counter array with new values. fCallFailed = false; struct Params { const void* fCounters; } params; params.fCounters = &counters; fSetCountersCall.SetParamPtrs(¶ms, 1); gCINTErrorMessage = ""; fSetCountersCall.Execute(fObject); if (gCINTErrorMessage != "") { fCallFailed = true; HLTError(gCINTErrorMessage.Data()); HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); } } bool AliHLTGlobalTriggerWrapper::IsValid() const { // Checks if the wrapper class was initialised correctly. return fClass != NULL and fObject != NULL and fFillFromMenuCall.IsValid() and fNewEventCall.IsValid() and fAddCall.IsValid() and fCalculateTriggerDecisionCall.IsValid(); }