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

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