- setup scripts for running environment added
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTDataBuffer.cxx
1 // $Id$
2
3 /**************************************************************************
4  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
5  *                                                                        *
6  * Authors: Matthias Richter <Matthias.Richter@ift.uib.no>                *
7  *          for The ALICE Off-line 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   AliHLTDataBuffer.cxx
19     @author Matthias Richter
20     @date   
21     @brief  Handling of Data Buffers for HLT components.
22 */
23
24 #if __GNUC__>= 3
25 using namespace std;
26 #endif
27
28 #include "AliHLTDataBuffer.h"
29 #include "AliHLTComponent.h"
30 #include <string>
31 #include "AliHLTSystem.h"
32
33 AliHLTConsumerDescriptor::AliHLTConsumerDescriptor()
34   :
35   fpConsumer(NULL),
36   fSegments()
37 {
38   fSegments.clear();
39 }
40
41 AliHLTConsumerDescriptor::AliHLTConsumerDescriptor(AliHLTComponent* pConsumer)
42   :
43   fpConsumer(pConsumer),
44   fSegments()
45 {
46   fSegments.clear();
47 }
48
49 AliHLTConsumerDescriptor::AliHLTConsumerDescriptor(const AliHLTConsumerDescriptor& desc)
50   :
51   TObject(),
52   AliHLTLogging(),
53   fpConsumer(desc.fpConsumer),
54   fSegments()
55 {
56   // we can simply transfer the pointer to th new object since there are no
57   // release actions in the destructor
58 }
59
60 AliHLTConsumerDescriptor& AliHLTConsumerDescriptor::operator=(const AliHLTConsumerDescriptor& desc)
61
62   // we can simply transfer the pointer to th new object since there are no
63   // release actions in the destructor
64   fpConsumer=desc.fpConsumer;
65   return *this;
66 }
67
68 AliHLTConsumerDescriptor::~AliHLTConsumerDescriptor()
69 {
70   if (fSegments.size()>0) {
71     //HLTWarning("unreleased data segments found");
72   }
73 }
74
75 int AliHLTConsumerDescriptor::SetActiveDataSegment(AliHLTUInt32_t offset, AliHLTUInt32_t size)
76 {
77   int iResult=0;
78   AliHLTDataSegment segment(offset, size);
79   fSegments.push_back(segment);
80   //HLTDebug("set active segment (%d:%d) for consumer %p", offset, size, this);
81   return iResult;
82 }
83
84 int AliHLTConsumerDescriptor::CheckActiveDataSegment(AliHLTUInt32_t offset, AliHLTUInt32_t size)
85 {
86   int iResult=0;
87   if (fSegments.size()>0) {
88     vector<AliHLTDataSegment>::iterator segment=fSegments.begin();
89     while (segment!=fSegments.end()) {
90       if (iResult=((*segment).fSegmentOffset==offset && (*segment).fSegmentSize==size)) {
91         break;
92       }
93       segment++;
94     }
95   } else {
96     //HLTWarning("no data segment active for consumer %p", this);
97     iResult=-ENODATA;
98   }
99   return iResult;
100 }
101
102 int AliHLTConsumerDescriptor::ReleaseActiveDataSegment(AliHLTUInt32_t offset, AliHLTUInt32_t size)
103 {
104   int iResult=0;
105   if (fSegments.size()>0) {
106     vector<AliHLTDataSegment>::iterator segment=fSegments.begin();
107     while (segment!=fSegments.end()) {
108       if (iResult=((*segment).fSegmentOffset==offset && (*segment).fSegmentSize==size)) {
109         fSegments.erase(segment);
110         break;
111       }
112       segment++;
113     }
114     if (iResult=0) {
115       //HLTWarning("no data segment (%d:%d) active for consumer %p", offset, size, this);
116       iResult=-ENOENT;
117     }
118   } else {
119     //HLTWarning("no data segment active for consumer %p", this);
120     iResult=-ENODATA;
121   }
122   return iResult;
123 }
124
125 /** ROOT macro for the implementation of ROOT specific class methods */
126 ClassImp(AliHLTDataBuffer)
127
128 AliHLTDataBuffer::AliHLTDataBuffer()
129   :
130   fSegments(),
131   fConsumers(),
132   fActiveConsumers(),
133   fReleasedConsumers(),
134   fpBuffer(NULL),
135   fFlags(0)
136 {
137   fSegments.empty();
138   fConsumers.empty();
139   fActiveConsumers.empty();
140   fReleasedConsumers.empty();
141   fNofInstances++;
142 }
143
144 AliHLTDataBuffer::AliHLTDataBuffer(const AliHLTDataBuffer&)
145   :
146   TObject(),
147   AliHLTLogging(),
148   fSegments(),
149   fConsumers(),
150   fActiveConsumers(),
151   fReleasedConsumers(),
152   fpBuffer(NULL),
153   fFlags(0)
154 {
155   HLTFatal("copy constructor untested");
156 }
157
158 AliHLTDataBuffer& AliHLTDataBuffer::operator=(const AliHLTDataBuffer&)
159
160   HLTFatal("assignment operator untested");
161   return *this;
162 }
163
164 int AliHLTDataBuffer::fNofInstances=0;
165 vector<AliHLTRawBuffer*> AliHLTDataBuffer::fFreeBuffers;
166 vector<AliHLTRawBuffer*> AliHLTDataBuffer::fActiveBuffers;
167 AliHLTUInt32_t AliHLTDataBuffer::fMargin=1024;
168 AliHLTLogging AliHLTDataBuffer::fgLogging;
169
170 AliHLTDataBuffer::~AliHLTDataBuffer()
171 {
172   if (--fNofInstances<=0) {
173     DeleteRawBuffers();
174   }
175   CleanupConsumerList();
176 }
177
178 int AliHLTDataBuffer::SetConsumer(AliHLTComponent* pConsumer)
179 {
180   int iResult=0;
181   if (pConsumer) {
182     AliHLTConsumerDescriptor* pDesc=new AliHLTConsumerDescriptor(pConsumer);
183     if (pDesc) {
184       fConsumers.push_back(pDesc);
185     } else {
186       HLTError("memory allocation failed");
187       iResult=-ENOMEM;
188     }
189   } else {
190     HLTError("invalid parameter");
191     iResult=-EINVAL;
192   }
193   return iResult;
194 }
195
196 int AliHLTDataBuffer::FindMatchingDataBlocks(const AliHLTComponent* pConsumer, vector<AliHLTComponent_DataType>* tgtList)
197 {
198   int iResult=0;
199   if (pConsumer) {
200     vector<AliHLTDataSegment> segments;
201     if ((iResult=FindMatchingDataSegments(pConsumer, segments))>=0) {
202       if (tgtList) {
203         vector<AliHLTDataSegment>::iterator segment=segments.begin();
204         while (segment!=segments.end()) {
205           tgtList->push_back((*segment).fDataType);
206           segment++;
207         }
208       }
209       iResult=segments.size();
210     }
211   } else {
212     iResult=-EINVAL;
213   }
214   return iResult;
215 }
216
217 int AliHLTDataBuffer::FindMatchingDataSegments(const AliHLTComponent* pConsumer, vector<AliHLTDataSegment>& tgtList)
218 {
219   int iResult=0;
220   if (pConsumer) {
221     vector<AliHLTComponent_DataType> dtlist;
222     ((AliHLTComponent*)pConsumer)->GetInputDataTypes(dtlist);
223     vector<AliHLTDataSegment>::iterator segment=fSegments.begin();
224     while (segment!=fSegments.end()) {
225       vector<AliHLTComponent_DataType>::iterator type=dtlist.begin();
226       while (type!=dtlist.end()) {
227         if ((*segment).fDataType==(*type)) {
228           tgtList.push_back(*segment);
229           iResult++;
230           break;
231         }
232         type++;
233       }
234       segment++;
235     }
236   } else {
237     iResult=-EINVAL;
238   }
239   return iResult;
240 }
241
242 int AliHLTDataBuffer::Subscribe(const AliHLTComponent* pConsumer, AliHLTComponent_BlockData* arrayBlockDesc, int iArraySize)
243 {
244   int iResult=0;
245   if (pConsumer && arrayBlockDesc) {
246     if (fpBuffer) {
247       AliHLTConsumerDescriptor* pDesc=FindConsumer(pConsumer, fConsumers);
248       if (pDesc) {
249         vector<AliHLTDataSegment> tgtList;
250         /* TODO: think about a good policy for this check
251          * is it enough that at least one segment is available, or have all to be available?
252          * or is it possible to have optional segments?
253          */
254         if ((iResult=FindMatchingDataSegments(pConsumer, tgtList))>0) {
255           int i =0;
256           vector<AliHLTDataSegment>::iterator segment=tgtList.begin();
257           while (segment!=tgtList.end() && i<iArraySize) {
258             // fill the block data descriptor
259             arrayBlockDesc[i].fStructSize=sizeof(AliHLTComponent_BlockData);
260             // the shared memory key is not used in AliRoot
261             arrayBlockDesc[i].fShmKey.fStructSize=sizeof(AliHLTComponent_ShmData);
262             arrayBlockDesc[i].fShmKey.fShmType=gkAliHLTComponent_InvalidShmType;
263             arrayBlockDesc[i].fShmKey.fShmID=gkAliHLTComponent_InvalidShmID;
264             arrayBlockDesc[i].fOffset=(*segment).fSegmentOffset;
265             arrayBlockDesc[i].fPtr=fpBuffer->fPtr;
266             arrayBlockDesc[i].fSize=(*segment).fSegmentSize;
267             arrayBlockDesc[i].fDataType=(*segment).fDataType;
268             arrayBlockDesc[i].fSpecification=(*segment).fSpecification;
269             pDesc->SetActiveDataSegment(arrayBlockDesc[i].fOffset, arrayBlockDesc[i].fSize);
270             HLTDebug("component %p (%s) subscribed to segment #%d offset %d", pConsumer, ((AliHLTComponent*)pConsumer)->GetComponentID(), i, arrayBlockDesc[i].fOffset);
271             i++;
272             segment++;
273           }
274           // move this consumer to the active list
275           if (ChangeConsumerState(pDesc, fConsumers, fActiveConsumers)>=0) {
276             HLTDebug("component %p (%s) subscribed to data buffer %p", pConsumer, ((AliHLTComponent*)pConsumer)->GetComponentID(), this);
277           } else {
278             // TODO: cleanup the consumer descriptor correctly
279             memset(arrayBlockDesc, 0, iArraySize*sizeof(AliHLTComponent_BlockData));
280             HLTError("can not activate consumer %p for data buffer %p", pConsumer, this);
281             iResult=-EACCES;
282           }
283         } else {
284           HLTError("unresolved data segment(s) for component %p (%s)", pConsumer, ((AliHLTComponent*)pConsumer)->GetComponentID());
285           iResult=-EBADF;
286         }
287       } else {
288         HLTError("component %p is not a data consumer of data buffer %s", pConsumer, this);
289         iResult=-ENOENT;
290       }
291     } else {
292       HLTError("data buffer %p is empty", this);
293       iResult=-ENODATA;
294     }
295   } else {
296     HLTError("invalid parameter");
297     iResult=-EINVAL;
298   }
299   return iResult;
300 }
301
302 int AliHLTDataBuffer::Release(AliHLTComponent_BlockData* pBlockDesc, const AliHLTComponent* pConsumer)
303 {
304   int iResult=0;
305   if (pBlockDesc && pConsumer) {
306     AliHLTConsumerDescriptor* pDesc=FindConsumer(pConsumer, fActiveConsumers);
307     if (pDesc) {
308       if ((iResult=pDesc->CheckActiveDataSegment(pBlockDesc->fOffset, pBlockDesc->fSize))!=1) {
309         HLTWarning("data segment missmatch, component %p has not subscribed to a segment with offset %#x and size %d", pConsumer, pBlockDesc->fOffset, pBlockDesc->fSize);
310         // TODO: appropriate error handling, but so far optional
311         iResult=0;
312       } else {
313         pDesc->ReleaseActiveDataSegment(pBlockDesc->fOffset, pBlockDesc->fSize);
314         pBlockDesc->fOffset=0;
315         pBlockDesc->fPtr=NULL;
316         pBlockDesc->fSize=0;
317       }
318       if (pDesc->GetNofActiveSegments()==0) {
319         if ((iResult=ChangeConsumerState(pDesc, fActiveConsumers, fReleasedConsumers))>=0) {
320           if (GetNofActiveConsumers()==0) {
321             // this is the last consumer, reset the consumer list and release the raw buffer
322             ResetDataBuffer();
323           }
324         } else {
325           HLTError("can not deactivate consumer %p for data buffer %p", pConsumer, this);
326           iResult=-EACCES;
327         }
328       }
329     } else {
330       HLTWarning("component %p has currently not subscribed to the data buffer %p", pConsumer, this);
331       iResult=-ENOENT;
332     }
333   } else {
334     HLTError("inavalid parameter: pBlockDesc=%p pConsumer=%p", pBlockDesc, pConsumer);
335     iResult=-EINVAL;
336   }
337   return iResult;
338 }
339
340 AliHLTUInt8_t* AliHLTDataBuffer::GetTargetBuffer(int iMinSize)
341 {
342   AliHLTUInt8_t* pTargetBuffer=NULL;
343   fpBuffer=CreateRawBuffer(iMinSize);
344   pTargetBuffer=(AliHLTUInt8_t*)fpBuffer;
345   return pTargetBuffer;
346 }
347
348 int AliHLTDataBuffer::SetSegments(AliHLTUInt8_t* pTgt, AliHLTComponent_BlockData* arrayBlockData, int iSize)
349 {
350   int iResult=0;
351   if (pTgt && arrayBlockData && iSize>=0) {
352     if (fpBuffer) {
353       if (fpBuffer->fPtr==(void*)pTgt) {
354         AliHLTDataSegment segment;
355         memset(&segment, 0, sizeof(AliHLTDataSegment));
356         for (int i=0; i<iSize; i++) {
357           if (arrayBlockData[i].fOffset+arrayBlockData[i].fSize<fpBuffer->fSize) {
358             segment.fSegmentOffset=arrayBlockData[i].fOffset;
359             segment.fSegmentSize=arrayBlockData[i].fSize;
360             segment.fDataType=arrayBlockData[i].fDataType;
361             segment.fSpecification=arrayBlockData[i].fSpecification;
362             fSegments.push_back(segment);
363           } else {
364             HLTError("block data specification #%d (%s@%s) exceeds size of data buffer", i, arrayBlockData[i].fDataType.fOrigin, arrayBlockData[i].fDataType.fID);
365           }
366         }
367       } else {
368         HLTError("this data buffer (%p) does not match the internal data buffer %p of raw buffer %p", pTgt, fpBuffer->fPtr, fpBuffer);
369       }
370     } else {
371       HLTFatal("internal data structur missmatch");
372       iResult=-EFAULT;
373     }
374   } else {
375     HLTError("invalid parameter: pTgtBuffer=%p arrayBlockData=%p", pTgt, arrayBlockData);
376     iResult=-EINVAL;
377   }
378   return iResult;
379 }
380
381 int AliHLTDataBuffer::IsEmpty()
382 {
383   int iResult=fpBuffer==NULL || GetNofSegments()==0;
384   return iResult;
385 }
386
387 int AliHLTDataBuffer::GetNofSegments()
388 {
389   int iResult=fSegments.size();
390   return iResult;
391 }
392
393 int AliHLTDataBuffer::GetNofConsumers()
394 {
395   int iResult=fConsumers.size() + GetNofActiveConsumers() + fReleasedConsumers.size();
396   return iResult;
397 }
398
399 int AliHLTDataBuffer::GetNofActiveConsumers()
400 {
401   int iResult=fActiveConsumers.size();
402   return iResult;
403 }
404
405 AliHLTRawBuffer* AliHLTDataBuffer::CreateRawBuffer(AliHLTUInt32_t size)
406 {
407   AliHLTRawBuffer* pRawBuffer=NULL;
408   vector<AliHLTRawBuffer*>::iterator buffer=fFreeBuffers.begin();
409   while (buffer!=fFreeBuffers.end() && pRawBuffer==NULL) {
410     if ((*buffer)->fTotalSize>=size && ((*buffer)->fTotalSize-size)<fMargin) {
411       // assign this element
412       pRawBuffer=*buffer;
413       pRawBuffer->fSize=size;
414       fFreeBuffers.erase(buffer);
415       fgLogging.Logging(kHLTLogDebug, "AliHLTDataBuffer::CreateRawBuffer", "data buffer handling", "raw buffer container %p provided for request of %d bytes (total %d available in buffer %p)", pRawBuffer, size, pRawBuffer->fTotalSize, pRawBuffer->fPtr);
416       fActiveBuffers.push_back(pRawBuffer);
417       break;
418     }
419     buffer++;
420   }
421   if (pRawBuffer==NULL) {
422     // no buffer found, create a new one
423     pRawBuffer=new AliHLTRawBuffer;
424     if (pRawBuffer) {
425       memset(pRawBuffer, 0, sizeof(AliHLTRawBuffer));
426       pRawBuffer->fPtr=malloc(size);
427       if (pRawBuffer->fPtr) {
428         pRawBuffer->fSize=size;
429         pRawBuffer->fTotalSize=size;
430         fActiveBuffers.push_back(pRawBuffer);
431         fgLogging.Logging(kHLTLogDebug, "AliHLTDataBuffer::CreateRawBuffer", "data buffer handling", "new raw buffer %p of size %d created (container %p)", pRawBuffer->fPtr, pRawBuffer->fTotalSize, pRawBuffer);
432       } else {
433         delete pRawBuffer;
434         pRawBuffer=NULL;
435         fgLogging.Logging(kHLTLogError, "AliHLTDataBuffer::CreateRawBuffer", "data buffer handling", "memory allocation failed");
436       } 
437     } else {
438       fgLogging.Logging(kHLTLogError, "AliHLTDataBuffer::CreateRawBuffer", "data buffer handling", "memory allocation failed");
439     }
440   }
441   return pRawBuffer;
442 }
443
444 int AliHLTDataBuffer::ReleaseRawBuffer(AliHLTRawBuffer* pBuffer)
445 {
446   int iResult=0;
447   if (pBuffer) {
448     vector<AliHLTRawBuffer*>::iterator buffer=fActiveBuffers.begin();
449     while (buffer!=fActiveBuffers.end() && (*buffer)!=pBuffer) {
450       buffer++;
451     }
452     if (buffer!=fActiveBuffers.end()) {
453       (*buffer)->fSize=0;
454       fFreeBuffers.push_back(*buffer);
455       fActiveBuffers.erase(buffer);
456     } else {
457       fgLogging.Logging(kHLTLogWarning, "AliHLTDataBuffer::ReleaseRawBuffer", "data buffer handling", "can not find raw buffer container %p in the list of active containers", pBuffer);
458       iResult=-ENOENT;
459     }
460   } else {
461     fgLogging.Logging(kHLTLogError, "AliHLTDataBuffer::ReleaseRawBuffer", "data buffer handling", "invalid parameter");
462     iResult=-EINVAL;
463   }
464   return iResult;
465 }
466
467
468 int AliHLTDataBuffer::DeleteRawBuffers() 
469 {
470   int iResult=0;
471   vector<AliHLTRawBuffer*>::iterator buffer=fFreeBuffers.begin();
472   while (buffer!=fFreeBuffers.end()) {
473     free((*buffer)->fPtr);
474     delete *buffer;
475     fFreeBuffers.erase(buffer);
476     buffer=fFreeBuffers.begin();
477   }
478   buffer=fActiveBuffers.begin();
479   while (buffer!=fFreeBuffers.end()) {
480     fgLogging.Logging(kHLTLogWarning, "AliHLTDataBuffer::ReleaseRawBuffer", "data buffer handling", "request to delete active raw buffer container (raw buffer %p, size %d)", (*buffer)->fPtr, (*buffer)->fTotalSize);
481     free((*buffer)->fPtr);
482     delete *buffer;
483     fActiveBuffers.erase(buffer);
484     buffer=fActiveBuffers.begin();
485   }
486   return iResult;
487 }
488
489 AliHLTConsumerDescriptor* AliHLTDataBuffer::FindConsumer(const AliHLTComponent* pConsumer, vector<AliHLTConsumerDescriptor*> &list)
490 {
491   AliHLTConsumerDescriptor* pDesc=NULL;
492   vector<AliHLTConsumerDescriptor*>::iterator desc=list.begin();
493   while (desc!=list.end() && pDesc==NULL) {
494     if ((pConsumer==NULL || (*desc)->GetComponent()==pConsumer)) {
495       pDesc=*desc;
496     }
497     desc++;
498   }
499   return pDesc;
500 }
501
502 int AliHLTDataBuffer::ResetDataBuffer() 
503 {
504   int iResult=0;
505   AliHLTRawBuffer* pBuffer=fpBuffer;
506   fpBuffer=NULL;
507   vector<AliHLTConsumerDescriptor*>::iterator desc=fReleasedConsumers.begin();
508   while (desc!=fReleasedConsumers.end()) {
509     AliHLTConsumerDescriptor* pDesc=*desc;
510     fReleasedConsumers.erase(desc);
511     desc=fReleasedConsumers.begin();
512     fConsumers.push_back(pDesc);
513   }
514   desc=fActiveConsumers.begin();
515   while (desc!=fActiveConsumers.end()) {
516     AliHLTConsumerDescriptor* pDesc=*desc;
517     HLTWarning("consumer %p was not released", pDesc);
518     fActiveConsumers.erase(desc);
519     desc=fActiveConsumers.begin();
520     fConsumers.push_back(pDesc);
521   }
522   ReleaseRawBuffer(pBuffer);
523   return iResult;
524 }
525
526 // this is the version which works on lists of components instead of consumer descriptors
527 // int AliHLTDataBuffer::ChangeConsumerState(AliHLTComponent* pConsumer, vector<AliHLTComponent*> &srcList, vector<AliHLTComponent*> &tgtList)
528 // {
529 //   int iResult=0;
530 //   if (pDesc) {
531 //     vector<AliHLTComponent*>::iterator desc=srcList.begin();
532 //     while (desc!=srcList.end()) {
533 //       if ((*desc)==pConsumer) {
534 //      srcList.erase(desc);
535 //      tgtList.push_back(pConsumer);
536 //      break;
537 //       }
538 //      desc++;
539 //     }
540 //     if (desc==srcList.end()) {
541 //       HLTError("can not find consumer component %p in list", pConsumer);
542 //       iResult=-ENOENT;
543 //     }
544 //   } else {
545 //     HLTError("invalid parameter");
546 //     iResult=-EINVAL;
547 //   }
548 //   return iResult;
549 // }
550
551 int AliHLTDataBuffer::ChangeConsumerState(AliHLTConsumerDescriptor* pDesc, vector<AliHLTConsumerDescriptor*> &srcList, vector<AliHLTConsumerDescriptor*> &tgtList)
552 {
553   int iResult=0;
554   if (pDesc) {
555     vector<AliHLTConsumerDescriptor*>::iterator desc=srcList.begin();
556     while (desc!=srcList.end()) {
557       if ((*desc)==pDesc) {
558         srcList.erase(desc);
559         tgtList.push_back(pDesc);
560         break;
561       }
562       desc++;
563     }
564     if (desc==srcList.end()) {
565       HLTError("can not find consumer descriptor %p in list", pDesc);
566       iResult=-ENOENT;
567     }
568   } else {
569     HLTError("invalid parameter");
570     iResult=-EINVAL;
571   }
572   return iResult;
573 }
574
575 int AliHLTDataBuffer::CleanupConsumerList() {
576   int iResult=0;
577   ResetDataBuffer();
578   vector<AliHLTConsumerDescriptor*>::iterator desc=fConsumers.begin();
579   while (desc!=fConsumers.end()) {
580     delete *desc;
581     fConsumers.erase(desc);
582     desc=fConsumers.begin();
583   }
584   return iResult;
585 }