source: trunk/MagicSoft/Mars/mbase/MTaskList.cc@ 3500

Last change on this file since 3500 was 3497, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 23.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2004
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MTaskList
28//
29// Collection of tasks.
30//
31// A tasklist is necessary to run the eventloop. It contains the scheduled
32// tasks, which should be executed in your program.
33//
34// To add a task use AddToList.
35//
36// The tasklist itself is a task, too. You can add a tasklist to another
37// tasklist. This makes sense, if you want to filter the execution of
38// more than one task of your tasklist using the same filter.
39//
40// The tasks in the list are idetified by their names. If more than one
41// task has the same name, the tasklist will still work correctly, but
42// you might run into trouble trying to get a pointer to a task by name
43// from the list.
44//
45// Warning:
46// Be carefull if you are writing your tasklist
47// (eg. MWriteRootFile("file.root", "MTaskList")) to a file. You may
48// not be able to initialize a new working tasklist from a file if
49// a) Two Paramerer containers with the same names are existing in the
50// MParList.
51// b) You used a container somewhere which is not part of MParList.
52// (eg. You specified a pointer to a MH container in MFillH which is
53// not added to the parameter list.
54//
55/////////////////////////////////////////////////////////////////////////////
56#include "MTaskList.h"
57
58#include <fstream> // ofstream, SavePrimitive
59
60#include <TSystem.h> // gSystem
61#include <TOrdCollection.h> // TOrdCollection
62
63#include "MLog.h"
64#include "MLogManip.h"
65
66#include "MIter.h"
67#include "MFilter.h"
68#include "MParList.h"
69#include "MInputStreamID.h"
70
71#include "MStatusDisplay.h"
72
73ClassImp(MTaskList);
74
75using namespace std;
76
77const TString MTaskList::gsDefName = "MTaskList";
78const TString MTaskList::gsDefTitle = "A list for tasks to be executed";
79
80// --------------------------------------------------------------------------
81//
82// the name for the task list must be the same for all task lists
83// because the task list (at the moment) is identified by exactly
84// this name in the parameter list (by MEvtLoop::SetParList)
85//
86MTaskList::MTaskList(const char *name, const char *title)
87{
88 fName = name ? name : gsDefName.Data();
89 fTitle = title ? title : gsDefTitle.Data();
90
91 fTasks = new TList;
92
93 gROOT->GetListOfCleanups()->Add(fTasks);
94 gROOT->GetListOfCleanups()->Add(&fTasksProcess);
95 fTasks->SetBit(kMustCleanup);
96 fTasksProcess.SetBit(kMustCleanup);
97}
98
99// --------------------------------------------------------------------------
100//
101// CopyConstructor
102// creates a new TaskList and put the contents of an existing
103// TaskList in the new TaskList.
104//
105MTaskList::MTaskList(MTaskList &ts)
106{
107 fTasks->AddAll(ts.fTasks);
108}
109
110// --------------------------------------------------------------------------
111//
112// If the 'IsOwner' bit is set (via SetOwner()) all tasks are deleted
113// by the destructor
114//
115MTaskList::~MTaskList()
116{
117 if (TestBit(kIsOwner))
118 fTasks->SetOwner();
119
120 delete fTasks;
121}
122
123// --------------------------------------------------------------------------
124//
125// If the 'IsOwner' bit is set (via SetOwner()) all containers are deleted
126// by the destructor
127//
128void MTaskList::SetOwner(Bool_t enable)
129{
130 enable ? SetBit(kIsOwner) : ResetBit(kIsOwner);
131}
132
133
134// --------------------------------------------------------------------------
135//
136// Set the logging stream for the all tasks in the list and the tasklist
137// itself.
138//
139void MTaskList::SetLogStream(MLog *log)
140{
141 fTasks->ForEach(MTask, SetLogStream)(log);
142 MTask::SetLogStream(log);
143}
144
145// --------------------------------------------------------------------------
146//
147// Set the display for the all tasks in the list and the tasklist itself.
148//
149void MTaskList::SetDisplay(MStatusDisplay *d)
150{
151 fTasks->ForEach(MTask, SetDisplay)(d);
152 MTask::SetDisplay(d);
153}
154
155// --------------------------------------------------------------------------
156//
157// Set the serial number for the all tasks in the list and the tasklist
158// itself.
159//
160void MTaskList::SetSerialNumber(Byte_t num)
161{
162 fTasks->ForEach(MTask, SetSerialNumber)(num);
163 MTask::SetSerialNumber(num);
164}
165
166Bool_t MTaskList::CheckAddToList(MTask *task, const char *type, const MTask *where) const
167{
168 //
169 // Sanity check
170 //
171 if (!task)
172 {
173 *fLog << err << "ERROR - task argument=NULL." << endl;
174 return kFALSE;
175 }
176
177 //
178 // Get Name of new task
179 //
180 const char *name = task->GetName();
181
182 //
183 // Check if the new task is already existing in the list
184 //
185 const TObject *objn = fTasks->FindObject(name);
186 const TObject *objt = fTasks->FindObject(task);
187
188 if (objn || objt)
189 {
190 //
191 // If the task is already in the list ignore it.
192 //
193 if (objt || objn==task)
194 {
195 *fLog << warn << dbginf << "Warning: Task '" << task->GetName() << ", 0x" << (void*)task;
196 *fLog << "' already existing in '" << GetName() << "'... ignoring." << endl;
197 return kTRUE;
198 }
199
200 //
201 // Otherwise add it to the list, but print a warning message
202 //
203 *fLog << warn << dbginf << "Warning: Task '" << task->GetName();
204 *fLog << "' already existing in '" << GetName() << "'." << endl;
205 *fLog << "You may not be able to get a pointer to this task by name." << endl;
206 }
207
208 if (!where)
209 return kTRUE;
210
211 if (fTasks->FindObject(where))
212 return kTRUE;
213
214 *fLog << err << dbginf << "Error: Cannot find task after which the new task should be scheduled!" << endl;
215 return kFALSE;
216}
217
218
219// --------------------------------------------------------------------------
220//
221// schedule task for execution, before 'where'.
222// 'type' is the event type which should be processed
223//
224Bool_t MTaskList::AddToListBefore(MTask *task, const MTask *where, const char *type)
225{
226 // FIXME: We agreed to put the task into list in an ordered way.
227 if (!CheckAddToList(task, type, where))
228 return kFALSE;
229
230 *fLog << inf << "Adding " << task->GetName() << " to " << GetName() << " for " << type << "... " << flush;
231 task->SetStreamId(type);
232 task->SetBit(kMustCleanup);
233 fTasks->AddBefore((TObject*)where, task);
234 *fLog << "Done." << endl;
235
236 return kTRUE;
237}
238
239// --------------------------------------------------------------------------
240//
241// schedule task for execution, after 'where'.
242// 'type' is the event type which should be processed
243//
244Bool_t MTaskList::AddToListAfter(MTask *task, const MTask *where, const char *type)
245{
246 // FIXME: We agreed to put the task into list in an ordered way.
247
248 if (!CheckAddToList(task, type, where))
249 return kFALSE;
250
251 *fLog << inf << "Adding " << task->GetName() << " to " << GetName() << " for " << type << "... " << flush;
252 task->SetStreamId(type);
253 task->SetBit(kMustCleanup);
254 fTasks->AddAfter((TObject*)where, task);
255 *fLog << "Done." << endl;
256
257 return kTRUE;
258}
259
260// --------------------------------------------------------------------------
261//
262// schedule task for execution, 'type' is the event type which should
263// be processed
264//
265Bool_t MTaskList::AddToList(MTask *task, const char *type)
266{
267 // FIXME: We agreed to put the task into list in an ordered way.
268
269 if (!CheckAddToList(task, type))
270 return kFALSE;
271
272 *fLog << inf << "Adding " << task->GetName() << " to " << GetName() << " for " << type << "... " << flush;
273 task->SetStreamId(type);
274 task->SetBit(kMustCleanup);
275 fTasks->Add(task);
276 *fLog << "Done." << endl;
277
278 return kTRUE;
279}
280
281// --------------------------------------------------------------------------
282//
283// Find an object in the list.
284// 'name' is the name of the object you are searching for.
285//
286TObject *MTaskList::FindObject(const char *name) const
287{
288 return fTasks->FindObject(name);
289}
290
291// --------------------------------------------------------------------------
292//
293// check if the object is in the list or not
294//
295TObject *MTaskList::FindObject(const TObject *obj) const
296{
297 return fTasks->FindObject(obj);
298}
299
300// --------------------------------------------------------------------------
301//
302// do reinit of all tasks in the task-list
303//
304Bool_t MTaskList::ReInit(MParList *pList)
305{
306 *fLog << all << "Reinit... " << flush;
307
308 if (!pList)
309 pList = fParList;
310
311 //
312 // Make sure, that the ReadyToSave flag is not reset from a tasklist
313 // running as a task in another tasklist.
314 //
315 const Bool_t noreset = pList->TestBit(MParList::kDoNotReset);
316 if (!noreset)
317 pList->SetBit(MParList::kDoNotReset);
318
319 //
320 // create the Iterator over the tasklist
321 //
322 TIter Next(fTasks);
323
324 MTask *task=NULL;
325
326 //
327 // loop over all tasks for reinitialization
328 //
329 while ((task=(MTask*)Next()))
330 {
331 *fLog << all << task->GetName() << "... " << flush;
332
333 if (!task->ReInit(pList/*?pList:fParList*/))
334 {
335 *fLog << err << "ERROR - ReInit of Task '" << task->GetDescriptor() << "' failed." << endl;
336 return kFALSE;
337 }
338 }
339
340 *fLog << all << endl;
341
342 //
343 // Reset the ReadyToSave flag.
344 //
345 if (!noreset)
346 {
347 pList->SetReadyToSave(kFALSE);
348 pList->ResetBit(MParList::kDoNotReset);
349 }
350
351 return kTRUE;
352}
353
354// --------------------------------------------------------------------------
355//
356// removes a task from the list (used in PreProcess).
357// if kIsOwner is set the task is deleted. (see SetOwner())
358//
359void MTaskList::Remove(MTask *task)
360{
361 TObject *obj = fTasks->Remove(task);
362
363 if (TestBit(kIsOwner))
364 delete obj;
365}
366
367// --------------------------------------------------------------------------
368//
369// do pre processing (before eventloop) of all tasks in the task-list
370// Only if a task overwrites the Process function the task is
371// added to the fTaskProcess-List. This makes the execution of the
372// tasklist a little bit (only a little bit) faster, bacause tasks
373// doing no Processing are not Processed.
374//
375Int_t MTaskList::PreProcess(MParList *pList)
376{
377 *fLog << all << "Preprocessing... " << flush;
378 if (fDisplay)
379 {
380 // Set status lines
381 fDisplay->SetStatusLine1("PreProcessing...");
382 fDisplay->SetStatusLine2("");
383 }
384
385 fParList = pList;
386
387 //
388 // Make sure, that the ReadyToSave flag is not reset from a tasklist
389 // running as a task in another tasklist.
390 //
391 const Bool_t noreset = fParList->TestBit(MParList::kDoNotReset);
392 if (!noreset)
393 fParList->SetBit(MParList::kDoNotReset);
394
395 //
396 // create the Iterator over the tasklist
397 //
398 TIter Next(fTasks);
399
400 MTask *task=NULL;
401
402 //
403 // loop over all tasks for preproccesing
404 //
405 while ((task=(MTask*)Next()))
406 {
407 //
408 // PreProcess the task and check for it's return value.
409 //
410 switch (task->CallPreProcess(fParList))
411 {
412 case kFALSE:
413 return kFALSE;
414
415 case kTRUE:
416 // Handle GUI events (display changes, mouse clicks)
417 if (fDisplay)
418 gSystem->ProcessEvents();
419 continue;
420
421 case kSKIP:
422 Remove(task);
423 continue;
424 }
425
426 *fLog << err << dbginf << "PreProcess of " << task->GetDescriptor();
427 *fLog << " returned an unknown value... aborting." << endl;
428 return kFALSE;
429 }
430
431 *fLog << all << endl;
432
433 //
434 // Reset the ReadyToSave flag.
435 //
436 if (!noreset)
437 {
438 fParList->SetReadyToSave(kFALSE);
439 fParList->ResetBit(MParList::kDoNotReset);
440 }
441
442 //
443 // loop over all tasks to fill fTasksProcess
444 //
445 Next.Reset();
446 fTasksProcess.Clear();
447 while ((task=(MTask*)Next()))
448 if (task->OverwritesProcess())
449 fTasksProcess.Add(task);
450
451 return kTRUE;
452}
453
454// --------------------------------------------------------------------------
455//
456// do the event execution of all tasks in the task-list
457//
458Int_t MTaskList::Process()
459{
460 //
461 // Check whether there is something which can be processed, otherwise
462 // stop the eventloop.
463 //
464 if (fTasksProcess.GetSize()==0)
465 {
466 *fLog << warn << "Warning: No entries in " << GetDescriptor() << " for Processing." << endl;
467 return kFALSE;
468 }
469
470 //
471 // Reset the ReadyToSave flag.
472 // Reset all containers.
473 //
474 // Make sure, that the parameter list is not reset from a tasklist
475 // running as a task in another tasklist.
476 //
477 const Bool_t noreset = fParList->TestBit(MParList::kIsProcessing);
478 if (!noreset)
479 {
480 fParList->SetBit(MParList::kIsProcessing);
481 fParList->Reset();
482 }
483
484 //
485 // create the Iterator for the TaskList
486 //
487 TIter Next(&fTasksProcess);
488 MTask *task=NULL;
489
490 //
491 // loop over all tasks for processing
492 //
493 Bool_t rc = kTRUE;
494 while ( (task=(MTask*)Next()) )
495 {
496 //
497 // if the task has the wrong stream id skip it.
498 //
499 if (GetStreamId() != task->GetStreamId() &&
500 task->GetStreamId() != "All")
501 continue;
502
503 //
504 // if it has the right stream id execute the CallProcess() function
505 // and check what the result of it is.
506 // The CallProcess() function increases the execution counter and
507 // calls the Process() function dependent on the existance and
508 // return value of a filter.
509 //
510 switch (task->CallProcess())
511 {
512 case kTRUE:
513 //
514 // everything was OK: go on with the next task
515 //
516 continue;
517
518 case kFALSE:
519 //
520 // an error occured: stop eventloop
521 //
522 rc = kFALSE;
523 *fLog << inf << task->GetDescriptor() << " has stopped execution of " << GetDescriptor() << "." << endl;
524 break;
525
526 case kERROR:
527 //
528 // an error occured: stop eventloop and return: failed
529 //
530 *fLog << err << dbginf << "Fatal error occured... stopped." << endl;
531 rc = kERROR;
532 break;
533
534 case kCONTINUE:
535 //
536 // something occured: skip the rest of the tasks for this event
537 //
538 rc = kTRUE;
539 break;
540
541 default:
542 *fLog << warn << dbginf << "Unknown return value from MTask::Process()... ignored." << endl;
543 continue;
544 }
545 break;
546 }
547
548 if (!noreset)
549 {
550 fParList->SetReadyToSave(kFALSE);
551 fParList->ResetBit(MParList::kIsProcessing);
552 }
553
554 return rc;
555}
556
557// --------------------------------------------------------------------------
558//
559// do post processing (before eventloop) of all tasks in the task-list
560// only tasks which have successfully been preprocessed are postprocessed.
561//
562Int_t MTaskList::PostProcess()
563{
564 *fLog << all << "Postprocessing... " << flush;
565 if (fDisplay)
566 {
567 // Set status lines
568 fDisplay->SetStatusLine1("PostProcessing...");
569 fDisplay->SetStatusLine2("");
570 }
571
572 //
573 // Make sure, that the ReadyToSave flag is not reset from a tasklist
574 // running as a task in another tasklist.
575 //
576 const Bool_t noreset = fParList->TestBit(MParList::kDoNotReset);
577 if (!noreset)
578 {
579 fParList->SetBit(MParList::kDoNotReset);
580 fParList->Reset();
581 }
582
583 //
584 // create the Iterator for the TaskList
585 //
586 TIter Next(fTasks);
587
588 MTask *task=NULL;
589
590 //
591 // loop over all tasks for postprocessing
592 // only tasks which have successfully been preprocessed are postprocessed.
593 //
594 while ( (task=(MTask*)Next()) )
595 {
596 if (!task->CallPostProcess())
597 return kFALSE;
598
599 // Handle GUI events (display changes, mouse clicks)
600 if (fDisplay)
601 gSystem->ProcessEvents();
602 }
603
604 *fLog << all << endl;
605
606 //
607 // Reset the ReadyToSave flag.
608 //
609 if (!noreset)
610 {
611 fParList->SetReadyToSave(kFALSE);
612 fParList->ResetBit(MParList::kDoNotReset);
613 }
614
615 return kTRUE;
616}
617
618// --------------------------------------------------------------------------
619//
620// Prints the number of times all the tasks in the list has been.
621// For convinience the lvl argument results in a number of spaces at the
622// beginning of the line. So that the structur of a tasklist can be
623// identified. If a Tasklist or task has filter applied the name of the
624// filter is printer in <>-brackets behind the number of executions.
625// Use MTaskList::PrintStatistics without an argument.
626//
627void MTaskList::PrintStatistics(const Int_t lvl, Bool_t title, Double_t time) const
628{
629 if (lvl==0)
630 {
631 *fLog << all << underline << "Process execution Statistics:" << endl;
632 *fLog << GetDescriptor();
633 if (GetFilter())
634 *fLog << " <" << GetFilter()->GetName() << ">";
635 if (title)
636 *fLog << "\t" << fTitle;
637 *fLog << endl;
638 }
639 else
640 MTask::PrintStatistics(lvl, title, time);
641
642 //
643 // create the Iterator for the TaskList
644 //
645 fTasks->ForEach(MTask, PrintStatistics)(lvl+1, title, GetCpuTime());
646
647 if (lvl==0)
648 *fLog << endl;
649}
650
651// --------------------------------------------------------------------------
652//
653// Call 'Print()' of all tasks
654//
655void MTaskList::Print(Option_t *t) const
656{
657 *fLog << all << underline << GetDescriptor() << ":" << endl;
658
659 fTasks->Print();
660
661 *fLog << endl;
662}
663
664// --------------------------------------------------------------------------
665//
666// Implementation of SavePrimitive. Used to write the call to a constructor
667// to a macro. In the original root implementation it is used to write
668// gui elements to a macro-file.
669//
670void MTaskList::StreamPrimitive(ofstream &out) const
671{
672 out << " MTaskList " << GetUniqueName();
673 if (fName!=gsDefName || fTitle!=gsDefTitle)
674 {
675 out << "(\"" << fName << "\"";
676 if (fTitle!=gsDefTitle)
677 out << ", \"" << fTitle << "\"";
678 out <<")";
679 }
680 out << ";" << endl << endl;
681
682 MIter Next(fTasks);
683
684 MParContainer *cont = NULL;
685 while ((cont=Next()))
686 {
687 cont->SavePrimitive(out, "");
688 out << " " << GetUniqueName() << ".AddToList(&";
689 out << cont->GetUniqueName() << ");" << endl << endl;
690 }
691}
692
693void MTaskList::GetNames(TObjArray &arr) const
694{
695 MParContainer::GetNames(arr);
696 fTasks->ForEach(MParContainer, GetNames)(arr);
697}
698
699void MTaskList::SetNames(TObjArray &arr)
700{
701 MParContainer::SetNames(arr);
702 fTasks->ForEach(MParContainer, SetNames)(arr);
703}
704
705// --------------------------------------------------------------------------
706//
707// Read the contents/setup of a parameter container/task from a TEnv
708// instance (steering card/setup file).
709// The key to search for in the file should be of the syntax:
710// prefix.vname
711// While vname is a name which is specific for a single setup date
712// (variable) of this container and prefix is something like:
713// evtloopname.name
714// While name is the name of the containers/tasks in the parlist/tasklist
715//
716// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
717// Job4.MImgCleanStd.CleaningLevel2: 2.5
718//
719// If this cannot be found the next step is to search for
720// MImgCleanStd.CleaningLevel1: 3.0
721// And if this doesn't exist, too, we should search for:
722// CleaningLevel1: 3.0
723//
724// Warning: The programmer is responsible for the names to be unique in
725// all Mars classes.
726//
727Bool_t MTaskList::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
728{
729 if (print)
730 *fLog << all << "MTaskList::ReadEnv: " << prefix << " (" << (int)print << ")" << endl;
731
732 MParContainer *cont = NULL;
733
734 MIter Next(fTasks);
735 while ((cont=Next()))
736 {
737 if (cont->InheritsFrom("MTaskList"))
738 {
739 if (cont->ReadEnv(env, prefix, print)==kERROR)
740 return kERROR;
741 continue;
742 }
743
744 // Check For: Job4.ContainerName.Varname
745 if (print)
746 *fLog << all << "Testing: " << prefix+cont->GetName() << endl;
747 Bool_t rc = cont->ReadEnv(env, prefix+cont->GetName(), print);
748 if (rc==kERROR)
749 return kERROR;
750 if (rc==kTRUE)
751 continue;
752
753 // Check For: Job4.MClassName.Varname
754 if (print)
755 *fLog << all << "Testing: " << prefix+cont->ClassName() << endl;
756 rc = cont->ReadEnv(env, prefix+cont->ClassName(), print);
757 if (rc==kERROR)
758 return kERROR;
759 if (rc==kTRUE)
760 continue;
761
762 // Check For: ContainerName.Varname
763 if (print)
764 *fLog << all << "Testing: " << cont->GetName() << endl;
765 rc = cont->ReadEnv(env, cont->GetName(), print);
766 if (rc==kERROR)
767 return kERROR;
768 if (rc==kTRUE)
769 continue;
770
771 // Check For: MClassName.Varname
772 if (print)
773 *fLog << all << "Testing: " << cont->ClassName() << endl;
774 rc = cont->ReadEnv(env, cont->ClassName(), print);
775 if (rc==kERROR)
776 return kERROR;
777 if (rc==kTRUE)
778 continue;
779 }
780
781 return kTRUE;
782}
783
784// --------------------------------------------------------------------------
785//
786// Write the contents/setup of a parameter container/task to a TEnv
787// instance (steering card/setup file).
788// The key to search for in the file should be of the syntax:
789// prefix.vname
790// While vname is a name which is specific for a single setup date
791// (variable) of this container and prefix is something like:
792// evtloopname.name
793// While name is the name of the containers/tasks in the parlist/tasklist
794//
795// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
796// Job4.MImgCleanStd.CleaningLevel2: 2.5
797//
798// If this cannot be found the next step is to search for
799// MImgCleanStd.CleaningLevel1: 3.0
800// And if this doesn't exist, too, we should search for:
801// CleaningLevel1: 3.0
802//
803// Warning: The programmer is responsible for the names to be unique in
804// all Mars classes.
805//
806Bool_t MTaskList::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
807{
808 MParContainer *cont = NULL;
809
810 MIter Next(fTasks);
811 while ((cont=Next()))
812 if (!cont->WriteEnv(env, prefix, print))
813 return kFALSE;
814 return kTRUE;
815}
816
817// --------------------------------------------------------------------------
818//
819// Removes a task from the tasklist. Returns kFALSE if the object was not
820// found in the list.
821//
822Bool_t MTaskList::RemoveFromList(MTask *task)
823{
824 TObject *obj = fTasks->Remove(task);
825
826 //
827 // If the task was found in the list try to remove it from the second
828 // list, too.
829 //
830 if (obj)
831 fTasksProcess.Remove(task);
832
833 return obj ? kTRUE : kFALSE;
834
835}
Note: See TracBrowser for help on using the repository browser.