This is Unofficial EPICS BASE Doxygen Site
pdb.cpp
Go to the documentation of this file.
1 
2 #include <vector>
3 #include <utility>
4 
5 #include <errlog.h>
6 #include <epicsString.h>
7 #include <epicsAtomic.h>
8 
9 // printfs in this file will be redirected for capture
10 #include <epicsStdio.h>
11 
12 #include <dbAccess.h>
13 #include <dbChannel.h>
14 #include <dbStaticLib.h>
15 #include <dbNotify.h>
16 
17 #include <dbEvent.h>
18 
19 #include <pv/pvAccess.h>
20 #include <pv/configuration.h>
21 
22 #include "helper.h"
23 #include "pdbsingle.h"
24 #include "pvif.h"
25 #ifdef USE_MULTILOCK
26 # include "pdbgroup.h"
27 #endif
28 
29 #include <epicsExport.h>
30 
31 namespace pvd = epics::pvData;
32 namespace pva = epics::pvAccess;
33 
35 
36 namespace {
37 
38 struct Splitter {
39  const char sep, *cur, *end;
40  Splitter(const char *s, char sep)
41  :sep(sep), cur(s)
42  {
43  assert(s);
44  end = strchr(cur, sep);
45  }
46  bool operator!() const { return !cur; }
47  bool snip(std::string& ret) {
48  if(!cur) return false;
49  if(end) ret = std::string(cur, end-cur);
50  else ret = std::string(cur);
51  if(end) {
52  cur = end+1;
53  end = strchr(cur, sep);
54  } else {
55  cur = NULL;
56  }
57  return true;
58  }
59 };
60 
61 struct GroupMemberInfo {
62  // consumes builder
63  GroupMemberInfo(const std::string& a, const std::string& b, const std::tr1::shared_ptr<PVIFBuilder>& builder)
64  :pvname(a), pvfldname(b), builder(builder), putorder(0) {}
65 
66  std::string pvname, // aka. name passed to dbChannelOpen()
67  pvfldname; // PVStructure sub-field
68  std::string structID; // ID to assign to sub-field
69  typedef std::set<std::string> triggers_t;
70  triggers_t triggers; // names in GroupInfo::members_names which are post()d on events from pvfldname
71  std::tr1::shared_ptr<PVIFBuilder> builder; // not actually shared, but allows us to be copyable
72  int putorder;
73 
74  bool operator<(const GroupMemberInfo& o) const {
75  return putorder<o.putorder;
76  }
77 };
78 
79 struct GroupInfo {
80  GroupInfo(const std::string& name) : name(name),atomic(Unset),hastriggers(false) {}
81  std::string name, structID;
82 
83  typedef std::vector<GroupMemberInfo> members_t;
84  members_t members;
85 
86  typedef std::map<std::string, size_t> members_map_t;
87  members_map_t members_map;
88 
89  typedef std::set<std::string> triggers_set_t;
90  typedef std::map<std::string, triggers_set_t> triggers_t;
91  triggers_t triggers;
92 
93  enum tribool {Unset,True,False} atomic;
94  bool hastriggers;
95 };
96 
97 // Iterates all PDB records and gathers info() to construct PDB groups
98 struct PDBProcessor
99 {
100  typedef std::map<std::string, GroupInfo> groups_t;
101  groups_t groups;
102 
103  std::string recbase;
104  GroupInfo *curgroup;
105 
106  // validate trigger mappings and process into bit map form
107  void resolveTriggers()
108  {
109  FOREACH(groups_t::iterator, it, end, groups) { // for each group
110  GroupInfo& info = it->second;
111 
112  if(info.hastriggers) {
113  FOREACH(GroupInfo::triggers_t::iterator, it2, end2, info.triggers) { // for each trigger source
114  const std::string& src = it2->first;
115  GroupInfo::triggers_set_t& targets = it2->second;
116 
117  GroupInfo::members_map_t::iterator it2x = info.members_map.find(src);
118  if(it2x==info.members_map.end()) {
119  fprintf(stderr, "Error: Group \"%s\" defines triggers from non-existant field \"%s\"\n",
120  info.name.c_str(), src.c_str());
121  continue;
122  }
123  GroupMemberInfo& srcmem = info.members[it2x->second];
124 
125  if(PDBProviderDebug>2)
126  fprintf(stderr, " pdb trg '%s.%s' -> ",
127  info.name.c_str(), src.c_str());
128 
129  FOREACH(GroupInfo::triggers_set_t::const_iterator, it3, end3, targets) { // for each trigger target
130  const std::string& target = *it3;
131 
132  if(target=="*") {
133  for(size_t i=0; i<info.members.size(); i++) {
134  if(info.members[i].pvname.empty())
135  continue;
136  srcmem.triggers.insert(info.members[i].pvfldname);
137  if(PDBProviderDebug>2)
138  fprintf(stderr, "%s, ", info.members[i].pvfldname.c_str());
139  }
140 
141  } else {
142 
143  GroupInfo::members_map_t::iterator it3x = info.members_map.find(target);
144  if(it3x==info.members_map.end()) {
145  fprintf(stderr, "Error: Group \"%s\" defines triggers to non-existant field \"%s\"\n",
146  info.name.c_str(), target.c_str());
147  continue;
148  }
149  const GroupMemberInfo& targetmem = info.members[it3x->second];
150 
151  if(targetmem.pvname.empty()) {
152  if(PDBProviderDebug>2)
153  fprintf(stderr, "<ignore: %s>, ", targetmem.pvfldname.c_str());
154 
155  } else {
156  // and finally, update source BitSet
157  srcmem.triggers.insert(targetmem.pvfldname);
158  if(PDBProviderDebug>2)
159  fprintf(stderr, "%s, ", targetmem.pvfldname.c_str());
160  }
161  }
162  }
163 
164  if(PDBProviderDebug>2) fprintf(stderr, "\n");
165  }
166  } else {
167  if(PDBProviderDebug>1) fprintf(stderr, " pdb default triggers for '%s'\n", info.name.c_str());
168 
169  FOREACH(GroupInfo::members_t::iterator, it2, end2, info.members) {
170  GroupMemberInfo& mem = *it2;
171  if(mem.pvname.empty())
172  continue;
173 
174  mem.triggers.insert(mem.pvfldname); // default is self trigger
175  }
176  }
177  }
178  }
179 
180  PDBProcessor() : curgroup(NULL)
181  {
182  for(pdbRecordIterator rec; !rec.done(); rec.next())
183  {
184  const char *json = rec.info("Q:group");
185  if(!json) continue;
186 #ifndef USE_MULTILOCK
187  static bool warned;
188  if(!warned) {
189  warned = true;
190  fprintf(stderr, "%s: ignoring info(Q:Group, ...\n", rec.name());
191  }
192 #else
193  if(PDBProviderDebug>2) {
194  fprintf(stderr, "%s: info(Q:Group, ...\n", rec.name());
195  }
196 
197  try {
198  GroupConfig conf;
199  GroupConfig::parse(json, conf);
200  if(!conf.warning.empty())
201  fprintf(stderr, "%s: warning(s) from info(Q:group, ...\n%s", rec.name(), conf.warning.c_str());
202 
203  recbase = rec.name();
204  recbase += ".";
205 
206  for(GroupConfig::groups_t::const_iterator git=conf.groups.begin(), gend=conf.groups.end();
207  git!=gend; ++git)
208  {
209  const std::string& grpname = git->first;
210  const GroupConfig::Group& grp = git->second;
211 
212  if(dbChannelTest(grpname.c_str())==0) {
213  fprintf(stderr, "%s : Error: Group name conflicts with record name. Ignoring...\n", grpname.c_str());
214  continue;
215  }
216 
217  groups_t::iterator it = groups.find(grpname);
218  if(it==groups.end()) {
219  // lazy creation of group
220  std::pair<groups_t::iterator, bool> ins(groups.insert(std::make_pair(grpname, GroupInfo(grpname))));
221  it = ins.first;
222  }
223  curgroup = &it->second;
224  if(!grp.id.empty())
225  curgroup->structID = grp.id;
226 
227  for(GroupConfig::Group::fields_t::const_iterator fit=grp.fields.begin(), fend=grp.fields.end();
228  fit!=fend; ++fit)
229  {
230  const std::string& fldname = fit->first;
231  const GroupConfig::Field& fld = fit->second;
232 
233  GroupInfo::members_map_t::const_iterator oldgrp(curgroup->members_map.find(fldname));
234  if(oldgrp!=curgroup->members_map.end()) {
235  fprintf(stderr, "%s.%s Warning: ignoring duplicate mapping %s%s\n",
236  grpname.c_str(), fldname.c_str(),
237  recbase.c_str(), fld.channel.c_str());
238  continue;
239  }
240 
241  std::tr1::shared_ptr<PVIFBuilder> builder(PVIFBuilder::create(fld.type));
242 
243  curgroup->members.push_back(GroupMemberInfo(fld.channel.empty() ? fld.channel : recbase + fld.channel, fldname, builder));
244  curgroup->members.back().structID = fld.id;
245  curgroup->members.back().putorder = fld.putorder;
246  curgroup->members_map[fldname] = (size_t)-1; // placeholder see below
247 
248  if(PDBProviderDebug>2) {
249  fprintf(stderr, " pdb map '%s.%s' <-> '%s'\n",
250  curgroup->name.c_str(),
251  curgroup->members.back().pvfldname.c_str(),
252  curgroup->members.back().pvname.c_str());
253  }
254 
255  if(!fld.trigger.empty()) {
256  GroupInfo::triggers_t::iterator it = curgroup->triggers.find(fldname);
257  if(it==curgroup->triggers.end()) {
258  std::pair<GroupInfo::triggers_t::iterator, bool> ins(curgroup->triggers.insert(
259  std::make_pair(fldname, GroupInfo::triggers_set_t())));
260  it = ins.first;
261  }
262 
263  Splitter sep(fld.trigger.c_str(), ',');
264  std::string target;
265 
266  while(sep.snip(target)) {
267  curgroup->hastriggers = true;
268  it->second.insert(target);
269  }
270  }
271  }
272 
273  if(grp.atomic_set) {
274  GroupInfo::tribool V = grp.atomic ? GroupInfo::True : GroupInfo::False;
275 
276  if(curgroup->atomic!=GroupInfo::Unset && curgroup->atomic!=V)
277  fprintf(stderr, "%s Warning: pdb atomic setting inconsistent '%s'\n",
278  grpname.c_str(), curgroup->name.c_str());
279 
280  curgroup->atomic=V;
281 
282  if(PDBProviderDebug>2)
283  fprintf(stderr, " pdb atomic '%s' %s\n",
284  curgroup->name.c_str(), curgroup->atomic ? "YES" : "NO");
285  }
286  }
287 
288  }catch(std::exception& e){
289  fprintf(stderr, "%s: Error parsing info(\"Q:group\", ... : %s\n",
290  rec.record()->name, e.what());
291  }
292 #endif // USE_MULTILOCK
293  }
294 
295  // re-sort GroupInfo::members to ensure the shorter names appear first
296  // allows use of 'existing' PVIFBuilder on leaves.
297  for(groups_t::iterator it = groups.begin(), end = groups.end(); it!=end; ++it)
298  {
299  GroupInfo& info = it->second;
300  std::sort(info.members.begin(),
301  info.members.end());
302 
303  info.members_map.clear();
304 
305  for(size_t i=0, N=info.members.size(); i<N; i++)
306  {
307  info.members_map[info.members[i].pvfldname] = i;
308  }
309  }
310 
311  resolveTriggers();
312  // must not re-sort members after this point as resolveTriggers()
313  // has stored array indicies.
314  }
315 
316 };
317 }
318 
320 
321 PDBProvider::PDBProvider(const epics::pvAccess::Configuration::const_shared_pointer &)
322 {
323  /* Long view
324  * 1. PDBProcessor collects info() tags and builds config of groups and group fields
325  * (including those w/o a dbChannel)
326  * 2. Build pvd::Structure and discard those w/o dbChannel
327  * 3. Build the lockers for the triggers of each group field
328  */
329  PDBProcessor proc;
332 
333  pvd::StructureConstPtr _options(fcreate->createFieldBuilder()
334  ->addNestedStructure("_options")
335  ->add("queueSize", pvd::pvUInt)
336  ->add("atomic", pvd::pvBoolean)
337  ->endNested()
338  ->createStructure());
339 
340 #ifdef USE_MULTILOCK
341  // assemble group PVD structure definitions and build dbLockers
342  FOREACH(PDBProcessor::groups_t::const_iterator, it, end, proc.groups)
343  {
344  const GroupInfo &info=it->second;
345  try{
346  if(persist_pv_map.find(info.name)!=persist_pv_map.end())
347  throw std::runtime_error("name already in used");
348 
349  PDBGroupPV::shared_pointer pv(new PDBGroupPV());
350  pv->weakself = pv;
351  pv->name = info.name;
352 
353  pv->pgatomic = info.atomic!=GroupInfo::False; // default true if Unset
354  pv->monatomic = info.hastriggers;
355 
356  // some gymnastics because Info isn't copyable
358  typedef std::map<std::string, size_t> members_map_t;
359  members_map_t members_map;
360  {
361  size_t nchans = 0;
362  for(size_t i=0, N=info.members.size(); i<N; i++)
363  if(!info.members[i].pvname.empty())
364  nchans++;
366  members.swap(temp);
367  }
368 
369  std::vector<dbCommon*> records(members.size());
370 
371  pvd::FieldBuilderPtr builder(fcreate->createFieldBuilder());
372  builder = builder->add("record", _options);
373 
374  if(!info.structID.empty())
375  builder = builder->setId(info.structID);
376 
377  for(size_t i=0, J=0, N=info.members.size(); i<N; i++)
378  {
379  const GroupMemberInfo &mem = info.members[i];
380 
381  // parse down attachment point to build/traverse structure
382  FieldName parts(mem.pvfldname);
383 
384  if(!parts.empty()) {
385  for(size_t j=0; j<parts.size()-1; j++) {
386  if(parts[j].isArray())
387  builder = builder->addNestedStructureArray(parts[j].name);
388  else
389  builder = builder->addNestedStructure(parts[j].name);
390  }
391  }
392 
393  if(!mem.structID.empty())
394  builder = builder->setId(mem.structID);
395 
396  DBCH chan;
397  if(!mem.pvname.empty()) {
398  DBCH temp(mem.pvname);
399  unsigned ftype = dbChannelFieldType(temp);
400 
401  // can't include in multi-locking
402  if(ftype>=DBF_INLINK && ftype<=DBF_FWDLINK)
403  throw std::runtime_error("Can't include link fields in group");
404 
405  chan.swap(temp);
406  }
407 
408  if(!parts.empty())
409  builder = mem.builder->dtype(builder, parts.back().name, chan);
410  else
411  builder = mem.builder->dtype(builder, "", chan);
412 
413  if(!parts.empty()) {
414  for(size_t j=0; j<parts.size()-1; j++)
415  builder = builder->endNested();
416  }
417 
418  if(!mem.pvname.empty()) {
419  members_map[mem.pvfldname] = J;
420  PDBGroupPV::Info& info = members[J];
421 
422  info.allowProc = mem.putorder != std::numeric_limits<int>::min();
423  info.builder = PTRMOVE(mem.builder);
424  assert(info.builder.get());
425 
426  info.attachment.swap(parts);
427  info.chan.swap(chan);
428 
429  // info.triggers populated below
430 
431  assert(info.chan);
432  records[J] = dbChannelRecord(info.chan);
433 
434  J++;
435  }
436  }
437  pv->members.swap(members);
438 
439  pv->fielddesc = builder->createStructure();
440  pv->complete = pvbuilder->createPVStructure(pv->fielddesc);
441 
442  pv->complete->getSubFieldT<pvd::PVBoolean>("record._options.atomic")->put(pv->monatomic);
443 
444  DBManyLock L(&records[0], records.size(), 0);
445  pv->locker.swap(L);
446 
447  // construct locker for records triggered by each member
448  for(size_t i=0, J=0, N=info.members.size(); i<N; i++)
449  {
450  const GroupMemberInfo &mem = info.members[i];
451  if(mem.pvname.empty()) continue;
452  PDBGroupPV::Info& info = pv->members[J++];
453 
454  if(mem.triggers.empty()) continue;
455 
456  std::vector<dbCommon*> trig_records;
457  trig_records.reserve(mem.triggers.size());
458 
459  FOREACH(GroupMemberInfo::triggers_t::const_iterator, it, end, mem.triggers) {
460  members_map_t::const_iterator imap(members_map.find(*it));
461  if(imap==members_map.end())
462  throw std::logic_error("trigger resolution missed map to non-dbChannel");
463 
464  info.triggers.push_back(imap->second);
465  trig_records.push_back(records[imap->second]);
466  }
467 
468  DBManyLock L(&trig_records[0], trig_records.size(), 0);
469  info.locker.swap(L);
470  }
471 
472  persist_pv_map[info.name] = pv;
473 
474  }catch(std::exception& e){
475  fprintf(stderr, "%s: Error Group not created: %s\n", info.name.c_str(), e.what());
476  }
477  }
478 #else
479  if(!proc.groups.empty()) {
480  fprintf(stderr, "Group(s) were defined, but need Base >=3.16.0.2 to function. Ignoring.\n");
481  }
482 #endif // USE_MULTILOCK
483 
484  event_context = db_init_events();
485  if(!event_context)
486  throw std::runtime_error("Failed to create dbEvent context");
487  int ret = db_start_events(event_context, "PDB-event", NULL, NULL, epicsThreadPriorityCAServerLow-1);
488  if(ret!=DB_EVENT_OK)
489  throw std::runtime_error("Failed to stsart dbEvent context");
490 
491  // setup group monitors
492 #ifdef USE_MULTILOCK
493  for(persist_pv_map_t::iterator next = persist_pv_map.begin(),
494  end = persist_pv_map.end(),
495  it = next!=end ? next++ : end;
496  it != end; it = next==end ? end : next++)
497  {
498  const PDBPV::shared_pointer& ppv = it->second;
499  PDBGroupPV *pv = dynamic_cast<PDBGroupPV*>(ppv.get());
500  if(!pv)
501  continue;
502  try {
503 
504  // prepare for monitor
505 
506  size_t i=0;
508  {
509  PDBGroupPV::Info& info = *it2;
510  info.evt_VALUE.index = info.evt_PROPERTY.index = i++;
511  info.evt_VALUE.self = info.evt_PROPERTY.self = pv;
512  assert(info.chan);
513 
514  info.pvif.reset(info.builder->attach(info.chan, pv->complete, info.attachment));
515 
516  // TODO: don't need evt_PROPERTY for PVIF plain
517  info.evt_PROPERTY.create(event_context, info.chan, &pdb_group_event, DBE_PROPERTY);
518 
519  if(!info.triggers.empty()) {
520  info.evt_VALUE.create(event_context, info.chan, &pdb_group_event, DBE_VALUE|DBE_ALARM);
521  }
522  }
523  }catch(std::exception& e){
524  fprintf(stderr, "%s: Error during dbEvent setup : %s\n", pv->name.c_str(), e.what());
525  persist_pv_map.erase(it);
526  }
527  }
528 #endif // USE_MULTILOCK
529  epics::atomic::increment(num_instances);
530 }
531 
533 {
534  epics::atomic::decrement(num_instances);
535 
536  destroy();
537 }
538 
540 {
541  dbEventCtx ctxt = NULL;
542 
543  persist_pv_map_t ppv;
544  {
545  epicsGuard<epicsMutex> G(transient_pv_map.mutex());
546  persist_pv_map.swap(ppv);
547  std::swap(ctxt, event_context);
548  }
549  ppv.clear(); // indirectly calls all db_cancel_events()
550  if(ctxt) db_close_events(ctxt);
551 }
552 
553 std::string PDBProvider::getProviderName() { return "QSRV"; }
554 
555 namespace {
556 struct ChannelFindRequesterNOOP : public pva::ChannelFind
557 {
558  const pva::ChannelProvider::weak_pointer provider;
559  ChannelFindRequesterNOOP(const pva::ChannelProvider::shared_pointer& prov) : provider(prov) {}
560  virtual ~ChannelFindRequesterNOOP() {}
561  virtual void destroy() {}
562  virtual std::tr1::shared_ptr<pva::ChannelProvider> getChannelProvider() { return provider.lock(); }
563  virtual void cancel() {}
564 };
565 }
566 
567 pva::ChannelFind::shared_pointer
568 PDBProvider::channelFind(const std::string &channelName, const pva::ChannelFindRequester::shared_pointer &requester)
569 {
570  pva::ChannelFind::shared_pointer ret(new ChannelFindRequesterNOOP(shared_from_this()));
571 
572  bool found = false;
573  {
574  epicsGuard<epicsMutex> G(transient_pv_map.mutex());
575  if(persist_pv_map.find(channelName)!=persist_pv_map.end()
576  || transient_pv_map.find(channelName)
577  || dbChannelTest(channelName.c_str())==0)
578  found = true;
579  }
580  requester->channelFindResult(pvd::Status(), ret, found);
581  return ret;
582 }
583 
584 pva::ChannelFind::shared_pointer
585 PDBProvider::channelList(pva::ChannelListRequester::shared_pointer const & requester)
586 {
587  pva::ChannelFind::shared_pointer ret;
589  for(pdbRecordIterator rec; !rec.done(); rec.next())
590  {
591  names.push_back(rec.name());
592  }
593  {
594  epicsGuard<epicsMutex> G(transient_pv_map.mutex());
595 
596  for(persist_pv_map_t::const_iterator it=persist_pv_map.begin(), end=persist_pv_map.end();
597  it != end; ++it)
598  {
599  names.push_back(it->first);
600  }
601  }
602  // check for duplicates?
603  requester->channelListResult(pvd::Status::Ok,
604  shared_from_this(),
605  pvd::freeze(names), false);
606  return ret;
607 }
608 
609 pva::Channel::shared_pointer
610 PDBProvider::createChannel(std::string const & channelName,
611  pva::ChannelRequester::shared_pointer const & channelRequester,
612  short priority)
613 {
614  return createChannel(channelName, channelRequester, priority, "???");
615 }
616 
617 pva::Channel::shared_pointer
618 PDBProvider::createChannel(std::string const & channelName,
619  pva::ChannelRequester::shared_pointer const & requester,
620  short priority, std::string const & address)
621 {
622  pva::Channel::shared_pointer ret;
623  PDBPV::shared_pointer pv;
625 
626  {
627  epicsGuard<epicsMutex> G(transient_pv_map.mutex());
628 
629  pv = transient_pv_map.find(channelName);
630  if(!pv) {
631  persist_pv_map_t::const_iterator it=persist_pv_map.find(channelName);
632  if(it!=persist_pv_map.end()) {
633  pv = it->second;
634  }
635  }
636  if(!pv) {
637  dbChannel *pchan = dbChannelCreate(channelName.c_str());
638  if(pchan) {
639  DBCH chan(pchan);
640  pv.reset(new PDBSinglePV(chan, shared_from_this()));
641  transient_pv_map.insert(channelName, pv);
642  PDBSinglePV::shared_pointer spv = std::tr1::static_pointer_cast<PDBSinglePV>(pv);
643  spv->weakself = spv;
644  spv->activate();
645  }
646  }
647  }
648  if(pv) {
649  ret = pv->connect(shared_from_this(), requester);
650  }
651  if(!ret) {
652  status = pvd::Status(pvd::Status::STATUSTYPE_ERROR, "not found");
653  }
654  requester->channelCreated(status, ret);
655  return ret;
656 }
657 
658 FieldName::FieldName(const std::string& pv)
659 {
660  if(pv.empty())
661  return;
662  Splitter S(pv.c_str(), '.');
663  std::string part;
664  while(S.snip(part)) {
665  if(part.empty())
666  throw std::runtime_error("Empty field component in: "+pv);
667 
668  if(part[part.size()-1]==']') {
669  const size_t open = part.find_last_of('['),
670  N = part.size();
671  bool ok = open!=part.npos;
672  epicsUInt32 index = 0;
673  for(size_t i=open+1; ok && i<(N-1); i++) {
674  ok &= part[i]>='0' && part[i]<='9';
675  index = 10*index + part[i] - '0';
676  }
677  if(!ok)
678  throw std::runtime_error("Invalid field array sub-script in : "+pv);
679 
680  parts.push_back(Component(part.substr(0, open), index));
681 
682  } else {
683  parts.push_back(Component(part));
684  }
685  }
686  if(parts.empty())
687  throw std::runtime_error("Empty field name");
688  if(parts.back().isArray())
689  throw std::runtime_error("leaf field may not have sub-script : "+pv);
690 }
691 
694 {
695  if(ppsar)
696  *ppsar = 0;
697 
698  pvd::PVFieldPtr ret = S;
699  for(size_t i=0, N=parts.size(); i<N; i++) {
700  pvd::PVStructure* parent = dynamic_cast<pvd::PVStructure*>(ret.get());
701  if(!parent)
702  throw std::runtime_error("mid-field is not structure");
703 
704  ret = parent->getSubFieldT(parts[i].name);
705 
706  if(parts[i].isArray()) {
707  pvd::PVStructureArray* sarr = dynamic_cast<pvd::PVStructureArray*>(ret.get());
708  if(!sarr)
709  throw std::runtime_error("indexed field is not structure array");
710 
711  if(ppsar && !*ppsar)
712  *ppsar = sarr;
713 
715 
716  if(V.size()<=parts[i].index || !V[parts[i].index]) {
717  // automatic re-size and ensure non-null
718  V.clear(); // drop our extra ref so that reuse() might avoid a copy
720 
721  if(E.size()<=parts[i].index)
722  E.resize(parts[i].index+1);
723 
724  if(!E[parts[i].index])
725  E[parts[i].index] = pvd::getPVDataCreate()->createPVStructure(sarr->getStructureArray()->getStructure());
726 
727  ret = E[parts[i].index];
728 
729  sarr->replace(pvd::freeze(E));
730 
731  } else {
732  ret = V[parts[i].index];
733  }
734  }
735  }
736  return ret;
737 }
738 
739 void FieldName::show() const
740 {
741  if(parts.empty()) {
742  printf("/");
743  return;
744  }
745 
746  bool first = true;
747  for(size_t i=0, N=parts.size(); i<N; i++)
748  {
749  if(!first) {
750  printf(".");
751  } else {
752  first = false;
753  }
754  if(parts[i].isArray())
755  printf("%s[%u]", parts[i].name.c_str(), (unsigned)parts[i].index);
756  else
757  printf("%s", parts[i].name.c_str());
758  }
759 }
760 
761 extern "C" {
763 }
static PVIFBuilder * create(const std::string &name)
Definition: pvif.cpp:1218
DBManyLock locker
Definition: pdbgroup.h:96
members_t members
Definition: pdbgroup.h:104
virtual epics::pvAccess::ChannelFind::shared_pointer channelList(epics::pvAccess::ChannelListRequester::shared_pointer const &channelListRequester) OVERRIDE FINAL
Definition: pdb.cpp:585
void * self
Definition: pvif.h:218
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
::epics::pvData::shared_vector< T > svector
Definition: pvData.h:1184
std::tr1::shared_ptr< detail::SharedPut > put
A holder for a contiguous piece of memory.
Definition: sharedVector.h:27
void swap(FieldName &o)
Definition: pvif.h:329
#define FOREACH(ITERTYPE, IT, END, C)
Definition: helper.h:6
pvd::Status status
std::string id
Definition: pdbgroup.h:25
static Status Ok
Definition: status.h:47
int i
Definition: scan.c:967
StructureArrayConstPtr getStructureArray() const
Definition: pvData.h:1278
void pdb_group_event(void *user_arg, struct dbChannel *chan, int eventsRemaining, struct db_field_log *pfl)
Definition: pdbgroup.cpp:30
#define min(x, y)
Definition: flexdef.h:78
::epics::pvData::shared_vector< PVStructurePtr > svector
Definition: pvData.h:1248
Definition: tool_lib.h:67
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
int PDBProviderDebug
Definition: pdb.cpp:34
#define printf
Definition: epicsStdio.h:41
virtual void replace(const const_svector &other) OVERRIDE FINAL
Definition: pvData.h:1299
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
::epics::pvData::shared_vector< const PVStructurePtr > const_svector
Definition: pvData.h:1249
#define NULL
Definition: catime.c:38
std::string channel
Definition: pdbgroup.h:25
#define DBE_ALARM
Definition: caeventmask.h:41
virtual void destroy() OVERRIDE FINAL
Definition: pdb.cpp:539
unsigned int epicsUInt32
Definition: epicsTypes.h:43
PVField is the base class for each PVData field.
Definition: pvData.h:152
void clear()
Clear contents. size() becomes 0.
Definition: sharedVector.h:210
std::tr1::shared_ptr< FieldBuilder > FieldBuilderPtr
std::string type
Definition: pdbgroup.h:25
void swap(DBCH &)
Definition: pvif.cpp:67
static size_t num_instances
Definition: pdb.h:67
std::string warning
Definition: pdbgroup.h:57
std::tr1::shared_ptr< PVDataCreate > PVDataCreatePtr
Definition: pvData.h:124
epics::pvData::PVStructurePtr complete
Definition: pdbgroup.h:108
#define DBE_VALUE
Definition: caeventmask.h:38
Holds all PVA related.
Definition: pvif.h:34
bool empty() const
Definition: pvif.h:333
pvData
Definition: monitor.h:428
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(std::string const &channelName, epics::pvAccess::ChannelFindRequester::shared_pointer const &channelFindRequester) OVERRIDE FINAL
Definition: pdb.cpp:568
void show() const
Definition: pdb.cpp:739
weak_pointer weakself
Definition: pdbsingle.h:26
std::map< std::string, PDBPV::shared_pointer > persist_pv_map_t
Definition: pdb.h:59
bool operator<(shared_ptr< T > const &a, shared_ptr< U > const &b) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:778
void create(dbEventCtx ctx, dbChannel *ch, EVENTFUNC *fn, unsigned mask)
Definition: pvif.h:224
const ChannelProcessRequester::weak_pointer requester
Definition: pvAccess.cpp:68
groups_t groups
Definition: pdbgroup.h:56
void swap(shared_vector_base &o)
Swap the contents of this vector with another.
Definition: sharedVector.h:199
virtual std::string getProviderName() OVERRIDE FINAL
Definition: pdb.cpp:553
std::string name
Definition: pdbgroup.h:88
Data interface for a structure,.
Definition: pvData.h:712
size_t size() const
Definition: pvif.h:334
bool operator!() const BOOST_NOEXCEPT
size_t size() const
Number of elements visible through this vector.
Definition: sharedVector.h:220
FORCE_INLINE const FieldCreatePtr & getFieldCreate()
epics::pvData::PVFieldPtr lookup(const epics::pvData::PVStructurePtr &S, epics::pvData::PVField **ppenclose) const
Definition: pdb.cpp:693
const Component & back() const
Definition: pvif.h:336
Definition: pvif.h:72
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
#define DBE_PROPERTY
Definition: caeventmask.h:42
#define epicsThreadPriorityCAServerLow
Definition: epicsThread.h:80
Data class for a structureArray.
Definition: pvData.h:1236
FORCE_INLINE std::tr1::shared_ptr< PVField > getSubFieldT(A a)
Definition: pvData.h:786
std::string trigger
Definition: pdbgroup.h:25
std::string name
Definition: pvif.h:315
virtual ~PDBProvider()
Definition: pdb.cpp:532
unsigned index
Definition: pvif.h:219
Class that holds the data for each possible scalar type.
Definition: pvData.h:54
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
std::tr1::shared_ptr< FieldCreate > FieldCreatePtr
FieldName attachment
Definition: pdbgroup.h:93
DBEvent evt_VALUE
Definition: pdbgroup.h:98
virtual const_svector view() const OVERRIDE FINAL
Fetch a read-only view of the current array data.
Definition: pvData.h:1297
epicsExportAddress(int, PDBProviderDebug)
static void parse(const char *txt, GroupConfig &result)
void swap(shared_ptr< T > &a, shared_ptr< T > &b) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:783
triggers_t triggers
Definition: pdbgroup.h:95
std::string id
Definition: pdbgroup.h:43
p2p::auto_ptr< PVIF > pvif
Definition: pdbgroup.h:97
#define stderr
Definition: epicsStdio.h:32
#define PTRMOVE(AUTO)
Definition: helper.h:15
fields_t fields
Definition: pdbgroup.h:41
virtual epics::pvAccess::Channel::shared_pointer createChannel(std::string const &channelName, epics::pvAccess::ChannelRequester::shared_pointer const &channelRequester, short priority=PRIORITY_DEFAULT) OVERRIDE FINAL
std::tr1::shared_ptr< PVIFBuilder > builder
Definition: pdbgroup.h:92
DBEvent evt_PROPERTY
Definition: pdbgroup.h:98
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
PDBProvider(const epics::pvAccess::Configuration::const_shared_pointer &=epics::pvAccess::Configuration::const_shared_pointer())
Definition: pdb.cpp:321
FieldName()
Definition: pvif.h:326
Exporting IOC objects.
bool done() const
Definition: pvif.h:164