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

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