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