]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/BASE/AliHLTTask.cxx
further work on HLTOUT treatment
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTTask.cxx
1 // $Id$
2 // splitted from AliHLTConfiguration.cxx,v 1.25 2007/10/12 13:24:47
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   AliHLTTask.cxx
20     @author Matthias Richter
21     @date   
22     @brief  Implementation of HLT tasks.
23 */
24
25 // see header file for class documentation
26 // or
27 // refer to README to build package
28 // or
29 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
30
31 #if __GNUC__>= 3
32 using namespace std;
33 #endif
34
35 #include <cerrno>
36 #include <iostream>
37 #include <string>
38 #include "AliHLTTask.h"
39 #include "AliHLTConfiguration.h"
40 #include "AliHLTComponent.h"
41 #include "AliHLTComponentHandler.h"
42 #include "TList.h"
43
44 /** ROOT macro for the implementation of ROOT specific class methods */
45 ClassImp(AliHLTTask)
46
47 AliHLTTask::AliHLTTask()
48   :
49   fpConfiguration(NULL),
50   fpComponent(NULL),
51   fpDataBuffer(NULL),
52   fListTargets(),
53   fListDependencies(),
54   fBlockDataArray()
55 {
56   // see header file for class documentation
57   // or
58   // refer to README to build package
59   // or
60   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
61 }
62
63 AliHLTTask::AliHLTTask(AliHLTConfiguration* pConf)
64   :
65   fpConfiguration(pConf),
66   fpComponent(NULL),
67   fpDataBuffer(NULL),
68   fListTargets(),
69   fListDependencies(),
70   fBlockDataArray()
71 {
72   // see header file for function documentation
73 }
74
75 AliHLTTask::~AliHLTTask()
76 {
77   // see header file for function documentation
78   TObjLink* lnk=fListDependencies.FirstLink();
79
80   while (lnk!=NULL) {
81     AliHLTTask* pTask=(AliHLTTask*)lnk->GetObject();
82     pTask->UnsetTarget(this);
83     lnk=lnk->Next();
84   }
85   lnk=fListTargets.FirstLink();
86
87   while (lnk!=NULL) {
88     AliHLTTask* pTask=(AliHLTTask*)lnk->GetObject();
89     pTask->UnsetDependency(this);
90     lnk=lnk->Next();
91   }
92
93   if (fpComponent) delete fpComponent;
94   fpComponent=NULL;
95 }
96
97 int AliHLTTask::Init(AliHLTConfiguration* pConf, AliHLTComponentHandler* pCH)
98 {
99   // see header file for function documentation
100   int iResult=0;
101   if (fpConfiguration!=NULL && pConf!=NULL && fpConfiguration!=pConf) {
102     HLTWarning("overriding existing reference to configuration object %p (%s) by %p",
103                fpConfiguration, GetName(), pConf);
104   }
105   if (pConf!=NULL) fpConfiguration=pConf;
106   if (fpConfiguration) {
107     if (pCH) {
108       int argc=0;
109       const char** argv=NULL;
110       if ((iResult=fpConfiguration->GetArguments(&argv))>=0) {
111         argc=iResult; // just to make it clear
112         // TODO: we have to think about the optional environment parameter,
113         // currently just set to NULL. 
114         iResult=pCH->CreateComponent(fpConfiguration->GetComponentID(), NULL, argc, argv, fpComponent);
115         if (fpComponent || iResult<=0) {
116           //HLTDebug("component %s (%p) created", fpComponent->GetComponentID(), fpComponent); 
117         } else {
118           HLTError("can not find component \"%s\" (%d)", fpConfiguration->GetComponentID(), iResult);
119         }
120       } else {
121         HLTError("can not get argument list for configuration %s (%s)", fpConfiguration->GetName(), fpConfiguration->GetComponentID());
122         iResult=-EINVAL;
123       }
124     } else {
125       HLTError("component handler instance needed for task initialization");
126       iResult=-EINVAL;
127     }
128   } else {
129     HLTError("configuration object instance needed for task initialization");
130     iResult=-EINVAL;
131   }
132   return iResult;
133 }
134
135 int AliHLTTask::Deinit()
136 {
137   // see header file for function documentation
138   int iResult=0;
139   AliHLTComponent* pComponent=GetComponent();
140   fpComponent=NULL;
141   if (pComponent) {
142     //HLTDebug("delete component %s (%p)", pComponent->GetComponentID(), pComponent); 
143     pComponent->Deinit();
144     delete pComponent;
145   } else {
146     HLTWarning("task %s (%p) doesn't seem to be in initialized", GetName(), this);
147   }
148   return iResult;
149 }
150
151 const char *AliHLTTask::GetName() const
152 {
153   // see header file for function documentation
154   if (fpConfiguration)
155     return fpConfiguration->GetName();
156   return TObject::GetName();
157 }
158
159 AliHLTConfiguration* AliHLTTask::GetConf() const
160 {
161   // see header file for function documentation
162   return fpConfiguration;
163 }
164
165 AliHLTComponent* AliHLTTask::GetComponent() const
166 {
167   // see header file for function documentation
168   return fpComponent;
169 }
170
171 AliHLTTask* AliHLTTask::FindDependency(const char* id)
172 {
173   // see header file for function documentation
174   AliHLTTask* pTask=NULL;
175   if (id) {
176     pTask=(AliHLTTask*)fListDependencies.FindObject(id);
177   }
178   return pTask;
179 }
180
181 int AliHLTTask::FollowDependency(const char* id, TList* pTgtList)
182 {
183   // see header file for function documentation
184   int iResult=0;
185   if (id) {
186     AliHLTTask* pDep=NULL;
187     if ((pDep=(AliHLTTask*)fListDependencies.FindObject(id))!=NULL) {
188       if (pTgtList) pTgtList->Add(pDep);
189       iResult++;
190     } else {
191       TObjLink* lnk=fListDependencies.FirstLink();
192       while (lnk && iResult==0) {
193         pDep=(AliHLTTask*)lnk->GetObject();
194         if (pDep) {
195           if ((iResult=pDep->FollowDependency(id, pTgtList))>0) {
196             if (pTgtList) pTgtList->AddFirst(pDep);
197             iResult++;
198           }
199         } else {
200           iResult=-EFAULT;
201         }
202         lnk=lnk->Next();
203       }
204     }
205   } else {
206     iResult=-EINVAL;
207   }
208   return iResult;
209 }
210
211 void AliHLTTask::PrintDependencyTree(const char* id, int bFromConfiguration)
212 {
213   // see header file for function documentation
214   HLTLogKeyword("task dependencies");
215   int iResult=0;
216   TList tgtList;
217   if (bFromConfiguration) {
218     if (fpConfiguration)
219       iResult=fpConfiguration->FollowDependency(id, &tgtList);
220     else
221       iResult=-EFAULT;
222   } else
223     iResult=FollowDependency(id, &tgtList);
224   if (iResult>0) {
225     HLTMessage("     task \"%s\": dependency level %d ", GetName(), iResult);
226     TObjLink* lnk=tgtList.FirstLink();
227     int i=iResult;
228     char* pSpace = new char[iResult+1];
229     if (pSpace) {
230       memset(pSpace, 32, iResult);
231       pSpace[i]=0;
232       while (lnk) {
233         TObject* obj=lnk->GetObject();
234         HLTMessage("     %s^-- %s ", &pSpace[i--], obj->GetName());
235         lnk=lnk->Next();
236       }
237       delete [] pSpace;
238     } else {
239       iResult=-ENOMEM;
240     }
241   }
242 }
243
244 int AliHLTTask::SetDependency(AliHLTTask* pDep)
245 {
246   // see header file for function documentation
247   int iResult=0;
248   if (pDep) {
249     if (FindDependency(pDep->GetName())==NULL) {
250       fListDependencies.Add(pDep);
251     } else {
252       iResult=-EEXIST;
253     }
254   } else {
255     iResult=-EINVAL;
256   }
257   return iResult;
258 }
259
260 int AliHLTTask::UnsetDependency(AliHLTTask* pDep)
261 {
262   // see header file for function documentation
263   fListDependencies.Remove(pDep);
264   if (fpConfiguration) {
265     fpConfiguration->InvalidateSources();
266   }
267   return 0;
268 }
269
270 int AliHLTTask::CheckDependencies()
271 {
272   // see header file for function documentation
273   int iResult=0;
274   AliHLTConfiguration* pSrc=fpConfiguration->GetFirstSource();
275   while (pSrc) {
276     if (FindDependency(pSrc->GetName())==NULL) {
277       //HLTDebug("dependency \"%s\" unresolved", pSrc->GetName());
278       iResult++;
279     }
280     pSrc=fpConfiguration->GetNextSource();
281   }
282   return iResult;
283 }
284
285
286 int AliHLTTask::Depends(AliHLTTask* pTask)
287 {
288   // see header file for function documentation
289   int iResult=0;
290   if (pTask) {
291     if (fpConfiguration) {
292       iResult=fpConfiguration->GetSource(pTask->GetName())!=NULL;
293       if (iResult>0) {
294         //HLTDebug("task  \"%s\" depends on \"%s\"", GetName(), pTask->GetName());
295       } else {
296         //HLTDebug("task  \"%s\" independend of \"%s\"", GetName(), pTask->GetName());
297       }
298     } else {
299       iResult=-EFAULT;
300     }
301   } else {
302     iResult=-EINVAL;
303   }
304   return iResult;
305 }
306
307 AliHLTTask* AliHLTTask::FindTarget(const char* id)
308 {
309   // see header file for function documentation
310   AliHLTTask* pTask=NULL;
311   if (id) {
312     pTask=(AliHLTTask*)fListTargets.FindObject(id);
313   }
314   return pTask;
315 }
316
317 int AliHLTTask::SetTarget(AliHLTTask* pTgt)
318 {
319   // see header file for function documentation
320   int iResult=0;
321   if (pTgt) {
322     if (FindTarget(pTgt->GetName())==NULL) {
323       fListTargets.Add(pTgt);
324     } else {
325       iResult=-EEXIST;
326     }
327   } else {
328     iResult=-EINVAL;
329   }
330   return iResult;
331 }
332
333 int AliHLTTask::UnsetTarget(AliHLTTask* pTarget)
334 {
335   // see header file for function documentation
336   fListTargets.Remove(pTarget);
337   return 0;
338 }
339
340 int AliHLTTask::StartRun()
341 {
342   // see header file for function documentation
343   int iResult=0;
344   int iNofInputDataBlocks=0;
345   AliHLTComponent* pComponent=GetComponent();
346   if (pComponent) {
347     // determine the number of input data blocks provided from the source tasks
348     TObjLink* lnk=fListDependencies.FirstLink();
349     while (lnk && iResult>=0) {
350       AliHLTTask* pSrcTask=(AliHLTTask*)lnk->GetObject();
351       if (pSrcTask) {
352         if ((iResult=pSrcTask->GetNofMatchingDataTypes(this))>0) {
353           iNofInputDataBlocks+=iResult;
354         } else if (iResult==0) {
355           HLTWarning("source task %s (%p) does not provide any matching data type for task %s (%p)", pSrcTask->GetName(), pSrcTask, GetName(), this);
356         } else {
357           HLTError("task %s (%p): error getting matching data types for source task %s (%p)", GetName(), this, pSrcTask->GetName(), pSrcTask);
358           iResult=-EFAULT;
359         }
360       }
361       lnk=lnk->Next();
362     }
363     if (iResult>=0) {
364       if (fBlockDataArray.size()>0) {
365         HLTWarning("block data array for task %s (%p) was not cleaned", GetName(), this);
366         fBlockDataArray.resize(0);
367       }
368
369       // component init
370       // the initialization of the component is done by the ComponentHandler after creation
371       // of the component.
372       //iResult=Init( AliHLTComponentEnvironment* environ, void* environ_param, int argc, const char** argv );
373
374       // allocate internal task variables for bookkeeping aso.
375       // we allocate the BlockData array with at least one member
376       if (iNofInputDataBlocks==0) iNofInputDataBlocks=1;
377       AliHLTComponentBlockData init;
378       memset(&init, 0, sizeof(AliHLTComponentBlockData));
379       fBlockDataArray.resize(iNofInputDataBlocks, init);
380
381       // allocate the data buffer, which controls the output buffer and subscriptions
382       if (iResult>=0) {
383         fpDataBuffer=new AliHLTDataBuffer;
384         if (fpDataBuffer!=NULL) {
385           HLTDebug("created data buffer %p for task %s (%p)", fpDataBuffer, GetName(), this);
386           TObjLink* lnk=fListTargets.FirstLink();
387           while (lnk && iResult>=0) {
388             AliHLTTask* pTgtTask=(AliHLTTask*)lnk->GetObject();
389             if (pTgtTask) {
390               if ((iResult=fpDataBuffer->SetConsumer(pTgtTask->GetComponent()))>=0) {
391               }
392             } else {
393               break;
394               iResult=-EFAULT;
395             }
396             lnk=lnk->Next();
397           }
398         } else {
399           HLTFatal("can not create data buffer object, memory allocation failed");
400           iResult=-ENOMEM;
401         }
402       }
403     }
404   } else {
405     HLTError("task %s (%p) does not have a component", GetName(), this);
406     iResult=-EFAULT;
407   }
408   return iResult;
409 }
410
411 int AliHLTTask::EndRun()
412 {
413   // see header file for function documentation
414   int iResult=0;
415   if (fBlockDataArray.size()>0) {
416     fBlockDataArray.resize(0);
417   } else {
418     HLTWarning("task %s (%p) doesn't seem to be in running mode", GetName(), this);
419   }
420   if (fpDataBuffer) {
421     AliHLTDataBuffer* pBuffer=fpDataBuffer;
422     fpDataBuffer=NULL;
423     delete pBuffer;
424   }
425   return iResult;
426 }
427
428 int AliHLTTask::ProcessTask(Int_t eventNo)
429 {
430   // see header file for function documentation
431   int iResult=0;
432   AliHLTComponent* pComponent=GetComponent();
433   if (pComponent && fpDataBuffer) {
434     HLTDebug("Processing task %s (%p) fpDataBuffer %p", GetName(), this, fpDataBuffer);
435     fpDataBuffer->Reset();
436     int iSourceDataBlock=0;
437     int iInputDataVolume=0;
438
439     AliHLTTask* pSrcTask=NULL;
440     TList subscribedTaskList;
441     TObjLink* lnk=fListDependencies.FirstLink();
442
443     // subscribe to all source tasks
444     while (lnk && iResult>=0) {
445       pSrcTask=(AliHLTTask*)lnk->GetObject();
446       if (pSrcTask) {
447         int iMatchingDB=pSrcTask->GetNofMatchingDataBlocks(this);
448         if (iMatchingDB>=0 && static_cast<unsigned int>(iMatchingDB)>fBlockDataArray.size()-iSourceDataBlock) {
449           AliHLTComponentBlockData init;
450           memset(&init, 0, sizeof(AliHLTComponentBlockData));
451           fBlockDataArray.resize(iSourceDataBlock+iMatchingDB, init);
452         } else {
453           if (iMatchingDB<0) {
454             HLTError("task %s (%p): error getting no of matching data blocks from task %s (%p), error %d", GetName(), this, pSrcTask->GetName(), pSrcTask, iMatchingDB);
455             iResult=iMatchingDB;
456             break;
457           } else if (iMatchingDB==0) {
458             HLTDebug("source task %s (%p) does not provide any matching data type for task %s (%p)", pSrcTask->GetName(), pSrcTask, GetName(), this);
459           }
460         }
461         if ((iResult=pSrcTask->Subscribe(this, &fBlockDataArray[iSourceDataBlock],fBlockDataArray.size()-iSourceDataBlock))>=0) {
462           for (int i=0; i<iResult; i++) {
463             iInputDataVolume+=fBlockDataArray[i+iSourceDataBlock].fSize;
464             // put the source task as many times into the list as it provides data blocks
465             // makes the bookkeeping for the data release easier
466             subscribedTaskList.Add(pSrcTask);
467           }
468           HLTDebug("Task %s (%p) successfully subscribed to %d data block(s) of task %s (%p)", GetName(), this, iResult, pSrcTask->GetName(), pSrcTask);
469           iSourceDataBlock+=iResult;      
470           iResult=0;
471         } else {
472           HLTError("Task %s (%p): subscription to task %s (%p) failed with error %d", GetName(), this, pSrcTask->GetName(), pSrcTask, iResult);
473           iResult=-EFAULT;
474         }
475       } else {
476         HLTFatal("fatal internal error in ROOT list handling");
477         iResult=-EFAULT;
478       }
479       lnk=lnk->Next();
480     }
481
482     // process the event
483     int iNofTrial=0; // repeat processing if component returns -ENOSPC
484     AliHLTUInt32_t size=0;
485     if (iResult>=0) {
486     do {
487       long unsigned int iConstBase=0;
488       double fInputMultiplier=0;
489       if (pComponent->GetComponentType()!=AliHLTComponent::kSink)
490         pComponent->GetOutputDataSize(iConstBase, fInputMultiplier);
491       if (fInputMultiplier<0) {
492         HLTWarning("ignoring negative input multiplier");
493         fInputMultiplier=0;
494       }
495       long unsigned int iOutputDataSize=int(fInputMultiplier*iInputDataVolume) + iConstBase;
496       //HLTDebug("task %s: reqired output size %d", GetName(), iOutputDataSize);
497       if (iNofTrial>0) {
498         // dont process again if the buffer size is the same
499         if (size==iOutputDataSize) break;
500         HLTInfo("processing task %s again with buffer size %d", GetName(), iOutputDataSize);
501       }
502       AliHLTUInt8_t* pTgtBuffer=NULL;
503       if (iOutputDataSize>0) pTgtBuffer=fpDataBuffer->GetTargetBuffer(iOutputDataSize);
504       //HLTDebug("provided raw buffer %p", pTgtBuffer);
505       AliHLTComponentEventData evtData;
506       AliHLTComponent::FillEventData(evtData);
507       evtData.fEventID=(AliHLTEventID_t)eventNo;
508       evtData.fBlockCnt=iSourceDataBlock;
509       AliHLTComponentTriggerData trigData;
510       size=iOutputDataSize;
511       AliHLTUInt32_t outputBlockCnt=0;
512       AliHLTComponentBlockData* outputBlocks=NULL;
513       AliHLTComponentEventDoneData* edd;
514       if (pTgtBuffer!=NULL || iOutputDataSize==0) {
515         iResult=pComponent->ProcessEvent(evtData, &fBlockDataArray[0], trigData, pTgtBuffer, size, outputBlockCnt, outputBlocks, edd);
516         HLTDebug("task %s: component %s ProcessEvent finnished (%d): size=%d blocks=%d", GetName(), pComponent->GetComponentID(), iResult, size, outputBlockCnt);
517         if (iResult>=0 && pTgtBuffer && outputBlocks) {
518           iResult=fpDataBuffer->SetSegments(pTgtBuffer, outputBlocks, outputBlockCnt);
519           delete [] outputBlocks; outputBlocks=NULL; outputBlockCnt=0;
520         } else {
521           fpDataBuffer->Reset();
522         }
523       } else {
524         HLTError("task %s: no target buffer available", GetName());
525         iResult=-EFAULT;
526       }
527     } while (iResult==-ENOSPC && iNofTrial++<1);
528     }
529
530     // now release all buffers which we have subscribed to
531     iSourceDataBlock=0;
532     lnk=subscribedTaskList.FirstLink();
533     while (lnk) {
534       pSrcTask=(AliHLTTask*)lnk->GetObject();
535       if (pSrcTask) {
536         int iTempRes=0;
537         if ((iTempRes=pSrcTask->Release(&fBlockDataArray[iSourceDataBlock], this))>=0) {
538           HLTDebug("Task %s (%p) successfully released segment of task %s (%p)", GetName(), this, pSrcTask->GetName(), pSrcTask);
539         } else {
540           HLTError("Task %s (%p): realease of task %s (%p) failed with error %d", GetName(), this, pSrcTask->GetName(), pSrcTask, iTempRes);
541         }
542       } else {
543         HLTFatal("task %s (%p): internal error in ROOT list handling", GetName(), this);
544         if (iResult>=0) iResult=-EFAULT;
545       }
546       subscribedTaskList.Remove(lnk);
547       lnk=subscribedTaskList.FirstLink();
548       iSourceDataBlock++;
549     }
550     if (subscribedTaskList.GetSize()>0) {
551       HLTError("task %s (%p): could not release all data buffers", GetName(), this);
552     }
553   } else {
554     HLTError("task %s (%p): internal failure (not initialized component %p, data buffer %p)", GetName(), this, fpComponent, fpDataBuffer);
555     iResult=-EFAULT;
556   }
557   return iResult;
558 }
559
560 int AliHLTTask::GetNofMatchingDataBlocks(const AliHLTTask* pConsumerTask) const
561 {
562   // see header file for function documentation
563   int iResult=0;
564   if (pConsumerTask) {
565     if (fpDataBuffer) {
566       iResult=fpDataBuffer->FindMatchingDataBlocks(pConsumerTask->GetComponent(), NULL);
567     } else {
568       HLTFatal("internal data buffer missing");
569       iResult=-EFAULT;
570     }
571   } else {
572     iResult=-EINVAL;
573   }
574   return iResult;
575 }
576
577 int AliHLTTask::GetNofMatchingDataTypes(const AliHLTTask* pConsumerTask) const
578 {
579   // see header file for function documentation
580   int iResult=0;
581   if (pConsumerTask) {
582     AliHLTComponent* pComponent=GetComponent();
583     if (!pComponent) {
584       // init ?
585       HLTError("component not initialized");
586       iResult=-EFAULT;
587     }
588     if (pComponent) {
589       iResult=pComponent->FindMatchingDataTypes(pConsumerTask->GetComponent(), NULL);
590     } else {
591       HLTFatal("task initialization failed");
592       iResult=-EFAULT;
593     }
594   } else {
595     iResult=-EINVAL;
596   }
597   return iResult;
598 }
599
600 int AliHLTTask::Subscribe(const AliHLTTask* pConsumerTask, AliHLTComponentBlockData* pBlockDesc, int iArraySize)
601 {
602   // see header file for function documentation
603   int iResult=0;
604   if (pConsumerTask) {
605     if (fpDataBuffer) {
606       iResult=fpDataBuffer->Subscribe(pConsumerTask->GetComponent(), pBlockDesc, iArraySize);
607     } else {
608       HLTFatal("internal data buffer missing");
609       iResult=-EFAULT;
610     }
611   } else {
612     iResult=-EINVAL;
613   }
614   return iResult;
615 }
616
617 int AliHLTTask::Release(AliHLTComponentBlockData* pBlockDesc, const AliHLTTask* pConsumerTask)
618 {
619   // see header file for function documentation
620   int iResult=0;
621   if (pConsumerTask && pBlockDesc) {
622     if (fpDataBuffer) {
623       iResult=fpDataBuffer->Release(pBlockDesc, pConsumerTask->GetComponent());
624     } else {
625       HLTFatal("internal data buffer missing");
626       iResult=-EFAULT;
627     }
628   } else {
629     iResult=-EINVAL;
630   }
631   return iResult;
632 }
633
634 void AliHLTTask::PrintStatus()
635 {
636   // see header file for function documentation
637   HLTLogKeyword("task properties");
638   AliHLTComponent* pComponent=GetComponent();
639   if (pComponent) {
640     HLTMessage("     component: %s (%p)", pComponent->GetComponentID(), pComponent);
641   } else {
642     HLTMessage("     no component set!");
643   }
644   if (fpConfiguration) {
645     AliHLTConfiguration* pSrc=fpConfiguration->GetFirstSource();
646     while (pSrc) {
647       const char* pQualifier="unresolved";
648       if (FindDependency(pSrc->GetName()))
649         pQualifier="resolved";
650       HLTMessage("     source: %s (%s)", pSrc->GetName(), pQualifier);
651       pSrc=fpConfiguration->GetNextSource();
652     }
653     TObjLink* lnk = fListTargets.FirstLink();
654     while (lnk) {
655       TObject *obj = lnk->GetObject();
656       HLTMessage("     target: %s", obj->GetName());
657       lnk = lnk->Next();
658     }
659   } else {
660     HLTMessage("     task \"%s\" not initialized", GetName());
661   }
662 }