DABC (Data Acquisition Backbone Core)  2.9.9
Application.cxx
Go to the documentation of this file.
1 // $Id: Application.cxx 4476 2020-04-15 14:12:38Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/Application.h"
17 
18 #include <cstring>
19 
20 #include "dabc/Manager.h"
21 #include "dabc/Configuration.h"
22 #include "dabc/Url.h"
23 
24 dabc::Application::Application(const char* classname) :
26  fAppClass(classname ? classname : typeApplication),
27  fInitFunc(0),
28  fAnyModuleWasRunning(false),
29  fSelfControl(true),
30  fAppDevices(),
31  fAppPools(),
32  fAppModules()
33 {
34  CreatePar(StateParName(), "state").SetSynchron(true, -1, true);
35 
40 
42 
43  fSelfControl = Cfg("self").AsBool(true);
44 
45  fConnTimeout = Cfg("ConnTimeout").AsDouble(5);
46 
47  PublishPars("$CONTEXT$/App");
48 }
49 
51 {
52 }
53 
55 {
56  if (fSelfControl)
57  Submit(dabc::CmdStateTransition(stRunning()));
58 }
59 
61 {
63 }
64 
65 
67 {
68  Command statecmd = cmd.GetRef("StateCmd");
69  if (statecmd.null()) return dabc::Worker::ReplyCommand(cmd);
70 
71  // this is finish of modules connection - we should complete state transition
72  std::string tgtstate = cmd.GetStr("StateCmdTarget");
73  int res = cmd.GetResult();
74 
75  if (tgtstate == stRunning() && (res == cmd_true)) {
76  if (!StartModules()) res = cmd_false;
77  // use timeout to control if application should be shutdown
78  if ((res==cmd_true) && fSelfControl) ActivateTimeout(0.2);
79  }
80 
81  if (res==cmd_true) SetAppState(tgtstate);
82  if (res==cmd_false) SetAppState(stFailure());
83 
84  statecmd.Reply(res);
85  return true;
86 }
87 
88 
90 {
91  if (cmd.IsName(CmdStateTransition::CmdName()))
92  return DoTransition(cmd.GetStr("State"), cmd);
93 
94  if (cmd.IsName(stcmdDoConfigure()))
95  return DoTransition(stReady(), cmd);
96 
97  if (cmd.IsName(stcmdDoStart()))
98  return DoTransition(stRunning(), cmd);
99 
100  if (cmd.IsName(stcmdDoStop()))
101  return DoTransition(stReady(), cmd);
102 
103  if (cmd.IsName(stcmdDoHalt()))
104  return DoTransition(stHalted(), cmd);
105 
106  if (cmd.IsName("AddAppObject")) {
107  if (cmd.GetStr("kind") == "device")
108  fAppDevices.push_back(cmd.GetStr("name"));
109  else
110  if (cmd.GetStr("kind") == "pool")
111  fAppPools.push_back(cmd.GetStr("name"));
112  else
113  if (cmd.GetStr("kind") == "module")
114  fAppModules.push_back(cmd.GetStr("name"));
115  else
116  return cmd_false;
117 
118  return cmd_true;
119  }
120 
121  if (cmd.IsName("StartAllModules") || cmd.IsName(CmdStartModule::CmdName())) {
122  StartModules();
123  return cmd_true;
124  }
125 
126  if (cmd.IsName("StopAllModules") || cmd.IsName(CmdStopModule::CmdName())) {
127  StopModules();
128  return cmd_true;
129  }
130 
131  return dabc::Worker::ExecuteCommand(cmd);
132 }
133 
134 
135 void dabc::Application::SetInitFunc(ExternalFunction* initfunc)
136 {
137  fInitFunc = initfunc;
138 }
139 
140 void dabc::Application::SetAppState(const std::string &name)
141 {
142  SetParValue(StateParName(), name);
143  if (name == stFailure()) DOUT0("Application switched to FAILURE state");
144 }
145 
146 int dabc::Application::DoTransition(const std::string &tgtstate, Command cmd)
147 {
148  std::string currstate = GetState();
149 
150  DOUT3("Doing transition curr %s tgt %s", currstate.c_str(), tgtstate.c_str());
151 
152  if (currstate == tgtstate) return cmd_true;
153 
154  // it is not allowed to change transition state - it is internal
155  if (currstate == stTransition()) return cmd_false;
156 
157  SetAppState(stTransition());
158 
159  int res = cmd_true;
160 
161  // in case of failure state always bring application into halted state first
162  if (currstate == stFailure()) {
163  res = CleanupApplication();
164  if (res) currstate = stHalted();
165  }
166 
167  if (tgtstate == stHalted()) {
168  if (currstate == stRunning()) res = cmd_bool(StopModules());
169  if (!CleanupApplication()) res = cmd_false;
170  } else
171  if (tgtstate == stReady()) {
172  if (currstate == stHalted()) res = CallInitFunc(cmd, tgtstate); else
173  if (currstate == stRunning()) res = cmd_bool(StopModules());
174  } else
175  if (tgtstate == stRunning()) {
176  if (currstate == stHalted()) {
177  res = CallInitFunc(cmd, tgtstate);
178  if (res == cmd_true) currstate = stReady();
179  }
180  if (currstate == stReady())
181  if (!StartModules()) res = cmd_false;
182 
183  // use timeout to control if application should be shutdown
184  if ((res==cmd_true) && fSelfControl) ActivateTimeout(0.2);
185 
186  } else
187  if (tgtstate == stFailure()) {
188  StopModules();
189  } else {
190  EOUT("Unsupported state name %s", tgtstate.c_str());
191  res = cmd_false;
192  }
193 
194  if (res==cmd_true) SetAppState(tgtstate);
195  if (res==cmd_false) SetAppState(stFailure());
196 
197  return res;
198 }
199 
201 {
202  if (!fSelfControl || (GetState() != stRunning())) return -1;
203 
204  if (IsModulesRunning()) { fAnyModuleWasRunning = true; return 0.2; }
205 
206  // if non modules was running, do not try automatic stop
207  if (!fAnyModuleWasRunning) return 0.2;
208 
209  // application decide to stop manager main loop
211 
212  return -1;
213 }
214 
215 
217 {
218  for (unsigned n=0;n<fAppModules.size();n++) {
219  ModuleRef m = dabc::mgr.FindModule(fAppModules[n]);
220  if (m.IsRunning()) return true;
221  }
222 
223  return false;
224 }
225 
226 
227 int dabc::Application::CallInitFunc(Command statecmd, const std::string &tgtstate)
228 {
229  if (fInitFunc) {
230  fInitFunc();
231  return cmd_true;
232  }
233 
234  // TODO: check that function is redefined
235  if (CreateAppModules()) return cmd_true;
236 
237  XMLNodePointer_t node = 0;
238  dabc::Configuration* cfg = dabc::mgr()->cfg();
239 
240  while (cfg->NextCreationNode(node, xmlDeviceNode, true)) {
241  const char* name = Xml::GetAttr(node, xmlNameAttr);
242  const char* clname = Xml::GetAttr(node, xmlClassAttr);
243  if ((name==0) || (clname==0)) continue;
244 
245  fAppDevices.push_back(name);
246 
247  if (!dabc::mgr.CreateDevice(clname, name)) {
248  EOUT("Fail to create device %s class %s", name, clname);
249  return cmd_false;
250  }
251  }
252 
253  while (cfg->NextCreationNode(node, xmlThreadNode, true)) {
254  const char* name = Xml::GetAttr(node, xmlNameAttr);
255  const char* clname = Xml::GetAttr(node, xmlClassAttr);
256  const char* devname = Xml::GetAttr(node, xmlDeviceAttr);
257  if (name==0) continue;
258  if (clname==0) clname = dabc::typeThread;
259  if (devname==0) devname = "";
260  DOUT2("Create thread %s", name);
261  dabc::mgr.CreateThread(name, clname, devname);
262  }
263 
264  while (cfg->NextCreationNode(node, xmlMemoryPoolNode, true)) {
265  const char* name = Xml::GetAttr(node, xmlNameAttr);
266  fAppPools.push_back(name);
267  DOUT2("Create memory pool %s", name);
268  if (!dabc::mgr.CreateMemoryPool(name)) {
269  EOUT("Fail to create memory pool %s", name);
270  return cmd_false;
271  }
272  }
273 
274  while (cfg->NextCreationNode(node, xmlModuleNode, true)) {
275  const char* name = Xml::GetAttr(node, xmlNameAttr);
276  const char* clname = Xml::GetAttr(node, xmlClassAttr);
277  const char* thrdname = Xml::GetAttr(node, xmlThreadAttr);
278  if (clname==0) continue;
279  if (thrdname==0) thrdname="";
280 
281  // check that module with such name exists
283  if (!m.null()) continue;
284 
285  // FIXME: for old xml files, remove after 12.2014
286  if (strcmp(clname, "dabc::Publisher")==0) continue;
287 
288  fAppModules.push_back(name);
289 
290  DOUT2("Create module %s class %s", name, clname);
291 
292  m = dabc::mgr.CreateModule(clname, name, thrdname);
293 
294  if (m.null()) {
295  EOUT("Fail to create module %s class %s", name, clname);
296  return cmd_false;
297  }
298 
299  for (unsigned n = 0; n < m.NumInputs(); n++) {
300 
301  PortRef port = m.FindPort(m.InputName(n, false));
302  if (!port.Cfg(xmlAutoAttr).AsBool(true)) continue;
303 
304  if (!dabc::mgr.CreateTransport(m.InputName(n))) {
305  EOUT("Cannot create input transport for port %s", m.InputName(n).c_str());
306  return cmd_false;
307  }
308  }
309 
310  for (unsigned n = 0; n < m.NumOutputs(); n++) {
311 
312  PortRef port = m.FindPort(m.OutputName(n, false));
313  if (!port.Cfg(xmlAutoAttr).AsBool(true)) continue;
314 
315  if (!dabc::mgr.CreateTransport(m.OutputName(n))) {
316  EOUT("Cannot create output transport for port %s", m.OutputName(n).c_str());
317  return cmd_false;
318  }
319  }
320  }
321 
322  int nconn = 0;
323 
324  while (cfg->NextCreationNode(node, xmlConnectionNode, false)) {
325 
326  const char* outputname = Xml::GetAttr(node, "output");
327  const char* inputname = Xml::GetAttr(node, "input");
328 
329  // output and input should always be specified
330  if ((outputname==0) || (inputname==0)) continue;
331 
332  const char* kind = Xml::GetAttr(node, "kind");
333  const char* lst = Xml::GetAttr(node, "list");
334 
335  if (kind && (strcmp(kind,"all-to-all")==0)) {
336  nconn++;
337  int numnodes = dabc::mgr.NumNodes();
338 
339  DOUT2("Create all-to-all connections for %d nodes", numnodes);
340 
341  for (int nsender=0; nsender<numnodes; nsender++)
342  for (int nreceiver=0;nreceiver<numnodes;nreceiver++) {
343  std::string port1 = dabc::Url::ComposePortName(nsender, dabc::format("%s/Output", outputname), nreceiver);
344 
345  std::string port2 = dabc::Url::ComposePortName(nreceiver, dabc::format("%s/Input", inputname), nsender);
346 
347  dabc::ConnectionRequest req = dabc::mgr.Connect(port1, port2);
348  req.SetConfigFromXml(node);
349  }
350  } else
351  if (lst && *lst) {
352  dabc::RecordField fld(cfg->ResolveEnv(lst));
353  std::vector<std::string> arr = fld.AsStrVect();
354  for (unsigned n = 0; n < arr.size(); ++n) {
355  std::string out = dabc::replace_all(cfg->ResolveEnv(outputname), "%name%", arr[n]),
356  inp = dabc::replace_all(cfg->ResolveEnv(inputname), "%name%", arr[n]),
357  id = dabc::format("%u", n);
358  out = dabc::replace_all(out, "%id%", id);
359  inp = dabc::replace_all(inp, "%id%", id);
360 
361  dabc::ConnectionRequest req = dabc::mgr.Connect(out, inp);
362  req.SetConfigFromXml(node);
363  if (!req.null()) nconn++;
364  }
365  } else {
366  dabc::ConnectionRequest req = dabc::mgr.Connect(outputname, inputname);
367  req.SetConfigFromXml(node);
368  if (!req.null()) nconn++;
369  }
370  }
371 
372  if (nconn==0) return cmd_true;
373 
374  dabc::Command cmd("ActivateConnections");
375  cmd.SetTimeout(fConnTimeout);
377 
378  cmd.SetRef("StateCmd", statecmd);
379  cmd.SetStr("StateCmdTarget", tgtstate);
380 
381  dabc::mgr.Submit(Assign(cmd));
382 
383  return cmd_postponed;
384 
385 // return cmd_bool(dabc::mgr.ActivateConnections(5));
386 }
387 
388 
390 {
391  for (unsigned n=0;n<fAppModules.size();n++)
392  dabc::mgr.StartModule(fAppModules[n]);
393 
394  return true;
395 }
396 
398 {
399  for (unsigned n=0;n<fAppModules.size();n++)
400  dabc::mgr.StopModule(fAppModules[n]);
401 
402  return true;
403 }
404 
406 {
407  for (unsigned n=0;n<fAppModules.size();n++)
408  dabc::mgr.DeleteModule(fAppModules[n]);
409 
410  for (unsigned n=0;n<fAppPools.size();n++)
411  dabc::mgr.DeletePool(fAppPools[n]);
412 
413  for (unsigned n=0;n<fAppDevices.size();n++)
414  dabc::mgr.DeleteDevice(fAppDevices[n]);
415 
416  fAppModules.clear();
417  fAppPools.clear();
418  fAppDevices.clear();
419 
420 /*
421  ReferencesVector vect;
422 
423  GetAllChildRef(&vect);
424 
425  while (vect.GetSize()>0) {
426  // by default, all workers are removed from the application
427  WorkerRef w = vect.TakeRef(0);
428  w.Destroy();
429  }
430 */
431  return true;
432 }
433 
434 
436 {
437  while (cfg.FindItem(xmlApplication)) {
438  // if application has non-default class name, one should check additionally class attribute
439  if ((strcmp(ClassName(), xmlApplication) == 0) ||
440  cfg.CheckAttr(xmlClassAttr, ClassName())) return true;
441  }
442 
443  return false;
444 }
445 
447 {
448  cont->Field(dabc::prop_kind).SetStr("DABC.Application");
449 }
450 
451 bool dabc::ApplicationRef::AddObject(const std::string &kind, const std::string &name)
452 {
453  dabc::Command cmd("AddAppObject");
454  cmd.SetStr("kind", kind);
455  cmd.SetStr("name", name);
456  return Execute(cmd);
457 }
bool AddObject(const std::string &kind, const std::string &name)
Adds object into application list List used when objects must be destroyed or application start/stop ...
virtual int DoTransition(const std::string &state, Command cmd)
Do action, required to make transition into specified state.
virtual int ExecuteCommand(Command cmd)
Main method where commands are executed.
Definition: Application.cxx:89
virtual bool IsModulesRunning()
Return true if all application-relevant modules are running.
static const char * stcmdDoHalt()
Definition: Application.h:93
virtual bool Find(ConfigIO &cfg)
Method to locate object in xml file.
virtual void OnThreadAssigned()
Method called at thread assignment - application may switch into running state.
Definition: Application.cxx:54
static const char * StateParName()
Definition: Application.h:161
static const char * stcmdDoStop()
Definition: Application.h:92
void SetInitFunc(ExternalFunction *initfunc)
Set external function, which creates all necessary components of the application.
virtual void BuildFieldsMap(RecordFieldsMap *cont)
Fill fields map, which is relevant for the object Objects hierarchy produced from dabc::Manager.
void SetAppState(const std::string &name)
Directly changes value of the state parameter.
Application(const char *classname=0)
Definition: Application.cxx:24
static const char * stHalted()
Definition: Application.h:83
bool fSelfControl
when true, application itself decide when stop main loop
Definition: Application.h:107
virtual bool StartModules()
Start all application modules.
virtual double ProcessTimeout(double)
Timeout used by application to control stop state of modules and brake application.
virtual bool ReplyCommand(Command cmd)
Reimplement this method to react on command reply Return true if command can be destroyed by framewor...
Definition: Application.cxx:66
virtual bool CleanupApplication()
Delete all components created in application, excluding state parameter.
double fConnTimeout
time for connecting all modules, default 5s
Definition: Application.h:109
virtual ~Application()
Definition: Application.cxx:50
static const char * stcmdDoConfigure()
Definition: Application.h:90
int CallInitFunc(Command statecmd, const std::string &tgtstate)
virtual bool StopModules()
Stop all application modules.
virtual void ObjectCleanup()
Cleanup application.
Definition: Application.cxx:60
static const char * stcmdDoStart()
Definition: Application.h:91
static const char * CmdName()
Definition: Manager.h:85
static const char * CmdName()
Definition: Manager.h:92
Represents command with its arguments.
Definition: Command.h:99
bool SetStr(const std::string &name, const char *value)
Definition: Command.h:134
std::string GetStr(const std::string &name, const std::string &dflt="") const
Definition: Command.h:136
Command & SetTimeout(double tm)
Set maximum time which can be used for command execution.
Definition: Command.cxx:108
Command & SetReceiver(const std::string &itemname)
These methods prepare command so, that one can submit command to the manager like: dabc::mgr....
Definition: Command.h:264
int GetResult() const
Definition: Command.h:174
Reference GetRef(const std::string &name)
Returns reference from the command, can be called only once.
Definition: Command.cxx:175
void Reply(int res=cmd_noresult)
Replied on the command.
Definition: Command.cxx:225
bool SetRef(const std::string &name, Reference ref)
Set reference to the command.
Definition: Command.cxx:168
std::string ResolveEnv(const std::string &arg, int id=-1)
Replaces entries like ${name} be variable value.
Definition: ConfigBase.cxx:440
Interface class between xml configuration and dabc objects.
Definition: ConfigIO.h:38
bool FindItem(const char *name)
Definition: ConfigIO.cxx:42
bool CheckAttr(const char *name, const char *value)
Check if item, found by FindItem routine, has attribute with specified value.
Definition: ConfigIO.cxx:63
Full-functional class to reading configuration from xml files.
Definition: Configuration.h:34
bool NextCreationNode(XMLNodePointer_t &prev, const char *nodename, bool check_name_for_multicast)
Method is used to find xml nodes like Module, MemoryPool, Connection in the xml file which should be ...
Connection request.
void SetConfigFromXml(XMLNodePointer_t node)
void StopApplication()
Definition: Manager.cxx:2231
ModuleRef CreateModule(const std::string &classname, const std::string &modulename, const std::string &thrdname="")
Definition: Manager.cxx:1981
ConnectionRequest Connect(const std::string &port1, const std::string &port2)
Request connection between two ports.
Definition: Manager.cxx:2138
int NumNodes() const
Definition: Manager.cxx:2091
ModuleRef FindModule(const std::string &name)
Definition: Manager.cxx:2018
ThreadRef CreateThread(const std::string &thrdname, const std::string &classname="", const std::string &devname="")
Definition: Manager.cxx:1988
static const char * ConnMgrName()
Definition: Manager.h:478
Reference on dabc::Module class
Definition: Module.h:275
bool IsRunning() const
Definition: Module.h:285
std::string OutputName(unsigned n=0, bool itemname=true)
Return item name of the output, can be used in connect command.
Definition: Module.cxx:1066
unsigned NumOutputs()
Returns number of outputs in the module.
Definition: Module.cxx:1049
unsigned NumInputs()
Returns number of inputs in the module.
Definition: Module.cxx:1043
PortRef FindPort(const std::string &name)
Return reference on the port.
Definition: Module.cxx:1031
std::string InputName(unsigned n=0, bool itemname=true)
Return item name of the input, can be used in connect command.
Definition: Module.cxx:1056
Parameter & SetSynchron(bool on, double interval=1., bool everyevnt=false)
Indicate if parameter is should generate events synchron with code which modified it.
Definition: Parameter.cxx:491
Reference on the dabc::Port class
Definition: Port.h:195
bool SetStr(const std::string &v)
Definition: Record.cxx:1127
std::vector< std::string > AsStrVect() const
Definition: Record.cxx:923
bool AsBool(bool dflt=false) const
Definition: Record.cxx:477
double AsDouble(double dflt=0.) const
Definition: Record.cxx:549
RecordField & Field(const std::string &name)
Direct access to the fields.
Definition: Record.h:401
bool IsName(const char *name) const
Returns true if object name is the same as specified one.
Definition: Reference.cxx:177
bool null() const
Returns true if reference contains nullptr.
Definition: Reference.h:151
static std::string ComposePortName(int nodeid, const std::string &fullportname, int portid=-1)
! Method creates url string with port address, which includes nodeid and full portname If optional pa...
Definition: Url.cxx:154
RecordField Cfg(const std::string &name, Command cmd=nullptr) const
Returns configuration record of specified name.
Definition: Worker.h:482
bool Submit(Command cmd)
Definition: Worker.cxx:1139
Active object, which is working inside dabc::Thread.
Definition: Worker.h:116
CommandDefinition CreateCmdDef(const std::string &name)
Definition: Worker.cxx:603
RecordField Cfg(const std::string &name, Command cmd=nullptr) const
Returns configuration field of specified name Configuration value of specified name searched in follo...
Definition: Worker.cxx:521
virtual int ExecuteCommand(Command cmd)
Main method where commands are executed.
Definition: Worker.cxx:851
virtual bool PublishPars(const std::string &path)
Definition: Worker.cxx:1081
virtual bool ReplyCommand(Command cmd)
Reimplement this method to react on command reply Return true if command can be destroyed by framewor...
Definition: Worker.cxx:856
virtual void ObjectCleanup()
Central cleanup method for worker.
Definition: Worker.cxx:238
virtual Parameter CreatePar(const std::string &name, const std::string &kind="")
Definition: Worker.cxx:558
#define DOUT2(args ...)
Definition: logging.h:170
#define DOUT0(args ...)
Definition: logging.h:156
#define DOUT3(args ...)
Definition: logging.h:176
#define EOUT(args ...)
Definition: logging.h:150
const char * GetAttr(XMLNodePointer_t xmlnode, const char *name)
Definition: XmlEngine.cxx:411
Event manipulation API.
Definition: api.h:23
std::string replace_all(const std::string &str, const std::string &match, const std::string &replace)
Replace all matches in the string.
Definition: string.cxx:237
void * XMLNodePointer_t
Definition: XmlEngine.h:25
const char * xmlDeviceAttr
Definition: ConfigBase.cxx:37
ManagerRef mgr
Definition: Manager.cxx:42
std::string format(const char *fmt,...)
Definition: string.cxx:49
const char * xmlAppDfltName
Definition: ConfigBase.cxx:31
const char * xmlAutoAttr
Definition: ConfigBase.cxx:43
const char * xmlApplication
Definition: ConfigBase.cxx:30
const char * xmlConnectionNode
Definition: Object.cxx:34
const char * prop_kind
Definition: Hierarchy.cxx:29
const char * xmlThreadAttr
Definition: ConfigBase.cxx:38
const char * xmlMemoryPoolNode
Definition: Object.cxx:32
const char * typeThread
Definition: Object.cxx:77
const char * xmlModuleNode
Definition: Object.cxx:33
const char * xmlClassAttr
Definition: ConfigBase.cxx:36
const char * xmlNameAttr
Definition: ConfigBase.cxx:33
const char * xmlDeviceNode
Definition: Object.cxx:30
const char * xmlThreadNode
Definition: Object.cxx:31
@ cmd_postponed
Definition: Command.h:42
@ cmd_false
Definition: Command.h:37
@ cmd_true
Definition: Command.h:38
const char * typeApplication
Definition: Object.cxx:81