DABC (Data Acquisition Backbone Core)  2.9.9
Worker.cxx
Go to the documentation of this file.
1 // $Id: Worker.cxx 4764 2021-04-23 07:01:04Z 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/Worker.h"
17 
18 #include <cstdlib>
19 #include <cmath>
20 
21 #include "dabc/Manager.h"
22 #include "dabc/Publisher.h"
23 #include "dabc/HierarchyStore.h"
24 #include "dabc/Url.h"
25 #include "dabc/defines.h"
26 
27 dabc::WorkerAddon::WorkerAddon(const std::string &name) :
28  Object(0, name),
29  fWorker()
30 {
31  SetFlag(flAutoDestroy, true);
32 }
33 
35 {
36 }
37 
38 
40 {
41  fWorker.Release();
42 }
43 
45 {
46  if (fWorker.null()) DeleteThis();
47  else fWorker.Destroy();
48 }
49 
51 {
52  if (fWorker.null()) DeleteThis();
53  else SubmitWorkerCmd(dabc::Command("DeleteAddon"));
54 }
55 
56 void dabc::WorkerAddon::FireWorkerEvent(unsigned evid)
57 {
58  dabc::Worker* wrk = (dabc::Worker*) fWorker();
59  if (wrk) wrk->FireEvent(evid);
60 }
61 
62 bool dabc::WorkerAddon::ActivateTimeout(double tmout_sec)
63 {
64  dabc::Worker* wrk = (dabc::Worker*) fWorker();
65 
66  if (wrk==0) return false;
67 
68  LockGuard lock(wrk->fThreadMutex);
69 
70  return wrk->fThread._ActivateAddonTimeout(wrk->fWorkerId, wrk->WorkerPriority(), tmout_sec);
71 }
72 
73 void dabc::WorkerAddon::SubmitWorkerCmd(Command cmd)
74 {
75  dabc::Worker* wrk = (dabc::Worker*) fWorker();
76 
77  if (wrk) wrk->Submit(cmd);
78 }
79 
80 // ================================================================================
81 
82 
83 dabc::Worker::Worker(Reference parent, const std::string &name) :
84  Object(parent, name),
85  fThread(),
86  fAddon(),
87  fPublisher(),
88  fWorkerId(0),
89  fWorkerPriority(-1), // minimum priority per default
90 
91  fThreadMutex(0),
92  fWorkerActive(false),
93  fWorkerFiredEvents(0),
94 
95  fWorkerCommands(CommandsQueue::kindNone),
96 
97  fWorkerCommandsLevel(0),
98  fWorkerHierarchy(),
99  fWorkerCfgId(-1)
100 {
101  SetFlag(flHasThread, false);
102 
103 #ifdef DABC_EXTRA_CHECKS
104  DebugObject("Worker", this, 10);
105 #endif
106 }
107 
108 
109 dabc::Worker::Worker(const ConstructorPair& pair) :
110  Object(pair),
111  fThread(),
112  fAddon(),
113  fWorkerId(0),
114  fWorkerPriority(-1), // minimum priority per default
115 
116  fThreadMutex(0),
117  fWorkerActive(false),
118  fWorkerFiredEvents(0),
119 
120  fWorkerCommands(CommandsQueue::kindNone),
121 
122  fWorkerCommandsLevel(0),
123  fWorkerHierarchy(),
124  fWorkerCfgId(-1)
125 {
126  SetFlag(flHasThread, false);
127 
128 #ifdef DABC_EXTRA_CHECKS
129  DebugObject("Worker", this, 10);
130 #endif
131 }
132 
134 {
135  DOUT3("~Worker %p %d thrd:%p 000 ", this, fWorkerId, fThread());
136 
137  CancelCommands();
138 
139  DOUT3("~Worker %p %d thrd:%p 111", this, fWorkerId, fThread());
140 
141  // just to ensure that reference is gone
142  ClearThreadRef();
143 
144  DOUT3("~Worker %p %d thrd:%p done", this, fWorkerId, fThread());
145 
146  #ifdef DABC_EXTRA_CHECKS
147  DebugObject("Worker", this, -10);
148  #endif
149 }
150 
151 bool dabc::Worker::HasThread() const
152 {
153  LockGuard lock(fThreadMutex);
154 
155  return !fThread.null();
156 }
157 
159 {
160 
161  dabc::ThreadRef res;
162 
163  {
164  // this is lock over thread main mutex,
165  // if we can get it, we also can increment ref counter directly by the thread
166  LockGuard lock(fThreadMutex);
167 
168  // we can acquire new reference without additional lock of the mutex
169  fThread._AcquireThreadRef(res);
170  }
171 
172  return res;
173 }
174 
175 
176 bool dabc::Worker::IsOwnThread() const
177 {
178  LockGuard lock(fThreadMutex);
179 
180  if (fThread.null()) return false;
181 
182  return fThread.IsItself();
183 }
184 
185 
186 std::string dabc::Worker::ThreadName() const
187 {
188  LockGuard lock(fThreadMutex);
189 
190  return std::string(fThread() ? fThread()->GetName() : "");
191 }
192 
193 
195 {
196  // method can be called from any thread therefore we should first ensure that
197  // correct reference will exists on the thread
198  // Once true is returned thread guarantees that DestroyCalledFromOwnThread() method
199  // will be called from thread context
200  // One should also remember that reference counter is granted to thread
201 
202  ThreadRef thrd = thread();
203 
204  if (thrd()==0) return false;
205 
206  if (IsLogging())
207  DOUT0("Worker %p %s ask thread to destroy it ", this, GetName());
208 
209  return thrd()->InvokeWorkerDestroy(this);
210 }
211 
212 
214 {
215  ThreadRef ref;
216 
217  {
218  LockGuard lock(fThreadMutex);
219  ref << fThread;
220 
221  fThreadMutex = 0;
222  fWorkerId = 0;
223  fWorkerActive = false;
224 // fWorkerFiredEvents = 0;
225  }
226 
227  if (IsLogging())
228  DOUT0("Worker %s releases thread reference %p", GetName(), ref());
229 
230  ref.Release();
231 
232  dabc::LockGuard lock(fObjectMutex);
233 
234  SetFlag(Object::flHasThread, false);
235 
236 }
237 
239 {
240  // TODO: that is correct sequence - first delete child, than clean ourself (current) or vice-versa
241 
242  DOUT4("START worker %s class %s cleanup refcnt = %d thrd %s publ %p publthrd %s", GetName(), ClassName(), fObjectRefCnt, thread().GetName(), fPublisher(), WorkerRef(fPublisher).thread().GetName());
243 
244  CleanupPublisher(false);
245 
246  // we do standard object cleanup - remove all our childs and remove ourself from parent
248 
249  // from this moment on no new commands/events
250  DettachFromThread();
251 
252  // now process old commands
253  if (fWorkerCommandsLevel>0) {
254  EOUT("We are in real trouble - when Worker %s %p executes command, cleanup is called", GetName(), this);
255  exit(076);
256  }
257 
258  // process all postponed and submitted commands
259  do {
260  Command cmd = fWorkerCommands.PopWithKind(CommandsQueue::kindPostponed);
261  if (cmd.null()) cmd = fWorkerCommands.PopWithKind(CommandsQueue::kindSubmit);
262  if (cmd.null()) break;
263  ProcessCommand(cmd);
264  } while (true);
265 
266  // here we cancel all commands we submit or get as replied
267  CancelCommands();
268 
269  // here addon must be destroyed or at least cross-reference removed
270  // DOUT0("Worker:%s Destroy addon:%p in ObjectCleanup", GetName(), fAddon());
271  fAddon.Release();
272 
273  DOUT4("DID worker %s class %s cleanup refcnt = %d", GetName(), ClassName(), fObjectRefCnt);
274 }
275 
276 
277 void dabc::Worker::AssignAddon(WorkerAddon* addon)
278 {
279  if (!fAddon.null()) {
280  // first remove addon from thread itself
281 
282  if (!fThread.null() && (fWorkerId>0))
283  fThread()->WorkerAddonChanged(this, false);
284 
285  // clean worker pointer
286  fAddon()->fWorker.Release();
287 
288  // release addon - it should be destroyed as soon as possible
289  fAddon.Release();
290  }
291 
292  fAddon = addon;
293  if (addon) addon->fWorker = this;
294 
295  if (!fThread.null() && (fWorkerId>0) && addon) {
296  fThread()->WorkerAddonChanged(this, true);
297  addon->OnThreadAssigned();
298  }
299 }
300 
301 
302 bool dabc::Worker::MakeThreadForWorker(const std::string &thrdname)
303 {
304  std::string newname = thrdname;
305 
306  if (newname.empty()) {
307  DOUT2("Thread name not specified - generate default, for a moment - processor name");
308  if (GetName() != 0) newname = GetName();
309  }
310 
311  if (newname.empty()) {
312  EOUT("Still no thread name - used name Thread");
313  newname = "Thread";
314  }
315 
316  ThreadRef thrd = dabc::mgr.CreateThread(newname, RequiredThrdClass());
317 
318  return thrd.null() ? false : AssignToThread(thrd);
319 }
320 
321 
322 
323 // FIXME: old code, need revising
324 
325 
326 bool dabc::Worker::AssignToThread(ThreadRef thrd, bool sync)
327 {
328  if (HasThread()) {
329  EOUT("Worker %s already has assigned thred %s", GetName(), ThreadName().c_str());
330  return false;
331  }
332 
333  if (thrd.null()) {
334  EOUT("Thread is not specified");
335  return false;
336  }
337 
338  std::string thrdcl = RequiredThrdClass();
339 
340  if (thrdcl.length()>0)
341  if (thrdcl.compare(thrd.ClassName())!=0) {
342  EOUT("Processor requires class %s than thread %s of class %s" , thrdcl.c_str(), thrd.GetName(), thrd.ClassName());
343  return false;
344  }
345 
346  Reference ref(this);
347  if (ref()==0) {
348  EOUT("Cannot obtain reference on itself");
349  return false;
350  }
351 
352  // this indicates that we are not in the thread, any events/commands will be rejected
353  fWorkerId = 0;
354  fWorkerActive = false;
355 
356  fWorkerFiredEvents = 0;
357 
358  fThread = thrd; // we copy reference, no extra locks required
359 
360  fThreadMutex = fThread()->ThreadMutex();
361 
362  {
363  dabc::LockGuard lock(fObjectMutex);
364  SetFlag(Object::flHasThread, true);
365  }
366 
367  DOUT2("Assign worker %s to thread sync = %s", GetName(), DBOOL(sync));
368 
369  return fThread()->AddWorker(ref, sync);
370 }
371 
373 {
374  ThreadRef thrd = thread();
375 
376  if (thrd.null()) return true;
377 
378  bool res = thrd()->HaltWorker(this);
379 
380  if (res) ClearThreadRef();
381 
382  return res;
383 }
384 
385 bool dabc::Worker::ActivateTimeout(double tmout_sec)
386 {
387  LockGuard lock(fThreadMutex);
388 
389  return fThread._ActivateWorkerTimeout(fWorkerId, WorkerPriority(), tmout_sec);
390 }
391 
392 void dabc::Worker::ProcessCoreEvent(EventId evnt)
393 {
394  DOUT3("Processor %p %u thrd %p CoreEvent %u", this, fWorkerId, fThread(), evnt.GetCode());
395 
396  switch (evnt.GetCode()) {
397  case evntSubmitCommand: {
398 
399  DOUT4("Process evntSubmitCommand proc %p %u thrd %p arg %u", this, fWorkerId, fThread(), evnt.GetArg());
400 
401  Command cmd;
402  {
403  LockGuard lock(fThreadMutex);
404  cmd = fWorkerCommands.PopWithId(evnt.GetArg());
405  }
406 
407  DOUT4("Thread:%p Worker: %s Command process %s lvl %d", fThread(), GetName(), cmd.GetName(), fWorkerCommandsLevel);
408 
409  ProcessCommand(cmd);
410 
411  // check if we have postponed commands
412  while(fWorkerCommandsLevel==0) {
413  {
414  LockGuard lock(fThreadMutex);
415  cmd = fWorkerCommands.PopWithKind(CommandsQueue::kindPostponed);
416  }
417  if (cmd.null()) break;
418  ProcessCommand(cmd);
419  }
420 
421  DOUT4("Process evntSubmitCommand done proc %p", this);
422 
423  break;
424  }
425  case evntReplyCommand: {
426 
427 // DOUT0("Process evntReplyCommand arg %u", evnt.GetArg());
428 
429  dabc::Command cmd;
430  {
431  LockGuard lock(fThreadMutex);
432  cmd = fWorkerCommands.PopWithId(evnt.GetArg());
433  }
434 
435  if (cmd.null())
436  EOUT("evntReplyCommand: no command with specified id %u", evnt.GetArg());
437  else {
438  if (ReplyCommand(cmd)) cmd.Reply();
439  }
440 
441  break;
442  }
443 
444  default:
445  EOUT("Core event %u arg:%u not processed", evnt.GetCode(), evnt.GetArg());
446  }
447 }
448 
449 int dabc::Worker::ProcessCommand(Command cmd)
450 {
451  if (cmd.null() || !IsNormalState()) return cmd_false;
452 
453  DOUT3("ProcessCommand cmd %s lvl %d isync %s", cmd.GetName(), fWorkerCommandsLevel, DBOOL(cmd.IsLastCallerSync()));
454 
455  if (cmd.IsCanceled()) {
456  cmd.Reply(cmd_canceled);
457  return cmd_canceled;
458  }
459 
460  // when other command is in processing state,
461  // and this cmd not need to be synchronous,
462  // one can process such command later
463  // synchronous command must be processed immediately
464 
465  if ((fWorkerCommandsLevel>0) && !cmd.IsLastCallerSync()) {
466  LockGuard lock(fThreadMutex);
467  fWorkerCommands.Push(cmd, CommandsQueue::kindPostponed);
468  return cmd_postponed;
469  }
470 
471  IntGuard guard(fWorkerCommandsLevel);
472 
473  if (IsLogging())
474  DOUT0("Worker %p %s process command %s", this, GetName(), cmd.GetName());
475 
476  int cmd_res = PreviewCommand(cmd);
477 
478  if (IsLogging())
479  DOUT0("Worker %p %s did preview command %s ignored %s", this, GetName(), cmd.GetName(), DBOOL(cmd_res == cmd_ignore));
480 
481  if (cmd_res == cmd_ignore)
482  cmd_res = ExecuteCommand(cmd);
483 
484  if (cmd_res == cmd_ignore) {
485  EOUT("Command ignored %s", cmd.GetName());
486  cmd_res = cmd_false;
487  }
488 
489  // FIXME: is it only postponed command is not completed ???
490  bool completed = cmd_res!=cmd_postponed;
491 
492  DOUT3("Thrd: %p Worker: %s ProcessCommand cmd %s lvl %d done", fThread(), GetName(), cmd.GetName(), fWorkerCommandsLevel);
493 
494  if (completed) cmd.Reply(cmd_res);
495 
496  return cmd_res;
497 }
498 
499 void dabc::Worker::ProcessEvent(const EventId& evnt)
500 {
501  EOUT("Event %u arg:%u not processed req:%s", evnt.GetCode(), evnt.GetArg(),
502  RequiredThrdClass().c_str());
503 }
504 
506 {
507  // call should be performed from the thread context
508  if (fThread())
509  return fThread()->SetExplicitLoop(this);
510  else
511  return false;
512 }
513 
514 // all about parameters handling
515 
516 dabc::Parameter dabc::Worker::Par(const std::string &name) const
517 {
518  return FindChildRef(name.c_str());
519 }
520 
521 dabc::RecordField dabc::Worker::Cfg(const std::string &name, Command cmd) const
522 {
523 
524  DOUT2("Worker %s Cfg %s", ItemName().c_str(), name.c_str());
525 
526  // first check in the command
527  if (cmd.HasField(name)) return cmd.GetField(name);
528 
529  DOUT3("Check Cfg %s in own parameters", name.c_str());
530 
531  // second - as parameter
532  dabc::RecordField res = Par(name).Value();
533  if (!res.null()) return res;
534 
535  DOUT3("Check Cfg %s in xml file", name.c_str());
536 
537  // third - in xml file
538  ConfigIO io(dabc::mgr()->cfg(), fWorkerCfgId);
539  if (io.ReadRecordField((Object*) this, name, &res, 0)) {
540  DOUT2("Worker %s Cfg %s xml %s", ItemName().c_str(), name.c_str(), res.AsStr().c_str());
541  return res;
542  }
543 
544  DOUT3("Check Cfg %s in parent parameters", name.c_str());
545 
546  // forth - in parameters of all parents
547  Object* prnt = GetParent();
548  while (prnt!=0) {
549  res = WorkerRef(prnt).Par(name).Value();
550  if (!res.null()) return res;
551 
552  prnt = prnt->GetParent();
553  }
554 
555  return res;
556 }
557 
558 dabc::Parameter dabc::Worker::CreatePar(const std::string &name, const std::string &kind)
559 {
560  Parameter par = Par(name);
561  if (par.null()) {
562 
563  bool hidden = (kind == "cmddef");
564 
565  ParameterContainer* cont = new ParameterContainer(this, name, kind, hidden);
566 
567  ConfigIO io(dabc::mgr()->cfg());
568 
569  io.ReadRecordField(this, name, 0, &(cont->Fields()));
570 
571  par = cont;
572 
573  cont->FireParEvent(parCreated);
574  }
575  return par;
576 }
577 
578 void dabc::Worker::SetParValue(const std::string &name, const RecordField &v)
579 {
580  Parameter par = Par(name);
581  if (par.null()) return;
582 
583  par.SetValue(v);
584 
585  Hierarchy chld = fWorkerHierarchy.FindChild(name.c_str());
586  if (!chld.null()) {
587  par.ScanParamFields(&chld()->Fields());
588  fWorkerHierarchy.MarkChangedItems();
589  }
590 }
591 
592 bool dabc::Worker::DestroyPar(const std::string &name)
593 {
594  Parameter par = Par(name);
595 
596  if (par.null()) return false;
597 
598  par.Destroy();
599 
600  return true;
601 }
602 
604 {
605  return CreatePar(name, "cmddef");
606 }
607 
608 bool dabc::Worker::Find(ConfigIO &cfg)
609 {
610  DOUT3("Worker::Find %p name = %s parent %p", this, GetName(), GetParent());
611 
612  if (GetParent()==0) return false;
613 
614  while (cfg.FindItem(ClassName()))
615  if (cfg.CheckAttr(xmlNameAttr, GetName())) return true;
616 
617  return false;
618 }
619 
620 void dabc::Worker::WorkerParameterChanged(bool force_call, ParameterContainer *par, const std::string &value)
621 {
622  if (force_call || IsOwnThread()) {
623 
624  unsigned mask = par->ConfirmFromWorker();
625 
626  if (mask & 1)
627  ProcessParameterRecording(par);
628 
629  if (mask & 2)
630  ProcessParameterEvent(CmdParameterEvent(par->GetName(), value, parModified));
631  } else {
632  CmdParameterEvent evnt(par->GetName(), value, parModified);
633  evnt.SetBool("local", true);
634  Submit(evnt);
635  }
636 }
637 
638 void dabc::Worker::ProcessParameterRecording(ParameterContainer *par)
639 {
640  if (fWorkerHierarchy.null()) return;
641 
642  LockGuard guard(fWorkerHierarchy.GetHMutex());
643 
644  Hierarchy chld = fWorkerHierarchy.FindChild(par->GetName());
645 
646  if (!chld.null()) par->BuildFieldsMap(&chld()->Fields());
647  fWorkerHierarchy.MarkChangedItems();
648 }
649 
650 int dabc::Worker::PreviewCommand(Command cmd)
651 {
652  int cmd_res = cmd_ignore;
653 
654  if (cmd.IsName(CmdSetParameter::CmdName())) {
655 
656  Parameter par = Par(cmd.GetStr(CmdSetParameter::ParName()));
657 
658  cmd_res = par.ExecuteChange(cmd);
659 
660  } else
661 
662  if (cmd.IsName(CmdParameterEvent::CmdName())) {
663 
664  ParameterEvent evnt(cmd);
665 
666  if (cmd.GetBool("local")) {
667  Parameter par = Par(evnt.ParName());
668  if (par.null()) {
669  EOUT("FAIL to find local parameter %s", evnt.ParName().c_str());
670  cmd_res = cmd_false;
671  } else {
672  WorkerParameterChanged(true, par(), evnt.ParValue());
673  cmd_res = cmd_true;
674  }
675  } else {
676  ProcessParameterEvent(evnt);
677  cmd_res = cmd_true;
678  }
679 
680  } else
681 
682  if (cmd.IsName("ObjectDestroyed")) {
683  // process cleanup in worker thread
684  ObjectDestroyed((Object*)cmd.GetPtr("#Object"));
685  cmd_res = cmd_true;
686  } else
687 
688  if (cmd.IsName("DestroyParameter")) {
689  cmd_res = cmd_bool(DestroyPar(cmd.GetStr("ParName")));
690  } else
691 
692  if (cmd.IsName("SyncWorker")) {
693  // this is just dummy command, which is submitted with minimum priority
694  cmd_res = cmd_true;
695  } else
696 
697  if (cmd.IsName("DeleteAddon")) {
698  // this is way to delete addon
699  AssignAddon(nullptr);
700  cmd_res = cmd_true;
701  } else
702 
703  if (cmd.IsName(CmdPublisher::CmdName())) {
704  dabc::Hierarchy h = (HierarchyContainer*) cmd.GetPtr("hierarchy");
705  HierarchyStore* store = (HierarchyStore*) cmd.GetPtr("store");
706  unsigned version = cmd.GetUInt("version");
707 
708  if (!h.null()) {
709 
710  BeforeHierarchyScan(h);
711 
712  LockGuard lock(h.GetHMutex());
713 
714  Buffer diff = h.SaveToBuffer(dabc::stream_NamesList, version);
715  cmd.SetRawData(diff);
716 
717  cmd.SetUInt("version", h.GetVersion());
718 
719  if (store) store->ExtractData(h);
720 
721  cmd_res = cmd_true;
722  }
723 
724  if (store) store->WriteExtractedData();
725 
726  } else
727  if (cmd.IsName(dabc::CmdGetBinary::CmdName())) {
728 
729  dabc::Hierarchy h = (HierarchyContainer*) cmd.GetPtr("hierarchy");
730  if (h.null()) return cmd_ignore;
731 
732  std::string item = cmd.GetStr("subitem");
733  std::string fullname = cmd.GetStr("Item");
734  std::string binkind = cmd.GetStr("Kind");
735  std::string query = cmd.GetStr("Query");
736 
737  DOUT4("Worker %s Process CmdGetBinary item:%s full:%s kind %s", GetName(), item.c_str(), fullname.c_str(), binkind.c_str());
738 
739  std::string surl = "getitem";
740  if (query.length()>0) { surl.append("?"); surl.append(query); }
741 
742  dabc::Url url(surl);
743  if (!url.IsValid()) {
744  EOUT("Cannot decode query url %s", query.c_str());
745  return cmd_ignore;
746  }
747 
748  unsigned hlimit(0);
749  uint64_t version(0);
750  int compact(0);
751  bool with_childs(false);
752 
753  if (url.HasOption("history")) {
754  int hist = url.GetOptionInt("history", 0);
755  if (hist>0) hlimit = (unsigned) hist;
756  }
757  if (url.HasOption("version")) {
758  int v = url.GetOptionInt("version", 0);
759  if (v>0) version = (unsigned) v;
760  }
761  if (url.HasOption("compact"))
762  compact = url.GetOptionInt("compact", 3);
763  if (url.HasOption("childs"))
764  with_childs = true;
765 
766  LockGuard lock(h.GetHMutex());
767 
768  dabc::Hierarchy sub = h.GetFolder(item);
769 
770  if (binkind=="hierarchy") {
771  if (sub.null()) return cmd_ignore;
772  // we record only fields, everything else is ignored - even name of entry is not stored
773  Buffer raw = sub.SaveToBuffer(with_childs ? dabc::stream_Full : dabc::stream_Value, version, hlimit);
774  if (raw.null()) return cmd_ignore;
775 
776  cmd.SetRawData(raw);
777  cmd.SetUInt("version", sub.GetVersion());
778  cmd_res = cmd_true;
779  } else
780  if (binkind=="cmd.json") {
781  std::string cmdname = url.GetOptionStr("command");
782  // make protection - append prefix to exclude misuse of interface
783  if (!cmdname.empty()) cmdname = std::string("HCMD_") + cmdname; else
784  if (sub.HasField("_numargs")) cmdname = "ROOTCMD";
785  if (cmdname.empty()) return cmd_ignore;
786  dabc::Command subcmd(cmdname);
787  subcmd.SetRef("item", sub);
788  subcmd.SetStr("query", query);
789 
790  // we misuse command interface for executing actions together with subitem
791  // one could have problems if any
792  if (ExecuteCommand(subcmd)!=cmd_true) return cmd_ignore;
793 
794  Buffer raw = subcmd.GetRawData();
795  cmd.SetRawData(raw);
796 
797  cmd_res = cmd_true;
798  } else
799  if ((binkind=="get.json") || (binkind=="value.json") || (binkind=="item.json") || (binkind=="get.xml") || (binkind=="dabc.json") || (binkind=="dabc.xml")) {
800  std::string field = "";
801  if (binkind=="value.json") field = "value";
802  else field = url.GetOptionStr("field", "");
803 
804  if (sub.null() && field.empty()) {
805  size_t separ = item.find_last_of('/');
806  if ((separ != std::string::npos) && (separ>0) && (separ < item.length()-1)) {
807  field = item.substr(separ+1);
808  item.resize(separ);
809  sub = h.GetFolder(item);
810  }
811  }
812 
813  if (sub.null()) return cmd_ignore;
814 
815  // DOUT0("Request JSON for item %s field %s compact %d", item.c_str(), field.c_str(), compact);
816 
817  bool isxml = binkind.find(".xml")!=std::string::npos;
818 
819  std::string replybuf;
820 
821  dabc::NumericLocale loc; // ensure correct locale for conversion
822 
823  if (field.empty()) {
824  if (compact<0) compact = 0; else
825  if (compact>storemask_Compact) compact = storemask_Compact;
826  unsigned mask = compact;
828  if (isxml) mask |= dabc::storemask_AsXML;
829 
830  dabc::HStore store(mask);
831  store.SetLimits(version, hlimit);
832  if (sub.SaveTo(store))
833  replybuf = store.GetResult();
834 
835  } else {
836  if (!sub.HasField(field)) return cmd_ignore;
837 
838  replybuf = sub.GetField(field).AsJson();
839  }
840 
841  cmd.SetStrRawData(replybuf);
842 
843  cmd_res = cmd_true;
844  }
845  }
846 
847  return cmd_res;
848 }
849 
850 
851 int dabc::Worker::ExecuteCommand(Command cmd)
852 {
853  return cmd_false;
854 }
855 
856 bool dabc::Worker::ReplyCommand(Command cmd)
857 {
858  return true;
859 }
860 
861 
867 {
868  // this is pointer of thread from which command is called
869  ThreadRef thrd = thread();
870 
871  // we must be sure that call is done from thread itself - otherwise it is wrong
872  if (!thrd.null()) return false;
873 
874  return thrd()->RunCommandInTheThread(this, dest, cmd) > 0;
875 }
876 
877 bool dabc::Worker::Execute(Command cmd, double tmout)
878 {
879  if (cmd.null()) return false;
880 
881  if (tmout>0) cmd.SetTimeout(tmout);
882 
883  ThreadRef thrd;
884  bool exe_direct(false);
885 
886  if (IsLogging())
887  DOUT0("Worker %p %s Executes command %s", this, GetName(), cmd.GetName());
888 
889  {
890  LockGuard lock(fThreadMutex);
891 
892  if (fThread.null() || (fWorkerId==0)) {
893 
894  // command execution possible without thread,
895  // but only manager allows to do it without warnings
896  if (this != dabc::mgr())
897  EOUT("warning: Cannot execute command %s without working thread, execute directly", cmd.GetName());
898  exe_direct = true;
899  } else
900  if (fThread.IsItself()) {
901  // DOUT0("Mutex = %p thrdmutex %p locked %s", fThreadMutex, fThread()->ThreadMutex(), DBOOL(fThreadMutex->IsLocked()));
902  fThread._AcquireThreadRef(thrd);
903  }
904  }
905 
906  if (exe_direct) return ProcessCommand(cmd) > 0;
907 
908  // if command was called not from the same thread,
909  // find handle of caller thread to let run its event loop
910  if (thrd.null())
911  thrd = dabc::mgr.CurrentThread();
912 
913  if (thrd()) {
914  return thrd()->RunCommandInTheThread(0, this, cmd) > 0;
915  //if (res!=cmd_ignore) return res>0;
916  //return ProcessCommand(cmd) > 0;
917  }
918 
919  // if there is no Thread with such id (most probably, some user-managed thrd)
920  // than we create fake object only to handle commands and events,
921  // but not really take over thread mainloop
922  // This object is not seen from the manager, therefore many such instances may exist in parallel
923 
924  DOUT3("**** We really creating dummy thread for cmd %s worker:%p %s", cmd.GetName(), this, GetName());
925 
926  Thread curr(Reference(), "Current");
927 
928  curr.Start(0, false);
929 
930  return curr.RunCommandInTheThread(0, this, cmd) > 0;
931 }
932 
934 {
935  if (cmd.null()) return cmd;
936 
937  {
938  LockGuard lock(fThreadMutex);
939 
940  if (fThread()==0) {
941  EOUT("Worker: %s - command %s cannot be assigned without thread", GetName(), cmd.GetName());
942  return Command();
943  }
944 
945  fWorkerCommands.Push(cmd, CommandsQueue::kindAssign);
946  }
947 
948  cmd.AddCaller(this, 0);
949 
950  return cmd;
951 }
952 
954 {
955  LockGuard lock(fThreadMutex);
956 
957  return !fThread.null() && fWorkerActive;
958 }
959 
961 {
962  if (cmd.null()) return false;
963 
964  int priority = cmd.GetPriority();
965 
966  {
967  LockGuard lock(fThreadMutex);
968 
969  // we can submit commands when worker is active (does not tries to halt)
970  if (!fThread.null())
971  if (fWorkerActive || (priority == priorityMagic)) {
972 
973  if (priority == priorityMagic) priority = fWorkerPriority; else
974  if (priority == priorityDefault) priority = 0; else
975  if (priority == priorityMinimum) priority = -1;
976 
977  uint32_t arg = fWorkerCommands.Push(cmd, CommandsQueue::kindSubmit);
978 
979  DOUT5("Fire event for worker %d with priority %d", fWorkerId, priority);
980 
981  fThread()->_Fire(EventId(evntSubmitCommand, fWorkerId, arg), priority);
982 
983  fWorkerFiredEvents++;
984 
985  return true;
986  }
987  }
988 
989  DOUT0("Worker:%s Command %s cannot be submitted - thread is not assigned", GetName(), cmd.GetName());
990 
991  cmd.ReplyFalse();
992 
993  return false;
994 }
995 
996 bool dabc::Worker::GetCommandReply(dabc::Command& cmd, bool* exe_ready)
997 {
998  if (cmd.null()) return false;
999 
1000  LockGuard lock(fThreadMutex);
1001 
1002  DOUT3("GetCommandReply %s exe_ready %p Thread %p %s", cmd.GetName(), exe_ready, fThread(), fThread()->GetName());
1003 
1004  if (exe_ready) {
1005  if (_FireDoNothingEvent()) {
1006  // we must be sure that event is accepted, it can be that worker is just break all its activity and pointer is no longer valid
1007  *exe_ready = true;
1008  return true;
1009  }
1010 
1011  return false;
1012  }
1013 
1014  // here command will be overtaken from the reference
1015  uint32_t id = fWorkerCommands.ChangeKind(cmd, CommandsQueue::kindReply);
1016 
1017  if (!_FireEvent(evntReplyCommand, id, 0)) {
1018  fWorkerCommands.PopWithId(id);
1019  if (!cmd.HasField("#no_warnings")) EOUT("Worker %s don't want get command for reply", GetName());
1020  return false;
1021  }
1022 
1023  return true;
1024 }
1025 
1027 {
1028  fWorkerCommands.Cleanup(fThreadMutex, this, cmd_false);
1029 }
1030 
1031 void dabc::Worker::WorkerSleep(double tmout)
1032 {
1033  ThreadRef thrd = thread();
1034 
1035  if (!thrd.null() && thrd.IsItself()) {
1036  thrd.RunEventLoop(tmout);
1037  return;
1038  }
1039 
1040  thrd = dabc::mgr.CurrentThread();
1041  if (!thrd.null()) {
1042  thrd.RunEventLoop(tmout);
1043  return;
1044  }
1045 
1046  dabc::Sleep(tmout);
1047 }
1048 
1049 
1050 bool dabc::Worker::RegisterForParameterEvent(const std::string &mask, bool onlychangeevent)
1051 {
1052  return dabc::mgr.ParameterEventSubscription(this, true, mask, onlychangeevent);
1053 }
1054 
1055 
1056 bool dabc::Worker::UnregisterForParameterEvent(const std::string &mask)
1057 {
1058  return dabc::mgr.ParameterEventSubscription(this, false, mask);
1059 }
1060 
1061 
1062 std::string dabc::Worker::WorkerAddress(bool full)
1063 {
1064  return full ? dabc::mgr.ComposeAddress("",ItemName()) : ItemName();
1065 }
1066 
1067 
1069 {
1070  if (fPublisher.null()) fPublisher = dabc::mgr.FindItem(dabc::Publisher::DfltName());
1071  return fPublisher;
1072 }
1073 
1074 
1075 bool dabc::Worker::Publish(const Hierarchy& h, const std::string &path)
1076 {
1077  return PublisherRef(GetPublisher()).Register(path, ItemName(), h());
1078 }
1079 
1080 
1081 bool dabc::Worker::PublishPars(const std::string &path)
1082 {
1083  // no need to publish if publisher not exists
1084  if (GetPublisher().null()) return true;
1085 
1086  if (fWorkerHierarchy.null())
1087  fWorkerHierarchy.Create("Worker");
1088 
1089  for (unsigned n=0;n<NumChilds();n++) {
1090  Parameter par = dynamic_cast<ParameterContainer*> (GetChild(n));
1091  if (par.null()) continue;
1092 
1093  Hierarchy chld = fWorkerHierarchy.FindChild(par.GetName());
1094  if (!chld.null()) continue;
1095 
1096  chld = fWorkerHierarchy.CreateHChild(par.GetName());
1097 
1098  if (par.IsRatemeter() || (par.Kind() == "info") || par.GetField("#record").AsBool()) {
1099  chld.EnableHistory(100);
1100  par()->fRecorded = true;
1101  }
1102 
1103  par.ScanParamFields(&chld()->Fields());
1104  }
1105  fWorkerHierarchy.MarkChangedItems();
1106 
1107  return Publish(fWorkerHierarchy, path);
1108 }
1109 
1110 
1111 bool dabc::Worker::Unpublish(const Hierarchy& h, const std::string &path)
1112 {
1113  return PublisherRef(GetPublisher()).Unregister(path, ItemName(), h());
1114 }
1115 
1116 bool dabc::Worker::Subscribe(const std::string &path)
1117 {
1118  return PublisherRef(GetPublisher()).Subscribe(path, ItemName());
1119 }
1120 
1121 bool dabc::Worker::Unsubscribe(const std::string &path)
1122 {
1123  return PublisherRef(GetPublisher()).Unsubscribe(path, ItemName());
1124 }
1125 
1126 void dabc::Worker::CleanupPublisher(bool sync)
1127 {
1128  if (fPublisher.null()) return;
1129 
1130  PublisherRef ref;
1131 
1132  ref << fPublisher;
1133 
1134  if (!ref.thread().null()) ref.RemoveWorker(ItemName(), sync);
1135 }
1136 
1137 // ===========================================================================================
1138 
1140 {
1141  if (GetObject()) return GetObject()->Submit(cmd);
1142 
1143  cmd.ReplyFalse();
1144  return false;
1145 }
1146 
1147 bool dabc::WorkerRef::Execute(Command cmd, double tmout)
1148 {
1149  if (GetObject()==0) return false;
1150  return GetObject()->Execute(cmd, tmout);
1151 }
1152 
1153 bool dabc::WorkerRef::Execute(const std::string &cmd, double tmout)
1154 {
1155  if (GetObject()==0) return false;
1156  return GetObject()->Execute(cmd, tmout);
1157 }
1158 
1159 dabc::Parameter dabc::WorkerRef::Par(const std::string &name) const
1160 {
1161  if (GetObject()==0) return dabc::Parameter();
1162  return GetObject()->Par(name);
1163 }
1164 
1165 bool dabc::WorkerRef::HasThread() const
1166 {
1167  return GetObject() ? GetObject()->HasThread() : false;
1168 }
1169 
1170 bool dabc::WorkerRef::IsSameThread(const WorkerRef& ref)
1171 {
1172  if (GetObject() && ref.GetObject())
1173  return GetObject()->thread()() == ref.GetObject()->thread()();
1174 
1175  return false;
1176 }
1177 
1178 
1180 {
1181  return GetObject() ? GetObject()->CanSubmitCommand() : false;
1182 }
1183 
1184 bool dabc::WorkerRef::SyncWorker(double tmout)
1185 {
1186  if (GetObject()==0) return true;
1187 
1188  dabc::Command cmd("SyncWorker");
1189  cmd.SetPriority(dabc::Worker::priorityMinimum);
1190  if (tmout>=0) cmd.SetTimeout(tmout);
1191  return Execute(cmd) == cmd_true;
1192 }
static const char * ParName()
Definition: Manager.h:220
Command definition class.
Definition: Parameter.h:333
Represents command with its arguments.
Definition: Command.h:99
void AddCaller(Worker *worker, bool *exe_ready=nullptr)
Definition: Command.cxx:68
void ReplyFalse()
Reply on the command with false (cmd_false==0) value.
Definition: Command.h:232
void Reply(int res=cmd_noresult)
Replied on the command.
Definition: Command.cxx:225
int GetPriority() const
Returns command priority.
Definition: Command.cxx:146
@ kindSubmit
command submitted for execution
Definition: CommandsQueue.h:45
@ kindPostponed
command submitted but postponed to not increase execution recursion
Definition: CommandsQueue.h:48
@ kindReply
command replied to the worker
Definition: CommandsQueue.h:46
@ kindAssign
command assign with the worker, but not yet replied
Definition: CommandsQueue.h:47
class, used for direct store of records in JSON/XML form
Definition: Record.h:179
Represents objects hierarchy of remote (or local) DABC process.
Definition: Hierarchy.h:285
uint64_t GetVersion() const
Returns actual version of hierarchy entry.
Definition: Hierarchy.h:349
dabc::Buffer SaveToBuffer(unsigned kind=stream_Full, uint64_t version=0, unsigned hlimit=0)
Save hierarchy in binary form, relative to specified version.
Definition: Hierarchy.cxx:873
Mutex * GetHMutex() const
Definition: Hierarchy.h:292
Lock guard for posix mutex.
Definition: threads.h:127
ThreadRef CurrentThread()
Returns reference on the thread, which is now active.
Definition: Manager.cxx:1995
Reference FindItem(const std::string &name)
Definition: Manager.cxx:2054
bool ParameterEventSubscription(Worker *ptr, bool subscribe, const std::string &mask, bool onlychangeevent=true)
Definition: Manager.cxx:2096
std::string ComposeAddress(const std::string &server, const std::string &itemname="")
Definition: Manager.h:603
ThreadRef CreateThread(const std::string &thrdname, const std::string &classname="", const std::string &devname="")
Definition: Manager.cxx:1988
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
Definition: Object.cxx:532
@ flHasThread
flag indicates that object has thread and should be cleaned up via thread
Definition: Object.h:166
Parameter class
Definition: Parameter.h:163
static const char * DfltName()
Definition: Publisher.h:214
std::string AsJson() const
Returns field value in JSON format.
Definition: Record.cxx:835
std::string AsStr(const std::string &dflt="") const
Definition: Record.cxx:749
bool null() const
Definition: Record.h:302
RecordField GetField(const std::string &name) const
Definition: Record.h:510
bool HasField(const std::string &name) const
Definition: Record.h:498
bool SaveTo(HStore &store, bool create_node=true)
Store hierarchy in json/xml form
Definition: Record.h:534
Reference on the arbitrary object
Definition: Reference.h:73
const char * GetName() const
Return name of referenced object, if object not assigned, returns "---".
Definition: Reference.cxx:167
Reference GetFolder(const std::string &name, bool force=false)
Return folder of specified name, no special symbols are allowed.
Definition: Reference.cxx:234
bool null() const
Returns true if reference contains nullptr.
Definition: Reference.h:151
Reference on the dabc::Thread class
Definition: Thread.h:482
bool _ActivateAddonTimeout(unsigned workerid, int priority, double tmout)
Definition: Thread.cxx:1433
void RunEventLoop(double tmout=1.)
Runs thread event loop for specified time.
Definition: Thread.cxx:1406
Uniform Resource Locator interpreter.
Definition: Url.h:33
void FireWorkerEvent(unsigned evid)
Definition: Worker.cxx:56
void SubmitWorkerCmd(Command cmd)
Definition: Worker.cxx:73
void DeleteAddonItself()
This is possibility to delete addon itself, invoking worker command.
Definition: Worker.cxx:50
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
Definition: Worker.cxx:39
void DeleteWorker()
This is way to delete worker with addon inclusive.
Definition: Worker.cxx:44
virtual ~WorkerAddon()
Definition: Worker.cxx:34
bool ActivateTimeout(double tmout_sec)
Definition: Worker.cxx:62
WorkerAddon(const std::string &name)
Definition: Worker.cxx:27
bool HasThread() const
Returns true when thread is assigned to the worker.
Definition: Worker.cxx:1165
bool SyncWorker(double tmout=-1.)
Synchronize worker with caller thread.
Definition: Worker.cxx:1184
Parameter Par(const std::string &name) const
Returns reference on parameter.
Definition: Worker.cxx:1159
bool Execute(Command cmd, double tmout=-1.)
Definition: Worker.cxx:1147
bool CanSubmitCommand() const
Returns true if command can be submitted to the worker.
Definition: Worker.cxx:1179
bool IsSameThread(const WorkerRef &ref)
Returns true if two workers share same thread.
Definition: Worker.cxx:1170
bool Submit(Command cmd)
Definition: Worker.cxx:1139
Active object, which is working inside dabc::Thread.
Definition: Worker.h:116
virtual int PreviewCommand(Command cmd)
This method called before command will be executed.
Definition: Worker.cxx:650
virtual bool Subscribe(const std::string &path)
Definition: Worker.cxx:1116
bool ActivateTimeout(double tmout_sec)
Method used to produce timeout events in the worker.
Definition: Worker.cxx:385
@ priorityMinimum
Definition: Worker.h:208
CommandDefinition CreateCmdDef(const std::string &name)
Definition: Worker.cxx:603
int ProcessCommand(dabc::Command cmd)
Definition: Worker.cxx:449
uint32_t fWorkerId
worker id in thread list, used for events submit
Definition: Worker.h:155
void AssignAddon(WorkerAddon *addon)
Assigns addon to the worker Should be called before worker assigned to the thread.
Definition: Worker.cxx:277
void ProcessParameterRecording(ParameterContainer *par)
Method to process parameter recording in worker thread.
Definition: Worker.cxx:638
virtual void ProcessEvent(const EventId &)
Definition: Worker.cxx:499
Worker(const ConstructorPair &pair)
Special constructor, designed for inherited classes.
Definition: Worker.cxx:109
bool RegisterForParameterEvent(const std::string &mask, bool onlychangeevent=true)
Subscribe to parameter events from local or remote node.
Definition: Worker.cxx:1050
void ClearThreadRef()
Method to 'forget' thread reference.
Definition: Worker.cxx:213
bool Submit(Command cmd)
Submit command for execution in the processor.
Definition: Worker.cxx:960
bool GetCommandReply(dabc::Command &cmd, bool *exe_ready)
Definition: Worker.cxx:996
void WorkerParameterChanged(bool forcecall, ParameterContainer *par, const std::string &value)
Method called by parameter object which is belong to the worker.
Definition: Worker.cxx:620
void WorkerSleep(double tmout)
Definition: Worker.cxx:1031
bool CanSubmitCommand() const
Returns true if command can be submitted to worker.
Definition: Worker.cxx:953
bool Execute(Command cmd, double tmout=-1.)
Execute command in the processor.
Definition: Worker.cxx:877
bool ExecuteIn(Worker *dest, Command cmd)
Executes command in specified worker.
Definition: Worker.cxx:866
Command Assign(Command cmd)
! Assign command with processor before command be submitted to other processor This produce ReplyComm...
Definition: Worker.cxx:933
void CleanupPublisher(bool sync=true)
Release reference on publisher and unsubscribe/unpublish all registered entries.
Definition: Worker.cxx:1126
Parameter Par(const std::string &name) const
Returns reference on worker parameter object.
Definition: Worker.cxx:516
bool AssignToThread(ThreadRef thrd, bool sync=true)
Assign worker to thread, worker becomes active immediately.
Definition: Worker.cxx:326
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
std::string WorkerAddress(bool full=true)
Return address, which can be used to submit command to the worker If full specified,...
Definition: Worker.cxx:1062
virtual bool DestroyByOwnThread()
Inherited method from Object, invoked at the moment when worker requested to be destroyed by its thre...
Definition: Worker.cxx:194
bool UnregisterForParameterEvent(const std::string &mask)
Unsubscribe to parameter events from local or remote node.
Definition: Worker.cxx:1056
bool DestroyPar(const std::string &name)
Method must be used if worker wants to destroy parameter.
Definition: Worker.cxx:592
bool HasThread() const
Indicates if pointer on thread is not zero; thread-safe.
Definition: Worker.cxx:151
virtual bool Unpublish(const Hierarchy &h, const std::string &path)
Definition: Worker.cxx:1111
void CancelCommands()
Definition: Worker.cxx:1026
bool ActivateMainLoop()
Definition: Worker.cxx:505
bool MakeThreadForWorker(const std::string &thrdname="")
Creates appropriate thread for worker and assign worker to the thread.
Definition: Worker.cxx:302
std::string ThreadName() const
Returns name of the worker thread; thread-safe
Definition: Worker.cxx:186
virtual bool Unsubscribe(const std::string &path)
Definition: Worker.cxx:1121
ThreadRef fThread
reference on the thread, once assigned remain whole time
Definition: Worker.h:151
virtual bool Find(ConfigIO &cfg)
Method to locate object in xml file.
Definition: Worker.cxx:608
ThreadRef thread()
Return reference on the worker thread; thread-safe.
Definition: Worker.cxx:158
Reference GetPublisher()
Return reference on publisher.
Definition: Worker.cxx:1068
void SetParValue(const std::string &name, const RecordField &v)
Set parameter value and sync with worker hierarchy.
Definition: Worker.cxx:578
int WorkerPriority() const
Definition: Worker.h:260
void ProcessCoreEvent(EventId)
Definition: Worker.cxx:392
bool DettachFromThread()
Detach worker from the thread, later worker can be assigned to some other thread Method especially us...
Definition: Worker.cxx:372
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
virtual bool Publish(const Hierarchy &h, const std::string &path)
Definition: Worker.cxx:1075
bool IsOwnThread() const
Returns true if called from thread.
Definition: Worker.cxx:176
Mutex * fThreadMutex
pointer on main thread mutex
Definition: Worker.h:158
bool FireEvent(uint16_t evid)
Definition: Worker.h:341
virtual ~Worker()
Definition: Worker.cxx:133
#define DOUT2(args ...)
Definition: logging.h:170
#define DOUT0(args ...)
Definition: logging.h:156
#define DOUT5(args ...)
Definition: logging.h:188
#define DOUT3(args ...)
Definition: logging.h:176
#define EOUT(args ...)
Definition: logging.h:150
#define DBOOL(arg)
Definition: logging.h:191
#define DOUT4(args ...)
Definition: logging.h:182
XMLNodePointer_t GetParent(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:917
XMLNodePointer_t GetChild(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:906
void Sleep(double tm)
Definition: timing.cxx:129
@ storemask_TopVersion
Definition: Record.h:170
@ storemask_History
Definition: Record.h:171
@ storemask_NoChilds
Definition: Record.h:172
@ storemask_Compact
Definition: Record.h:168
@ storemask_AsXML
Definition: Record.h:173
ManagerRef mgr
Definition: Manager.cxx:42
@ parCreated
produced once when parameter is created
Definition: Parameter.h:41
@ parModified
produced when parameter value modified. Either every change or after time interval (default = 1 sec)
Definition: Parameter.h:43
@ stream_Full
Definition: Hierarchy.h:134
@ stream_NamesList
Definition: Hierarchy.h:132
@ stream_Value
Definition: Hierarchy.h:133
const char * xmlNameAttr
Definition: ConfigBase.cxx:33
@ cmd_postponed
Definition: Command.h:42
@ cmd_false
Definition: Command.h:37
@ cmd_ignore
Definition: Command.h:41
@ cmd_true
Definition: Command.h:38
@ cmd_canceled
Definition: Command.h:44