ALIROOT-5433 Transition to CDHv3 in HLT
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerWrapper.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   AliHLTGlobalTriggerWrapper.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
20 /// @date   28 Oct 2009
21 /// @brief  Implementation of the AliHLTGlobalTriggerWrapper interface class.
22 ///
23 /// The AliHLTGlobalTriggerWrapper class is used to interface with an interpreted
24 /// class deriving from AliHLTGlobalTrigger. This is used when the global trigger
25 /// component is using CINT to interpret the trigger logic. The wrapper is necessary
26 /// to be able to call interpreted code from compiled code.
27
28 #include "AliHLTGlobalTriggerWrapper.h"
29 #include "TArrayL64.h"
30 #include "TClass.h"
31 #include "TInterpreter.h"
32 #if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0)
33 #include "TCint.h"
34 # define LAST_ERR_LINENO G__lasterror_linenum()
35 #else
36 # define LAST_ERR_LINENO 0
37 #endif
38
39 ClassImp(AliHLTGlobalTriggerWrapper)
40
41
42 namespace
43 {
44   /// Variable to store the error message if an error occured in CINT when interpreting code.
45   TString gCINTErrorMessage = "";
46   
47   /**
48    * This routine is the callback for the CINT interpreter when it finds a syntax error
49    * in the source code generated by the AliHLTGlobalTriggerComponent class.
50    */
51   void AliHLTOnErrorInCINT(char* message)
52   {
53     gCINTErrorMessage += message;
54   }
55
56 } // end of namespace
57
58
59 AliHLTGlobalTriggerWrapper::AliHLTGlobalTriggerWrapper(const char* classname) :
60   AliHLTGlobalTrigger(),
61   AliHLTLogging(),
62   fClass(NULL),
63   fObject(NULL),
64   fFillFromMenuCall(),
65   fNewEventCall(),
66   fAddCall(),
67   fCalculateTriggerDecisionCall(),
68   fGetCountersCall(),
69   fSetCountersCall(),
70   fCallFailed(false)
71 {
72   // The default constructor.
73   
74   fClass = TClass::GetClass(classname);
75   if (fClass == NULL)
76   {
77     HLTError("Could not find class information for '%s'.", classname);
78     return;
79   }
80   fFillFromMenuCall.InitWithPrototype(fClass, "FillFromMenu", "const AliHLTTriggerMenu&");
81   if (not fFillFromMenuCall.IsValid())
82   {
83     HLTError("Could not initialise method call object for class '%s' and method FillFromMenu.", classname);
84     return;
85   }
86   fNewEventCall.InitWithPrototype(fClass, "NewEvent", " ");  // Must have single whitespace in last parameter or we get a segfault in G__interpret_func.
87   if (not fNewEventCall.IsValid())
88   {
89     HLTError("Could not initialise method call object for class '%s' and method NewEvent.", classname);
90     return;
91   }
92   fAddCall.InitWithPrototype(fClass, "Add", "const TObject*, const AliHLTComponentDataType&, AliHLTUInt32_t");
93   if (not fAddCall.IsValid())
94   {
95     HLTError("Could not initialise method call object for class '%s' and method Add.", classname);
96     return;
97   }
98   fCalculateTriggerDecisionCall.InitWithPrototype(fClass, "CalculateTriggerDecision", "bool&, AliHLTTriggerDomain&, TString&");
99   if (not fCalculateTriggerDecisionCall.IsValid())
100   {
101     HLTError("Could not initialise method call object for class '%s' and method CalculateTriggerDecision.", classname);
102     return;
103   }
104   fGetCountersCall.InitWithPrototype(fClass, "GetCounters", " ");  // Must have single whitespace in last parameter or we get a segfault in G__interpret_func.
105   if (not fGetCountersCall.IsValid())
106   {
107     HLTError("Could not initialise method call object for class '%s' and method GetCounters.", classname);
108     return;
109   }
110   fSetCountersCall.InitWithPrototype(fClass, "SetCounters", "TArrayL64&");
111   if (not fSetCountersCall.IsValid())
112   {
113     HLTError("Could not initialise method call object for class '%s' and method SetCounters.", classname);
114     return;
115   }
116   fObject = fClass->New();
117   if (fObject == NULL)
118   {
119     HLTError("Could not create a new object of type '%s'.", classname);
120   }
121   
122   // The following is a workaround for casting void* to void (*)(), i.e. a pointer to object to
123   // a pointer to function. Unfortunately the G__set_errmsgcallback routine interface is defined
124   // using a pointer to object so this workaround is necessary.
125   // We check that the two types are the same size. If they are not then such an operation is
126   // unsafe on the platform on which we are running and will not be performed.
127   union
128   {
129     void* fPtr;
130     void (*fFuncPtr)(char*);
131   };
132   fFuncPtr = AliHLTOnErrorInCINT;
133   if (sizeof(fPtr) == sizeof(fFuncPtr))
134   {
135     gInterpreter->SetErrmsgcallback(fPtr);
136   }
137   else
138   {
139     HLTWarning("On this platform a pointer to function and pointer to object are different sizes."
140       " For this reason we cannot use the G__set_errmsgcallback CINT API call in a safe way so all"
141       " error messages generated by CINT will not be captured or logged in the HLT system."
142     );
143   }
144 }
145
146
147 AliHLTGlobalTriggerWrapper::~AliHLTGlobalTriggerWrapper()
148 {
149   // Default destructor.
150   
151   fClass->Destructor(fObject);
152 #if ROOT_VERSION_CODE < ROOT_VERSION(5,99,0)
153   G__set_errmsgcallback(NULL);
154 #endif
155 }
156
157
158 void AliHLTGlobalTriggerWrapper::FillFromMenu(const AliHLTTriggerMenu& menu)
159 {
160   // Fills internal values from the trigger menu.
161   
162   fCallFailed = false;
163   struct Params
164   {
165     const void* fMenu;
166   } params;
167   params.fMenu = &menu;
168   fFillFromMenuCall.SetParamPtrs(&params, 1);
169   gCINTErrorMessage = "";
170   fFillFromMenuCall.Execute(fObject);
171   if (gCINTErrorMessage != "")
172   {
173     fCallFailed = true;
174     HLTError(gCINTErrorMessage.Data());
175     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
176   }
177 }
178
179
180 void AliHLTGlobalTriggerWrapper::NewEvent()
181 {
182   // Clears the internal buffers for a new event.
183
184   fCallFailed = false;
185   gCINTErrorMessage = "";
186   fNewEventCall.Execute(fObject);
187   if (gCINTErrorMessage != "")
188   {
189     fCallFailed = true;
190     HLTError(gCINTErrorMessage.Data());
191     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
192   }
193 }
194
195
196 void AliHLTGlobalTriggerWrapper::Add(
197       const TObject* object, const AliHLTComponentDataType& type,
198       AliHLTUInt32_t spec
199     )
200 {
201   // Adds parameters from the object to the internal buffers and variables.
202   
203   fCallFailed = false;
204   struct Params
205   {
206     const void* fObj;
207     const void* fType;
208     long fSpec;
209   } params;
210   params.fObj = object;
211   params.fType = &type;
212   params.fSpec = spec;
213   fAddCall.SetParamPtrs(&params, 3);
214   gCINTErrorMessage = "";
215   fAddCall.Execute(fObject);
216   if (gCINTErrorMessage != "")
217   {
218     fCallFailed = true;
219     HLTError(gCINTErrorMessage.Data());
220     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
221   }
222 }
223
224
225 bool AliHLTGlobalTriggerWrapper::CalculateTriggerDecision(bool& triggerResult, AliHLTTriggerDomain& domain, TString& description)
226 {
227   // Calculates the global trigger decision.
228
229   fCallFailed = false;
230   struct Params
231   {
232     const void* fResult;
233     const void* fDomain;
234     const void* fDesc;
235   } params;
236   params.fResult = &triggerResult;
237   params.fDomain = &domain;
238   params.fDesc = &description;
239   fCalculateTriggerDecisionCall.SetParamPtrs(&params, 3);
240   Long_t retval;
241   gCINTErrorMessage = "";
242   fCalculateTriggerDecisionCall.Execute(fObject, retval);
243   if (gCINTErrorMessage != "")
244   {
245     fCallFailed = true;
246     HLTError(gCINTErrorMessage.Data());
247     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
248     return false;
249   }
250   return bool(retval);
251 }
252
253
254 const TArrayL64& AliHLTGlobalTriggerWrapper::GetCounters() const
255 {
256   // Returns the internal counter array.
257
258   Long_t retval = 0x0;
259   gCINTErrorMessage = "";
260   fGetCountersCall.Execute(fObject, retval);
261   if (gCINTErrorMessage != "")
262   {
263     fCallFailed = true;
264     HLTError(gCINTErrorMessage.Data());
265     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
266   }
267   static const TArrayL64 emptyArray;
268   const TArrayL64* ptr = &emptyArray; // Make sure we do not return a NULL pointer.
269   if (retval != 0x0) ptr = reinterpret_cast<const TArrayL64*>(retval);
270   return *ptr;
271 }
272
273
274 void AliHLTGlobalTriggerWrapper::SetCounters(const TArrayL64& counters)
275 {
276   // Fills the internal counter array with new values.
277   
278   fCallFailed = false;
279   struct Params
280   {
281     const void* fCounters;
282   } params;
283   params.fCounters = &counters;
284   fSetCountersCall.SetParamPtrs(&params, 1);
285   gCINTErrorMessage = "";
286   fSetCountersCall.Execute(fObject);
287   if (gCINTErrorMessage != "")
288   {
289     fCallFailed = true;
290     HLTError(gCINTErrorMessage.Data());
291     HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), LAST_ERR_LINENO);
292   }
293 }
294
295
296 bool AliHLTGlobalTriggerWrapper::IsValid() const
297 {
298   // Checks if the wrapper class was initialised correctly.
299   
300   return fClass != NULL and fObject != NULL and fFillFromMenuCall.IsValid()
301     and fNewEventCall.IsValid() and fAddCall.IsValid()
302     and fCalculateTriggerDecisionCall.IsValid();
303 }
304