25 #include "dabc/defines.h"
31 SetFlag(flAutoDestroy,
true);
46 if (fWorker.null()) DeleteThis();
47 else fWorker.Destroy();
52 if (fWorker.null()) DeleteThis();
66 if (wrk==0)
return false;
93 fWorkerFiredEvents(0),
95 fWorkerCommands(CommandsQueue::kindNone),
97 fWorkerCommandsLevel(0),
101 SetFlag(flHasThread,
false);
103 #ifdef DABC_EXTRA_CHECKS
104 DebugObject(
"Worker",
this, 10);
117 fWorkerActive(false),
118 fWorkerFiredEvents(0),
120 fWorkerCommands(CommandsQueue::kindNone),
122 fWorkerCommandsLevel(0),
126 SetFlag(flHasThread,
false);
128 #ifdef DABC_EXTRA_CHECKS
129 DebugObject(
"Worker",
this, 10);
146 #ifdef DABC_EXTRA_CHECKS
147 DebugObject(
"Worker",
this, -10);
153 LockGuard lock(fThreadMutex);
155 return !fThread.null();
166 LockGuard lock(fThreadMutex);
169 fThread._AcquireThreadRef(res);
178 LockGuard lock(fThreadMutex);
180 if (fThread.null())
return false;
182 return fThread.IsItself();
188 LockGuard lock(fThreadMutex);
190 return std::string(fThread() ? fThread()->GetName() :
"");
202 ThreadRef thrd = thread();
204 if (thrd()==0)
return false;
207 DOUT0(
"Worker %p %s ask thread to destroy it ",
this, GetName());
209 return thrd()->InvokeWorkerDestroy(
this);
218 LockGuard lock(fThreadMutex);
223 fWorkerActive =
false;
228 DOUT0(
"Worker %s releases thread reference %p", GetName(), ref());
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());
244 CleanupPublisher(
false);
253 if (fWorkerCommandsLevel>0) {
254 EOUT(
"We are in real trouble - when Worker %s %p executes command, cleanup is called", GetName(),
this);
262 if (cmd.null())
break;
273 DOUT4(
"DID worker %s class %s cleanup refcnt = %d", GetName(), ClassName(), fObjectRefCnt);
279 if (!fAddon.null()) {
282 if (!fThread.null() && (fWorkerId>0))
283 fThread()->WorkerAddonChanged(
this,
false);
286 fAddon()->fWorker.Release();
293 if (addon) addon->fWorker =
this;
295 if (!fThread.null() && (fWorkerId>0) && addon) {
296 fThread()->WorkerAddonChanged(
this,
true);
297 addon->OnThreadAssigned();
304 std::string newname = thrdname;
306 if (newname.empty()) {
307 DOUT2(
"Thread name not specified - generate default, for a moment - processor name");
308 if (GetName() != 0) newname = GetName();
311 if (newname.empty()) {
312 EOUT(
"Still no thread name - used name Thread");
318 return thrd.
null() ? false : AssignToThread(thrd);
329 EOUT(
"Worker %s already has assigned thred %s", GetName(), ThreadName().c_str());
334 EOUT(
"Thread is not specified");
338 std::string thrdcl = RequiredThrdClass();
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());
348 EOUT(
"Cannot obtain reference on itself");
354 fWorkerActive =
false;
356 fWorkerFiredEvents = 0;
360 fThreadMutex = fThread()->ThreadMutex();
367 DOUT2(
"Assign worker %s to thread sync = %s", GetName(),
DBOOL(sync));
369 return fThread()->AddWorker(ref, sync);
374 ThreadRef thrd = thread();
376 if (thrd.null())
return true;
378 bool res = thrd()->HaltWorker(
this);
380 if (res) ClearThreadRef();
387 LockGuard lock(fThreadMutex);
389 return fThread._ActivateWorkerTimeout(fWorkerId, WorkerPriority(), tmout_sec);
394 DOUT3(
"Processor %p %u thrd %p CoreEvent %u",
this, fWorkerId, fThread(), evnt.GetCode());
396 switch (evnt.GetCode()) {
397 case evntSubmitCommand: {
399 DOUT4(
"Process evntSubmitCommand proc %p %u thrd %p arg %u",
this, fWorkerId, fThread(), evnt.GetArg());
403 LockGuard lock(fThreadMutex);
404 cmd = fWorkerCommands.PopWithId(evnt.GetArg());
407 DOUT4(
"Thread:%p Worker: %s Command process %s lvl %d", fThread(), GetName(), cmd.GetName(), fWorkerCommandsLevel);
412 while(fWorkerCommandsLevel==0) {
414 LockGuard lock(fThreadMutex);
417 if (cmd.null())
break;
421 DOUT4(
"Process evntSubmitCommand done proc %p",
this);
425 case evntReplyCommand: {
431 LockGuard lock(fThreadMutex);
432 cmd = fWorkerCommands.PopWithId(evnt.GetArg());
436 EOUT(
"evntReplyCommand: no command with specified id %u", evnt.GetArg());
438 if (ReplyCommand(cmd)) cmd.
Reply();
445 EOUT(
"Core event %u arg:%u not processed", evnt.GetCode(), evnt.GetArg());
451 if (cmd.null() || !IsNormalState())
return cmd_false;
453 DOUT3(
"ProcessCommand cmd %s lvl %d isync %s", cmd.GetName(), fWorkerCommandsLevel,
DBOOL(cmd.IsLastCallerSync()));
455 if (cmd.IsCanceled()) {
465 if ((fWorkerCommandsLevel>0) && !cmd.IsLastCallerSync()) {
466 LockGuard lock(fThreadMutex);
471 IntGuard guard(fWorkerCommandsLevel);
474 DOUT0(
"Worker %p %s process command %s",
this, GetName(), cmd.GetName());
476 int cmd_res = PreviewCommand(cmd);
479 DOUT0(
"Worker %p %s did preview command %s ignored %s",
this, GetName(), cmd.GetName(),
DBOOL(cmd_res ==
cmd_ignore));
482 cmd_res = ExecuteCommand(cmd);
485 EOUT(
"Command ignored %s", cmd.GetName());
492 DOUT3(
"Thrd: %p Worker: %s ProcessCommand cmd %s lvl %d done", fThread(), GetName(), cmd.GetName(), fWorkerCommandsLevel);
494 if (completed) cmd.Reply(cmd_res);
501 EOUT(
"Event %u arg:%u not processed req:%s", evnt.GetCode(), evnt.GetArg(),
502 RequiredThrdClass().c_str());
509 return fThread()->SetExplicitLoop(
this);
518 return FindChildRef(name.c_str());
524 DOUT2(
"Worker %s Cfg %s", ItemName().c_str(), name.c_str());
527 if (cmd.HasField(name))
return cmd.GetField(name);
529 DOUT3(
"Check Cfg %s in own parameters", name.c_str());
533 if (!res.
null())
return res;
535 DOUT3(
"Check Cfg %s in xml file", name.c_str());
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());
544 DOUT3(
"Check Cfg %s in parent parameters", name.c_str());
549 res = WorkerRef(prnt).Par(name).Value();
550 if (!res.
null())
return res;
552 prnt = prnt->GetParent();
560 Parameter par = Par(name);
563 bool hidden = (kind ==
"cmddef");
565 ParameterContainer* cont =
new ParameterContainer(
this, name, kind, hidden);
569 io.ReadRecordField(
this, name, 0, &(cont->Fields()));
580 Parameter par = Par(name);
581 if (par.null())
return;
585 Hierarchy chld = fWorkerHierarchy.FindChild(name.c_str());
587 par.ScanParamFields(&chld()->Fields());
588 fWorkerHierarchy.MarkChangedItems();
594 Parameter par = Par(name);
596 if (par.null())
return false;
605 return CreatePar(name,
"cmddef");
610 DOUT3(
"Worker::Find %p name = %s parent %p",
this, GetName(),
GetParent());
614 while (cfg.FindItem(ClassName()))
615 if (cfg.CheckAttr(
xmlNameAttr, GetName()))
return true;
622 if (force_call || IsOwnThread()) {
624 unsigned mask = par->ConfirmFromWorker();
627 ProcessParameterRecording(par);
630 ProcessParameterEvent(CmdParameterEvent(par->GetName(), value,
parModified));
632 CmdParameterEvent evnt(par->GetName(), value,
parModified);
633 evnt.SetBool(
"local",
true);
640 if (fWorkerHierarchy.null())
return;
642 LockGuard guard(fWorkerHierarchy.GetHMutex());
644 Hierarchy chld = fWorkerHierarchy.FindChild(par->GetName());
646 if (!chld.null()) par->BuildFieldsMap(&chld()->Fields());
647 fWorkerHierarchy.MarkChangedItems();
654 if (cmd.IsName(CmdSetParameter::CmdName())) {
658 cmd_res = par.ExecuteChange(cmd);
662 if (cmd.IsName(CmdParameterEvent::CmdName())) {
664 ParameterEvent evnt(cmd);
666 if (cmd.GetBool(
"local")) {
667 Parameter par = Par(evnt.ParName());
669 EOUT(
"FAIL to find local parameter %s", evnt.ParName().c_str());
672 WorkerParameterChanged(
true, par(), evnt.ParValue());
676 ProcessParameterEvent(evnt);
682 if (cmd.IsName(
"ObjectDestroyed")) {
684 ObjectDestroyed((Object*)cmd.GetPtr(
"#Object"));
688 if (cmd.IsName(
"DestroyParameter")) {
689 cmd_res = cmd_bool(DestroyPar(cmd.GetStr(
"ParName")));
692 if (cmd.IsName(
"SyncWorker")) {
697 if (cmd.IsName(
"DeleteAddon")) {
699 AssignAddon(
nullptr);
703 if (cmd.IsName(CmdPublisher::CmdName())) {
705 HierarchyStore* store = (HierarchyStore*) cmd.GetPtr(
"store");
706 unsigned version = cmd.GetUInt(
"version");
710 BeforeHierarchyScan(h);
715 cmd.SetRawData(diff);
719 if (store) store->ExtractData(h);
724 if (store) store->WriteExtractedData();
727 if (cmd.IsName(dabc::CmdGetBinary::CmdName())) {
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");
737 DOUT4(
"Worker %s Process CmdGetBinary item:%s full:%s kind %s", GetName(), item.c_str(), fullname.c_str(), binkind.c_str());
739 std::string surl =
"getitem";
740 if (query.length()>0) { surl.append(
"?"); surl.append(query); }
743 if (!url.IsValid()) {
744 EOUT(
"Cannot decode query url %s", query.c_str());
751 bool with_childs(
false);
753 if (url.HasOption(
"history")) {
754 int hist = url.GetOptionInt(
"history", 0);
755 if (hist>0) hlimit = (unsigned) hist;
757 if (url.HasOption(
"version")) {
758 int v = url.GetOptionInt(
"version", 0);
759 if (v>0) version = (unsigned) v;
761 if (url.HasOption(
"compact"))
762 compact = url.GetOptionInt(
"compact", 3);
763 if (url.HasOption(
"childs"))
770 if (binkind==
"hierarchy") {
780 if (binkind==
"cmd.json") {
781 std::string cmdname = url.GetOptionStr(
"command");
783 if (!cmdname.empty()) cmdname = std::string(
"HCMD_") + cmdname;
else
784 if (sub.
HasField(
"_numargs")) cmdname =
"ROOTCMD";
787 subcmd.SetRef(
"item", sub);
788 subcmd.SetStr(
"query", query);
794 Buffer raw = subcmd.GetRawData();
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",
"");
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);
817 bool isxml = binkind.find(
".xml")!=std::string::npos;
819 std::string replybuf;
824 if (compact<0) compact = 0;
else
826 unsigned mask = compact;
831 store.SetLimits(version, hlimit);
833 replybuf = store.GetResult();
841 cmd.SetStrRawData(replybuf);
869 ThreadRef thrd = thread();
872 if (!thrd.null())
return false;
874 return thrd()->RunCommandInTheThread(
this, dest, cmd) > 0;
879 if (cmd.null())
return false;
881 if (tmout>0) cmd.SetTimeout(tmout);
884 bool exe_direct(
false);
887 DOUT0(
"Worker %p %s Executes command %s",
this, GetName(), cmd.GetName());
890 LockGuard lock(fThreadMutex);
892 if (fThread.null() || (fWorkerId==0)) {
897 EOUT(
"warning: Cannot execute command %s without working thread, execute directly", cmd.GetName());
900 if (fThread.IsItself()) {
902 fThread._AcquireThreadRef(thrd);
906 if (exe_direct)
return ProcessCommand(cmd) > 0;
914 return thrd()->RunCommandInTheThread(0,
this, cmd) > 0;
924 DOUT3(
"**** We really creating dummy thread for cmd %s worker:%p %s", cmd.GetName(),
this, GetName());
926 Thread curr(Reference(),
"Current");
928 curr.Start(0,
false);
930 return curr.RunCommandInTheThread(0,
this, cmd) > 0;
935 if (cmd.
null())
return cmd;
938 LockGuard lock(fThreadMutex);
941 EOUT(
"Worker: %s - command %s cannot be assigned without thread", GetName(), cmd.
GetName());
955 LockGuard lock(fThreadMutex);
957 return !fThread.null() && fWorkerActive;
962 if (cmd.
null())
return false;
967 LockGuard lock(fThreadMutex);
971 if (fWorkerActive || (priority == priorityMagic)) {
973 if (priority == priorityMagic) priority = fWorkerPriority;
else
974 if (priority == priorityDefault) priority = 0;
else
975 if (priority == priorityMinimum) priority = -1;
979 DOUT5(
"Fire event for worker %d with priority %d", fWorkerId, priority);
981 fThread()->_Fire(EventId(evntSubmitCommand, fWorkerId, arg), priority);
983 fWorkerFiredEvents++;
989 DOUT0(
"Worker:%s Command %s cannot be submitted - thread is not assigned", GetName(), cmd.
GetName());
998 if (cmd.
null())
return false;
1000 LockGuard lock(fThreadMutex);
1002 DOUT3(
"GetCommandReply %s exe_ready %p Thread %p %s", cmd.
GetName(), exe_ready, fThread(), fThread()->GetName());
1005 if (_FireDoNothingEvent()) {
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());
1028 fWorkerCommands.Cleanup(fThreadMutex,
this,
cmd_false);
1033 ThreadRef thrd = thread();
1035 if (!thrd.null() && thrd.IsItself()) {
1036 thrd.RunEventLoop(tmout);
1077 return PublisherRef(GetPublisher()).Register(path, ItemName(), h());
1084 if (GetPublisher().
null())
return true;
1086 if (fWorkerHierarchy.null())
1087 fWorkerHierarchy.Create(
"Worker");
1089 for (
unsigned n=0;n<NumChilds();n++) {
1090 Parameter par =
dynamic_cast<ParameterContainer*
> (
GetChild(n));
1091 if (par.null())
continue;
1093 Hierarchy chld = fWorkerHierarchy.FindChild(par.GetName());
1094 if (!chld.null())
continue;
1096 chld = fWorkerHierarchy.CreateHChild(par.GetName());
1098 if (par.IsRatemeter() || (par.Kind() ==
"info") || par.GetField(
"#record").AsBool()) {
1099 chld.EnableHistory(100);
1100 par()->fRecorded =
true;
1103 par.ScanParamFields(&chld()->Fields());
1105 fWorkerHierarchy.MarkChangedItems();
1107 return Publish(fWorkerHierarchy, path);
1113 return PublisherRef(GetPublisher()).Unregister(path, ItemName(), h());
1118 return PublisherRef(GetPublisher()).Subscribe(path, ItemName());
1123 return PublisherRef(GetPublisher()).Unsubscribe(path, ItemName());
1128 if (fPublisher.null())
return;
1134 if (!ref.thread().null()) ref.RemoveWorker(ItemName(), sync);
1141 if (GetObject())
return GetObject()->Submit(cmd);
1149 if (GetObject()==0)
return false;
1150 return GetObject()->Execute(cmd, tmout);
1155 if (GetObject()==0)
return false;
1156 return GetObject()->Execute(cmd, tmout);
1162 return GetObject()->Par(name);
1167 return GetObject() ? GetObject()->HasThread() :
false;
1172 if (GetObject() && ref.GetObject())
1173 return GetObject()->thread()() == ref.GetObject()->thread()();
1181 return GetObject() ? GetObject()->CanSubmitCommand() :
false;
1186 if (GetObject()==0)
return true;
1190 if (tmout>=0) cmd.SetTimeout(tmout);
static const char * ParName()
Command definition class.
Represents command with its arguments.
void AddCaller(Worker *worker, bool *exe_ready=nullptr)
void ReplyFalse()
Reply on the command with false (cmd_false==0) value.
void Reply(int res=cmd_noresult)
Replied on the command.
int GetPriority() const
Returns command priority.
@ kindSubmit
command submitted for execution
@ kindPostponed
command submitted but postponed to not increase execution recursion
@ kindReply
command replied to the worker
@ kindAssign
command assign with the worker, but not yet replied
class, used for direct store of records in JSON/XML form
Represents objects hierarchy of remote (or local) DABC process.
uint64_t GetVersion() const
Returns actual version of hierarchy entry.
dabc::Buffer SaveToBuffer(unsigned kind=stream_Full, uint64_t version=0, unsigned hlimit=0)
Save hierarchy in binary form, relative to specified version.
Mutex * GetHMutex() const
Lock guard for posix mutex.
ThreadRef CurrentThread()
Returns reference on the thread, which is now active.
Reference FindItem(const std::string &name)
bool ParameterEventSubscription(Worker *ptr, bool subscribe, const std::string &mask, bool onlychangeevent=true)
std::string ComposeAddress(const std::string &server, const std::string &itemname="")
ThreadRef CreateThread(const std::string &thrdname, const std::string &classname="", const std::string &devname="")
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
@ flHasThread
flag indicates that object has thread and should be cleaned up via thread
static const char * DfltName()
std::string AsJson() const
Returns field value in JSON format.
std::string AsStr(const std::string &dflt="") const
RecordField GetField(const std::string &name) const
bool HasField(const std::string &name) const
bool SaveTo(HStore &store, bool create_node=true)
Store hierarchy in json/xml form
Reference on the arbitrary object
const char * GetName() const
Return name of referenced object, if object not assigned, returns "---".
Reference GetFolder(const std::string &name, bool force=false)
Return folder of specified name, no special symbols are allowed.
bool null() const
Returns true if reference contains nullptr.
Reference on the dabc::Thread class
bool _ActivateAddonTimeout(unsigned workerid, int priority, double tmout)
void RunEventLoop(double tmout=1.)
Runs thread event loop for specified time.
Uniform Resource Locator interpreter.
void FireWorkerEvent(unsigned evid)
void SubmitWorkerCmd(Command cmd)
void DeleteAddonItself()
This is possibility to delete addon itself, invoking worker command.
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
void DeleteWorker()
This is way to delete worker with addon inclusive.
bool ActivateTimeout(double tmout_sec)
WorkerAddon(const std::string &name)
bool HasThread() const
Returns true when thread is assigned to the worker.
bool SyncWorker(double tmout=-1.)
Synchronize worker with caller thread.
Parameter Par(const std::string &name) const
Returns reference on parameter.
bool Execute(Command cmd, double tmout=-1.)
bool CanSubmitCommand() const
Returns true if command can be submitted to the worker.
bool IsSameThread(const WorkerRef &ref)
Returns true if two workers share same thread.
Active object, which is working inside dabc::Thread.
virtual int PreviewCommand(Command cmd)
This method called before command will be executed.
virtual bool Subscribe(const std::string &path)
bool ActivateTimeout(double tmout_sec)
Method used to produce timeout events in the worker.
CommandDefinition CreateCmdDef(const std::string &name)
int ProcessCommand(dabc::Command cmd)
uint32_t fWorkerId
worker id in thread list, used for events submit
void AssignAddon(WorkerAddon *addon)
Assigns addon to the worker Should be called before worker assigned to the thread.
void ProcessParameterRecording(ParameterContainer *par)
Method to process parameter recording in worker thread.
virtual void ProcessEvent(const EventId &)
Worker(const ConstructorPair &pair)
Special constructor, designed for inherited classes.
bool RegisterForParameterEvent(const std::string &mask, bool onlychangeevent=true)
Subscribe to parameter events from local or remote node.
void ClearThreadRef()
Method to 'forget' thread reference.
bool Submit(Command cmd)
Submit command for execution in the processor.
bool GetCommandReply(dabc::Command &cmd, bool *exe_ready)
void WorkerParameterChanged(bool forcecall, ParameterContainer *par, const std::string &value)
Method called by parameter object which is belong to the worker.
void WorkerSleep(double tmout)
bool CanSubmitCommand() const
Returns true if command can be submitted to worker.
bool Execute(Command cmd, double tmout=-1.)
Execute command in the processor.
bool ExecuteIn(Worker *dest, Command cmd)
Executes command in specified worker.
Command Assign(Command cmd)
! Assign command with processor before command be submitted to other processor This produce ReplyComm...
void CleanupPublisher(bool sync=true)
Release reference on publisher and unsubscribe/unpublish all registered entries.
Parameter Par(const std::string &name) const
Returns reference on worker parameter object.
bool AssignToThread(ThreadRef thrd, bool sync=true)
Assign worker to thread, worker becomes active immediately.
RecordField Cfg(const std::string &name, Command cmd=nullptr) const
Returns configuration field of specified name Configuration value of specified name searched in follo...
virtual int ExecuteCommand(Command cmd)
Main method where commands are executed.
virtual bool PublishPars(const std::string &path)
std::string WorkerAddress(bool full=true)
Return address, which can be used to submit command to the worker If full specified,...
virtual bool DestroyByOwnThread()
Inherited method from Object, invoked at the moment when worker requested to be destroyed by its thre...
bool UnregisterForParameterEvent(const std::string &mask)
Unsubscribe to parameter events from local or remote node.
bool DestroyPar(const std::string &name)
Method must be used if worker wants to destroy parameter.
bool HasThread() const
Indicates if pointer on thread is not zero; thread-safe.
virtual bool Unpublish(const Hierarchy &h, const std::string &path)
bool MakeThreadForWorker(const std::string &thrdname="")
Creates appropriate thread for worker and assign worker to the thread.
std::string ThreadName() const
Returns name of the worker thread; thread-safe
virtual bool Unsubscribe(const std::string &path)
ThreadRef fThread
reference on the thread, once assigned remain whole time
virtual bool Find(ConfigIO &cfg)
Method to locate object in xml file.
ThreadRef thread()
Return reference on the worker thread; thread-safe.
Reference GetPublisher()
Return reference on publisher.
void SetParValue(const std::string &name, const RecordField &v)
Set parameter value and sync with worker hierarchy.
int WorkerPriority() const
void ProcessCoreEvent(EventId)
bool DettachFromThread()
Detach worker from the thread, later worker can be assigned to some other thread Method especially us...
virtual bool ReplyCommand(Command cmd)
Reimplement this method to react on command reply Return true if command can be destroyed by framewor...
virtual void ObjectCleanup()
Central cleanup method for worker.
virtual Parameter CreatePar(const std::string &name, const std::string &kind="")
virtual bool Publish(const Hierarchy &h, const std::string &path)
bool IsOwnThread() const
Returns true if called from thread.
Mutex * fThreadMutex
pointer on main thread mutex
bool FireEvent(uint16_t evid)
XMLNodePointer_t GetParent(XMLNodePointer_t xmlnode)
XMLNodePointer_t GetChild(XMLNodePointer_t xmlnode)
@ parCreated
produced once when parameter is created
@ parModified
produced when parameter value modified. Either every change or after time interval (default = 1 sec)