]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/BASE/AliHLTOUT.cxx
adding helper method for getting full block descriptor at once, updating documentation
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTOUT.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /// @file   AliHLTOUT.cxx
20 /// @author Matthias Richter
21 /// @date   
22 /// @brief  The control class for HLTOUT data.
23 ///
24
25 #include <cerrno>
26 #include <cassert>
27 #include "AliHLTOUT.h"
28 #include "AliHLTMessage.h"
29 #include "AliHLTMisc.h"
30 #include "TSystem.h"
31 #include "TClass.h"
32 #include "TROOT.h"
33 #include <sstream>
34 #include <iomanip>
35 using namespace std;
36
37 /** ROOT macro for the implementation of ROOT specific class methods */
38 ClassImp(AliHLTOUT)
39
40 AliHLTOUT::AliHLTOUT()
41   :
42   fSearchDataType(kAliHLTVoidDataType),
43   fSearchSpecification(kAliHLTVoidDataSpec),
44   fSearchHandlerType(AliHLTModuleAgent::kUnknownOutput),
45   fFlags(kSkipProcessed),
46   fBlockDescList(),
47   fCurrent(0),
48   fpBuffer(NULL),
49   fDataHandlers(),
50   fbVerbose(false),
51   fLog()
52   , fpDataObject(NULL)
53   , fpObjectBuffer(NULL)
54   , fObjectBufferSize(0)
55   , fCurrentEventId(kAliHLTVoidEventID)
56 {
57   // constructor
58   // 
59   // The control class for HLTOUT data
60   // see header file for class documentation
61   // author Matthias Richter
62 }
63
64 AliHLTOUT::~AliHLTOUT()
65 {
66   // destructor
67   if (CheckStatusFlag(kIsSubCollection)) {
68     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "~AliHLTOUT" , __FILE__ , __LINE__ , "severe internal error: collection has not been released, potential crash due to invalid pointer");
69   }
70
71   if (fpDataObject) {
72     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "data object has not been released, potential memory leak");
73   }
74   fpDataObject=NULL;
75 }
76 AliHLTOUT* AliHLTOUT::fgGlobalInstance=NULL;
77
78 int AliHLTOUT::Init()
79 {
80   // see header file for class documentation
81   int iResult=0;
82
83   // ignore if already initialized
84   if (fBlockDescList.size()>0) {
85     return 0;
86   }
87
88   SetStatusFlag(kCollecting);
89   if ((iResult=GenerateIndex())>=0) {
90     if ((iResult=InitHandlers())>=0) {
91     }
92   }
93   ClearStatusFlag(kCollecting);
94   return iResult;
95 }
96
97 int AliHLTOUT::GetNofDataBlocks()
98 {
99   // get number of data blocks
100   return fBlockDescList.size();
101 }
102
103 int AliHLTOUT::SelectFirstDataBlock(AliHLTComponentDataType dt, AliHLTUInt32_t spec,
104                                     AliHLTModuleAgent::AliHLTOUTHandlerType handlerType,
105                                     bool skipProcessed)
106 {
107   // select the first data block according to data type, specification and
108   // handler type
109   fCurrent=0;
110   fSearchDataType=dt;
111   fSearchSpecification=spec;
112   fSearchHandlerType=handlerType;
113   if (skipProcessed) SetStatusFlag(kSkipProcessed);
114   else ClearStatusFlag(kSkipProcessed);
115   return FindAndSelectDataBlock();
116 }
117
118 int AliHLTOUT::SelectNextDataBlock()
119 {
120   // select next data block according to selection criteria specified
121   // for SelectFirstDataBlock
122   if (fCurrent>=fBlockDescList.size()) return -ENOENT;
123   fCurrent++;
124   return FindAndSelectDataBlock();
125 }
126
127 int AliHLTOUT::FindAndSelectDataBlock()
128 {
129   // Select data block according to data type and specification, internal function
130   // invoked by SelectFirstDataBlock/SelectNextDataBlock
131   if (CheckStatusFlag(kLocked)) return -EPERM;
132   int iResult=-ENOENT;
133   while (fCurrent<fBlockDescList.size() && iResult==-ENOENT) {
134     if (fBlockDescList[fCurrent]==fSearchDataType &&
135         (fSearchSpecification==kAliHLTVoidDataSpec || fBlockDescList[fCurrent]==fSearchSpecification) &&
136         (fSearchHandlerType==AliHLTModuleAgent::kUnknownOutput || FindHandlerDesc(fCurrent)==fSearchHandlerType) &&
137         (!CheckStatusFlag(kBlockSelection) || fBlockDescList[fCurrent].IsSelected()) &&
138         (!CheckStatusFlag(kSkipProcessed) || !fBlockDescList[fCurrent].IsProcessed())) {
139       iResult=fBlockDescList[fCurrent].GetIndex();
140       // TODO: check the byte order on the current system and the byte order of the
141       // data block, print warning when mismatch and user did not check
142       //AliHLTOUTByteOrder blockBO=CheckByteOrder();
143       CheckByteOrder();
144       /*
145         if (blockBO!=fByteOrder) {
146         SetStatusFlag(kByteOrderWarning);
147
148         }
149        */
150       ClearStatusFlag(kByteOrderChecked);
151
152       // TODO: check the alignment on the current system and the alignment of the
153       // data block, print warning when mismatch and user did not check
154       ClearStatusFlag(kAlignmentChecked);
155
156       break;
157     }
158     fCurrent++;
159   }
160   return iResult;
161 }
162
163 int AliHLTOUT::GetDataBlockDescription(AliHLTComponentDataType& dt, AliHLTUInt32_t& spec)
164 {
165   // fill data type and specification
166   int iResult=-ENOENT;
167   if (fCurrent<fBlockDescList.size()) {
168     iResult=0;
169     dt=fBlockDescList[fCurrent];
170     spec=fBlockDescList[fCurrent];
171   }
172   return iResult;
173 }
174
175 const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::GetDataBlockHandlerDesc()
176 {
177   // Get handler descriptor of the selected data block.
178   return FindHandlerDesc(fCurrent);
179 }
180
181 AliHLTModuleAgent::AliHLTOUTHandlerType AliHLTOUT::GetDataBlockHandlerType()
182 {
183   // Get handler type of the selected data block.
184   AliHLTModuleAgent::AliHLTOUTHandlerDesc desc=FindHandlerDesc(fCurrent);
185   AliHLTModuleAgent::AliHLTOUTHandlerType type=desc;
186   return type;
187 }
188
189 AliHLTUInt32_t AliHLTOUT::GetDataBlockIndex()
190 {
191   // Get the index of the current data block.
192   if (fCurrent>=fBlockDescList.size()) return AliHLTOUTInvalidIndex;
193   return fBlockDescList[fCurrent].GetIndex();
194 }
195
196 int AliHLTOUT::GetDataBuffer(AliHLTComponentBlockData& desc)
197 {
198   // fill block data descriptor and select the current data buffer
199   // buffer has to be released using ReleaseDataBuffer
200   int iResult=-ENOENT;
201   if (fCurrent<fBlockDescList.size()) {
202     AliHLTComponent::FillBlockData(desc);
203     if ((iResult=fBlockDescList[fCurrent].GetDataBuffer(fpBuffer, desc.fSize))>=0) {
204       desc.fPtr=const_cast<void*>(reinterpret_cast<const void*>(fpBuffer));
205       desc.fDataType=fBlockDescList[fCurrent];
206       desc.fSpecification=fBlockDescList[fCurrent];
207     }
208   }
209   return iResult;
210 }
211
212 int AliHLTOUT::GetDataBuffer(const AliHLTUInt8_t* &pBuffer, AliHLTUInt32_t& size)
213 {
214   // select and return the current data buffer
215   // buffer has to be released using ReleaseDataBuffer
216   int iResult=-ENOENT;
217   pBuffer=NULL;
218   size=0;
219   if (fCurrent<fBlockDescList.size()) {
220     if ((iResult=fBlockDescList[fCurrent].GetDataBuffer(fpBuffer, size))>=0) {
221       pBuffer=fpBuffer;
222     }
223   }
224   return iResult;  
225 }
226
227 int AliHLTOUT::ReleaseDataBuffer(const AliHLTUInt8_t* pBuffer)
228 {
229   // release data buffer, previously returned by GetDataBuffer
230   int iResult=0;
231   if (pBuffer==fpBuffer) {
232     fpBuffer=NULL;
233   } else {
234     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "ReleaseDataBuffer" , __FILE__ , __LINE__ , "buffer %p does not match the provided one %p", pBuffer, fpBuffer);
235   }
236   return iResult;  
237 }
238
239 AliHLTModuleAgent* AliHLTOUT::GetAgent()
240 {
241   // get module agent of the selected data block
242   AliHLTModuleAgent* pAgent=NULL;
243   pAgent=FindHandlerDesc(fCurrent);
244   return pAgent;
245 }
246
247 AliHLTOUTHandler* AliHLTOUT::GetHandler()
248 {
249   // get HLTOUT handler of the selected data block
250   AliHLTOUTHandler* pHandler=NULL;
251   pHandler=FindHandlerDesc(fCurrent);
252   return pHandler;
253 }
254
255 int AliHLTOUT::WriteESD(const AliHLTUInt8_t* /*pBuffer*/, AliHLTUInt32_t /*size*/, AliHLTComponentDataType /*dt*/, AliESDEvent* /*tgtesd*/) const
256 {
257   // default function, child must overload
258   fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "WriteESD" , __FILE__ , __LINE__ , "method not implemented in base class");
259   return -ENOSYS;
260 }
261
262 int AliHLTOUT::AddBlockDescriptor(const AliHLTOUTBlockDescriptor desc)
263 {
264   // add new block descriptor
265   if (!CheckStatusFlag(kCollecting)) return -EPERM;
266   int iResult=0;
267   fBlockDescList.push_back(desc);
268   return iResult;  
269 }
270
271 AliHLTOUT::AliHLTOUTByteOrder AliHLTOUT::CheckByteOrder()
272 {
273   // check the byte order of the current data block
274   // NOTE: this functionality has not been tested and development was hardly finished
275   if (fCurrent<fBlockDescList.size()) {
276     SetStatusFlag(kByteOrderChecked);
277     AliHLTOUT::AliHLTOUTByteOrder order=CheckBlockByteOrder(fBlockDescList[fCurrent].GetIndex());
278     return order;
279   }
280   return kInvalidByteOrder;
281 }
282
283 int AliHLTOUT::CheckAlignment(AliHLTOUT::AliHLTOUTDataType type)
284 {
285   // check alignment of the current data block
286   // NOTE: this functionality has not been tested and development was hardly finished
287   if (fCurrent<fBlockDescList.size()) {
288     SetStatusFlag(kAlignmentChecked);
289     int alignment=CheckBlockAlignment(fBlockDescList[fCurrent].GetIndex(), type);
290     return alignment;
291   }
292   return -ENOENT;
293 }
294
295 int AliHLTOUT::InitHandlers()
296 {
297   // init handlers for all registered blocks
298   int iResult=0;
299   AliHLTOUTIndexList remnants;
300   int iCount=0;
301   for (int havedata=SelectFirstDataBlock(kAliHLTAnyDataType, kAliHLTVoidDataSpec); havedata>=0; havedata=SelectNextDataBlock()) {
302     iCount++;
303     remnants.push_back(GetDataBlockIndex());
304     AliHLTComponentDataType dt=kAliHLTVoidDataType;
305     AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
306     if (GetDataBlockDescription(dt, spec)<0) break;
307     bool bHaveHandler=false;
308     for (AliHLTModuleAgent* pAgent=AliHLTModuleAgent::GetFirstAgent(); pAgent && iResult>=0; pAgent=AliHLTModuleAgent::GetNextAgent()) {
309       AliHLTModuleAgent::AliHLTOUTHandlerDesc handlerDesc;
310       if (pAgent->GetHandlerDescription(dt, spec, handlerDesc)>0) {
311         AliHLTOUTHandlerListEntry entry(pAgent->GetOutputHandler(dt, spec), handlerDesc, pAgent, GetDataBlockIndex());
312         InsertHandler(fDataHandlers, entry);
313         remnants.pop_back();
314         bHaveHandler=true;
315         if (fbVerbose) {
316           stringstream sout;
317           sout << "adding handler for block " << AliHLTComponent::DataType2Text(dt).c_str()
318                << " 0x" << setfill('0') << setw(8) << hex << spec;
319           cout << sout.str() << endl;
320         }
321         break;
322       }
323     }
324     if (!bHaveHandler && (dt==kAliHLTDataTypeESDObject || dt==kAliHLTDataTypeESDTree)) {
325       // ESDs are handled by the framework
326       remnants.pop_back();
327     }
328   }
329
330   // warning if some of the data blocks are not selected by the kAliHLTAnyDataType
331   // criterion
332   if (GetNofDataBlocks()>iCount) {
333     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "InitHandlers" , __FILE__ , __LINE__ , "incomplete data type in %d out of %d data block(s)", GetNofDataBlocks()-iCount, GetNofDataBlocks());
334   }
335
336   // warning if handler not found
337   if (remnants.size()>0) {
338     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "InitHandlers" , __FILE__ , __LINE__ , "no handlers found for %d data blocks out of %d", remnants.size(), iCount);
339     AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
340     for (AliHLTOUTIndexList::iterator element=remnants.begin();
341          element!=remnants.end() && block!=fBlockDescList.end();
342          element++) {
343       for (int trials=0; trials<2; trials++) {
344         do {
345           // we start searching the index from the current position in the block list
346           if ((*block).GetIndex()==*element) break;
347         } while ((++block)!=fBlockDescList.end());
348         if (block==fBlockDescList.end()) {
349           // rewind and try again
350           block=fBlockDescList.begin();
351         }
352       }
353       assert(block!=fBlockDescList.end());
354     }
355   }
356
357   if (fbVerbose) Print();
358
359   return iResult;
360 }
361
362 int AliHLTOUT::InsertHandler(AliHLTOUTHandlerListEntryVector& list, const AliHLTOUTHandlerListEntry &entry)
363 {
364   // insert handler into list, called from child implementations
365   int iResult=0;
366   AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
367   for (; element!=list.end();
368          element++) {
369     if (entry==(*element)) break;
370   }
371   if (element==list.end()) {
372     list.push_back(entry);
373   } else {
374     element->AddIndex(const_cast<AliHLTOUTHandlerListEntry&>(entry));
375   }
376   return iResult;
377 }
378
379 int AliHLTOUT::FillHandlerList(AliHLTOUTHandlerListEntryVector& list, AliHLTModuleAgent::AliHLTOUTHandlerType handlerType)
380 {
381   // fill a list according to specified handler type
382   int iResult=0;
383   for (iResult=SelectFirstDataBlock(kAliHLTAnyDataType, kAliHLTVoidDataSpec, handlerType);
384        iResult>=0;
385        iResult=SelectNextDataBlock()) {
386     AliHLTComponentDataType dt=kAliHLTVoidDataType;
387     AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
388     GetDataBlockDescription(dt, spec);
389     AliHLTOUTHandler* pHandler=GetHandler();
390     if (!pHandler) {
391       fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "FillHandlerList" , __FILE__ , __LINE__ , 
392                          "missing HLTOUT handler for block of type kChain: agent %s, data type %s, specification %#x, ... skipping data block",
393                          GetAgent()?GetAgent()->GetModuleId():"invalid",
394                          AliHLTComponent::DataType2Text(dt).c_str(), spec);
395     } else {
396       InsertHandler(list, GetDataBlockHandlerDesc());
397     }
398   }
399   // TODO: the return value of SelectFirst/NextDataBlock must be
400   // changed in order to avoid this check
401   if (iResult==-ENOENT) iResult=0;
402
403   return iResult;
404 }
405
406 int AliHLTOUT::RemoveEmptyDuplicateHandlers(AliHLTOUTHandlerListEntryVector& list)
407 {
408   // remove empty handlers from list
409   int iResult=0;
410   AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
411   while (element!=list.end()) {
412     if (element->IsEmpty()) {
413       AliHLTOUTHandler* pHandler=*element;
414       AliHLTModuleAgent* pAgent=*element;
415       AliHLTModuleAgent::AliHLTOUTHandlerDesc desc=*element;
416       if (FindHandler(list, desc)>=0) {
417         element=list.erase(element);
418         if (pAgent) {
419           pAgent->DeleteOutputHandler(pHandler);
420         }
421         // we are already at the next element
422         continue;
423       }
424     }
425     element++;
426   }
427   return iResult;
428 }
429
430 int AliHLTOUT::FindHandler(AliHLTOUTHandlerListEntryVector& list, const AliHLTModuleAgent::AliHLTOUTHandlerDesc desc)
431 {
432   // find handler according to descriptor
433   for (int i=0; i<(int)list.size(); i++) {
434     if (list[i]==desc) return i;
435   }
436   return -ENOENT;
437 }
438
439 int AliHLTOUT::InvalidateBlocks(AliHLTOUTHandlerListEntryVector& list)
440 {
441   // invalidate all handlers in a list
442   for (AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
443          element!=list.end();
444          element++) {
445     element->InvalidateBlocks();
446   }
447   return 0;
448 }
449
450 const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::FindHandlerDesc(AliHLTUInt32_t blockIndex)
451 {
452   // get handler description
453   if (blockIndex<fBlockDescList.size()) {
454     return fBlockDescList[blockIndex].GetHandlerDesc();
455   }
456   return const_cast<AliHLTOUT::AliHLTOUTHandlerListEntry&>(AliHLTOUT::AliHLTOUTHandlerListEntry::fgkVoidHandlerListEntry);
457 }
458
459 AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry()
460   :
461   fpHandler(NULL),
462   fpHandlerDesc(NULL),
463   fpAgent(NULL),
464   fBlocks()
465 {
466   // default constructor
467 }
468
469 AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry(AliHLTOUTHandler* pHandler, 
470                                                                 AliHLTModuleAgent::AliHLTOUTHandlerDesc& handlerDesc,
471                                                                 AliHLTModuleAgent* pAgent,
472                                                                 AliHLTUInt32_t index)
473   :
474   fpHandler(pHandler),
475   fpHandlerDesc(new AliHLTModuleAgent::AliHLTOUTHandlerDesc),
476   fpAgent(pAgent),
477   fBlocks()
478 {
479   // constructor
480   *fpHandlerDesc=handlerDesc;
481   fBlocks.push_back(index);
482 }
483
484 AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry(const AliHLTOUTHandlerListEntry& src)
485   :
486   fpHandler(src.fpHandler),
487   fpHandlerDesc(new AliHLTModuleAgent::AliHLTOUTHandlerDesc),
488   fpAgent(src.fpAgent),
489   fBlocks()
490 {
491   // copy constructor
492   *fpHandlerDesc=*src.fpHandlerDesc;
493   fBlocks.assign(src.fBlocks.begin(), src.fBlocks.end());
494 }
495
496 AliHLTOUT::AliHLTOUTHandlerListEntry::~AliHLTOUTHandlerListEntry()
497 {
498   // destructor
499   if (fpHandlerDesc) delete fpHandlerDesc;
500   fpHandlerDesc=NULL;
501 }
502
503 AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::AliHLTOUTHandlerListEntry::operator=(const AliHLTOUTHandlerListEntry& src)
504 {
505   // assignment operator
506   if (this==&src) return *this;  
507   fpHandler=src.fpHandler;
508   if (src.fpHandlerDesc)
509     *fpHandlerDesc=*src.fpHandlerDesc;
510   fpAgent=src.fpAgent;
511   fBlocks.assign(src.fBlocks.begin(), src.fBlocks.end());
512   return *this;
513 }
514
515 AliHLTUInt32_t AliHLTOUT::AliHLTOUTHandlerListEntry::operator[](int i) const
516 {
517   // access operator
518   return (int)fBlocks.size()>i?fBlocks[i]:AliHLTOUTInvalidIndex;
519 }
520
521 bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTOUTHandlerListEntry& entry) const
522 {
523   // comparison operator
524   if (entry.fpHandler!=fpHandler || fpHandler==NULL) return false;
525   assert(entry.fpAgent==fpAgent);
526   if (entry.fpAgent!=fpAgent) return false;
527   return true;
528 }
529
530 bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTModuleAgent::AliHLTOUTHandlerType handlerType) const
531 {
532   // comparison operator
533   if (!fpHandlerDesc) return false;
534   return *fpHandlerDesc==handlerType;
535 }
536
537 bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTModuleAgent::AliHLTOUTHandlerDesc desc) const
538 {
539   // comparison operator
540   if (!fpHandlerDesc) return false;
541   return *fpHandlerDesc==desc;
542 }
543
544 void AliHLTOUT::AliHLTOUTHandlerListEntry::AddIndex(AliHLTOUT::AliHLTOUTHandlerListEntry &desc)
545 {
546   // add block index, a handler can serve multiple blocks
547   AliHLTOUTIndexList::iterator element;
548   for (element=desc.fBlocks.begin(); element!=desc.fBlocks.end(); element++) {
549     AddIndex(*element);
550   }  
551 }
552
553 void AliHLTOUT::AliHLTOUTHandlerListEntry::AddIndex(AliHLTUInt32_t index)
554 {
555   // add block index, a handler can serve multiple blocks
556   fBlocks.push_back(index);
557 }
558
559 bool AliHLTOUT::AliHLTOUTHandlerListEntry::HasIndex(AliHLTUInt32_t index) const
560 {
561   // check if handler serves the specified block
562   AliHLTOUTIndexList::iterator element;
563   for (unsigned int i=0; i<fBlocks.size(); i++) {
564     if (fBlocks[i]==index) return true;
565   }
566   return false;
567 }
568
569 const AliHLTOUT::AliHLTOUTHandlerListEntry AliHLTOUT::AliHLTOUTHandlerListEntry::fgkVoidHandlerListEntry;
570
571 AliHLTUInt64_t AliHLTOUT::ByteSwap64(AliHLTUInt64_t src)
572 {
573   // swap a 64 bit number
574   return ((src & 0xFFULL) << 56) | 
575     ((src & 0xFF00ULL) << 40) | 
576     ((src & 0xFF0000ULL) << 24) | 
577     ((src & 0xFF000000ULL) << 8) | 
578     ((src & 0xFF00000000ULL) >> 8) | 
579     ((src & 0xFF0000000000ULL) >> 24) | 
580     ((src & 0xFF000000000000ULL) >>  40) | 
581     ((src & 0xFF00000000000000ULL) >> 56);
582 }
583
584 AliHLTUInt32_t AliHLTOUT::ByteSwap32(AliHLTUInt32_t src)
585 {
586   // swap a 32 bit number
587   return ((src & 0xFFULL) << 24) | 
588     ((src & 0xFF00ULL) << 8) | 
589     ((src & 0xFF0000ULL) >> 8) | 
590     ((src & 0xFF000000ULL) >> 24);
591 }
592
593 AliHLTOUT* AliHLTOUT::New(AliRawReader* pRawReader)
594 {
595   // transparently create HLTOUT implementation for AliRawReader
596   AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTRawReader", "libHLTrec.so");
597   if (instance) {
598     instance->SetParam(pRawReader);
599   }
600   return instance;
601 }
602
603 AliHLTOUT* AliHLTOUT::New(TTree* pDigitTree, int event)
604 {
605   // transparently create HLTOUT implementation for digit tree
606   AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTDigitReader", "libHLTrec.so");
607   if (instance) {
608     instance->SetParam(pDigitTree, event);
609   }
610   return instance;
611 }
612
613 AliHLTOUT* AliHLTOUT::New(const char* filename, int event)
614 {
615   // transparently create HLTOUT implementation for raw file
616   AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTDigitReader", "libHLTrec.so");
617   if (instance) {
618     instance->SetParam(filename, event);
619   }
620   return instance;
621 }
622
623 void AliHLTOUT::Delete(AliHLTOUT* pInstance)
624 {
625   // delete the HLTOUT instance
626   // check if the library is still there in order to have the
627   // destructor available
628
629   if (!pInstance) return;
630   if (pInstance==fgGlobalInstance) return;
631
632   TClass* pCl1=TClass::GetClass("AliHLTOUTRawReader");
633   TClass* pCl2=TClass::GetClass("AliHLTOUTDigitReader");
634   if (!pCl1 && !pCl2) {
635     AliHLTLogging log;
636     log.Logging(kHLTLogError, "AliHLTOUT::Delete", "HLTOUT handling", "potential memory leak: libHLTrec library not available, skipping destruction %p", pInstance);    
637     return;
638   }
639
640   delete pInstance;  
641 }
642
643 void AliHLTOUT::SetParam(AliRawReader* /*pRawReader*/)
644 {
645   // see header file for class documentation
646   // default implementation, we should never get here
647   // this function can only be called from the class itsself and
648   // is intended to be used with the New functions. If we get into
649   // the default implementation there is a class mismatch.
650   assert(0);
651   fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
652 }
653
654 void AliHLTOUT::SetParam(TTree* /*pDigitTree*/, int /*event*/)
655 {
656   // see header file for class documentation
657   // default implementation, we should never get here
658   // this function can only be called from the class itsself and
659   // is intended to be used with the New functions. If we get into
660   // the default implementation there is a class mismatch.
661   assert(0);
662   fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
663 }
664
665 void AliHLTOUT::SetParam(const char* /*filename*/, int /*event*/)
666 {
667   // see header file for class documentation
668   // default implementation, we should never get here
669   // this function can only be called from the class itsself and
670   // is intended to be used with the New functions. If we get into
671   // the default implementation there is a class mismatch.
672   assert(0);
673   fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
674 }
675
676 int AliHLTOUT::SelectDataBlock()
677 {
678   // mark the current data block for processing
679   int iResult=0;
680   if (fCurrent>=fBlockDescList.size()) return 0;
681   fBlockDescList[fCurrent].Select(true);
682   EnableBlockSelection();
683   return iResult;
684 }
685
686 int AliHLTOUT::SelectDataBlocks(const AliHLTOUTHandlerListEntry* pHandlerEntry)
687 {
688   // mark all data blocks served by specified handler for processing
689   int iResult=0;
690   if (!pHandlerEntry) return 0;
691
692   AliHLTModuleAgent* pAgent=*pHandlerEntry;
693   AliHLTLogging log;
694   log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "selecting blocks for handler %s", pAgent->GetModuleId());
695   AliHLTOUTBlockDescriptorVector::iterator element;
696   for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
697        block!=fBlockDescList.end();
698        block++) {
699     if (block->GetHandlerDesc()==*pHandlerEntry && pHandlerEntry->HasIndex(block->GetIndex())) {
700       block->Select(true);
701       log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "   select block %s", AliHLTComponent::DataType2Text(*block).c_str());
702     } else {
703       log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "   skip block %s", AliHLTComponent::DataType2Text(*block).c_str());
704       block->Select(false);
705     }
706   }
707   EnableBlockSelection();
708
709   // Matthias 2009-07-03 bugfix: the fCurrent position was not reset at that
710   // place. Also I think the data type and specification must be set in order
711   // to make SelectFirst/NextDataBlock working on the selected collection
712   // of data blocks
713   AliHLTModuleAgent::AliHLTOUTHandlerDesc pHandlerDesc=*pHandlerEntry; 
714   fSearchDataType=pHandlerDesc;
715   fSearchSpecification=kAliHLTVoidDataSpec;
716   fSearchHandlerType=pHandlerDesc;
717   fCurrent=0;
718   
719   return iResult;
720 }
721
722 int AliHLTOUT::EnableBlockSelection()
723 {
724   // enable block selection, in this mode only the blocks marked for
725   // processing can be accessed
726   SetStatusFlag(kBlockSelection);
727   return 0;
728 }
729
730 int AliHLTOUT::DisableBlockSelection()
731 {
732   // disable block selection
733   ClearStatusFlag(kBlockSelection);
734   return 0;
735 }
736
737 int AliHLTOUT::ResetBlockSelection()
738 {
739   // reset the 'selected' flag for all blocks
740   for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
741        block!=fBlockDescList.end();
742        block++) {
743     block->Select(false);
744   }
745   return 0;
746 }
747
748 int AliHLTOUT::MarkDataBlockProcessed()
749 {
750   // mark the current data block as 'processed'
751   int iResult=0;
752   if (fCurrent>=fBlockDescList.size()) return 0;
753   fBlockDescList[fCurrent].MarkProcessed();
754   return iResult;
755 }
756
757 int AliHLTOUT::MarkDataBlocksProcessed(const AliHLTOUTHandlerListEntry* pHandlerDesc)
758 {
759   // mark all data blocks served by handler as processed
760   int iResult=0;
761   if (!pHandlerDesc) return 0;
762
763   AliHLTOUTBlockDescriptorVector::iterator element;
764   for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
765        block!=fBlockDescList.end();
766        block++) {
767     if (block->GetHandlerDesc()==*pHandlerDesc && pHandlerDesc->HasIndex(block->GetIndex()))
768       block->MarkProcessed();
769   }
770   
771   return iResult;
772 }
773
774 int AliHLTOUT::AddSubCollection(AliHLTOUT* pCollection)
775 {
776   // add a sub-collection to the HLTOUT instance
777   // all blocks of the sub-collection are accessed transparently through the master instance
778   int iResult=0;
779   if (!pCollection) return 0;
780
781   SetStatusFlag(kCollecting);  
782   int index=-1;
783   for (index=pCollection->SelectFirstDataBlock();
784        index>=0;
785        index=pCollection->SelectNextDataBlock()) {
786     AliHLTComponentDataType dt=kAliHLTVoidDataType;
787     AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
788     pCollection->GetDataBlockDescription(dt, spec);  
789     AliHLTOUTBlockDescriptor desc(dt, spec, index, pCollection);
790     AddBlockDescriptor(desc);
791     iResult++;
792   }
793   if (iResult>0) {
794     if (CheckStatusFlag(kIsSubCollection)) {
795       fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "AddSubCollection" , __FILE__ , __LINE__ , "HLTOUT object %p has already been added as sub-collection", pCollection);
796     } else {
797       pCollection->SetStatusFlag(kIsSubCollection);
798     }
799   }
800   ClearStatusFlag(kCollecting);  
801
802   return iResult;
803 }
804
805 int AliHLTOUT::ReleaseSubCollection(AliHLTOUT* pCollection)
806 {
807   // release a sub-collection
808   int iResult=0;
809   if (!pCollection) return 0;
810
811   AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
812   while (block!=fBlockDescList.end()) {
813     if ((*block)==pCollection) {
814       block=fBlockDescList.erase(block);
815       continue;
816     }
817     block++;
818   }
819   pCollection->ClearStatusFlag(kIsSubCollection);
820
821   return iResult;
822 }
823
824 int AliHLTOUT::Reset()
825 {
826   // reset HLTOUT instance
827   // clears all blocks and handler descriptions
828   int iResult=0;
829   AliHLTOUTPVector subCollections;
830   AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
831   while (block!=fBlockDescList.end()) {
832     if (!((*block)==this)) {
833       AliHLTOUTPVector::iterator collection=subCollections.begin();
834       for (; collection!=subCollections.end(); collection++)
835         if((*block)==*collection) break;
836       if (collection==subCollections.end())
837         subCollections.push_back(block->GetCollection());
838     }
839     block=fBlockDescList.erase(block);
840   }
841
842   for (AliHLTOUTPVector::iterator collection=subCollections.begin(); 
843        collection!=subCollections.end(); collection++) {
844     (*collection)->Reset();
845     (*collection)->ClearStatusFlag(kIsSubCollection);
846   }
847
848   ResetInput();
849   fCurrentEventId=kAliHLTVoidEventID;
850
851   return iResult;
852 }
853
854 int AliHLTOUT::ResetInput()
855 {
856   // default implementation, nothing to do
857   return 0;
858 }
859
860 const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::AliHLTOUTBlockDescriptor::GetHandlerDesc()
861 {
862   // see header file for class documentation
863   if (fpCollection) {
864     AliHLTOUTHandlerListEntryVector::iterator element=fpCollection->fDataHandlers.begin();
865     while (element!=fpCollection->fDataHandlers.end()) {
866       if (element->HasIndex(GetIndex())) {
867         return *element;
868       }
869       element++;
870     }
871   }
872   return const_cast<AliHLTOUT::AliHLTOUTHandlerListEntry&>(AliHLTOUT::AliHLTOUTHandlerListEntry::fgkVoidHandlerListEntry);
873 }
874
875 TObject* AliHLTOUT::GetDataObject()
876 {
877   // check if the current block encodes a ROOT object and expand it
878   if (fpDataObject) {
879     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "data object has not been released, potential memory leak");
880     ReleaseDataBuffer(fpObjectBuffer);
881   }
882   fpObjectBuffer=NULL;
883   fObjectBufferSize=0;
884   fpDataObject=NULL;
885
886   if (GetDataBuffer(fpObjectBuffer, fObjectBufferSize)>=0) {
887     fpDataObject=AliHLTMessage::Extract(fpObjectBuffer, fObjectBufferSize);
888   } else {
889     fLog.LoggingVarargs(kHLTLogError, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "can not fetch data buffer");    
890   }
891
892   return fpDataObject;
893 }
894
895 int AliHLTOUT::ReleaseDataObject(TObject* pObject)
896 {
897   // release a ROOT object previously expanded from the currentr data block
898   if (!pObject) return -EINVAL;
899   if (pObject!=fpDataObject) {
900     fLog.LoggingVarargs(kHLTLogError, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "attempt to release wrong data object %p, expected %p", pObject, fpDataObject);
901     return -EINVAL;
902   }
903
904   delete fpDataObject;
905   fpDataObject=NULL;
906   ReleaseDataBuffer(fpObjectBuffer);
907   fpObjectBuffer=NULL;
908   fObjectBufferSize=0;
909
910   return 0;
911 }
912
913 void AliHLTOUT::SetEventId(AliHLTUInt64_t id)
914 {
915   // set event id
916   if (fCurrentEventId!=kAliHLTVoidEventID && fCurrentEventId!=id) {
917     fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "SetEventId" , __FILE__ , __LINE__ , "event id was already set to 0x%llx, setting now to 0x%llx", fCurrentEventId, id);
918   }
919   fCurrentEventId=id;
920 }
921
922 void AliHLTOUT::Print(const char* option) const
923 {
924   // print info
925   {
926     for (AliHLTOUTBlockDescriptorVector::const_iterator  i=fBlockDescList.begin();
927          i!=fBlockDescList.end(); i++)
928       i->Print(option);
929   }
930   {
931     for (AliHLTOUTHandlerListEntryVector::const_iterator  i=fDataHandlers.begin();
932          i!=fDataHandlers.end(); i++)
933       i->Print(option);
934   }
935 }
936
937 void AliHLTOUT::AliHLTOUTBlockDescriptor::Print(const char* /*option*/) const
938 {
939   // print info
940   stringstream sout;
941   sout << "AliHLTOUTBlockDescriptor index 0x" << setfill('0') << setw(8) << hex << right << fIndex 
942        << ":   " << AliHLTComponent::DataType2Text(fDataType).c_str()
943        << "  0x" << setfill('0') << setw(8) << hex << fSpecification
944        << "  processed " << dec << fProcessed;
945   cout << sout.str() << endl;
946 }
947
948 void AliHLTOUT::AliHLTOUTHandlerListEntry::Print(const char* /*option*/) const
949 {
950   // print info
951   stringstream sout;
952   AliHLTModuleAgent::AliHLTOUTHandlerType type=AliHLTModuleAgent::kUnknownOutput;
953   AliHLTComponentDataType dt=kAliHLTVoidDataType;
954   if (this->fpHandlerDesc) {
955     type=*(this->fpHandlerDesc);
956     dt=*(this->fpHandlerDesc);
957   }
958   const char* stype="";
959   switch(type) {
960   case AliHLTModuleAgent::kEsd: stype="ESD"; break;
961   case AliHLTModuleAgent::kRawReader: stype="RawReader"; break;
962   case AliHLTModuleAgent::kRawStream: stype="RawStream"; break;
963   case AliHLTModuleAgent::kChain: stype="Chain"; break;
964   case AliHLTModuleAgent::kProprietary: stype="Proprietary"; break;
965   default: stype="unknown";
966   }
967   sout << "HLTOUT handler: "
968        << "  " << type << " (" << stype << ")"
969        << "  " << AliHLTComponent::DataType2Text(dt).c_str();
970   cout << sout.str() << endl;
971 }