pvDatabaseCPP  4.7.1-dev
pvRecord.cpp
Go to the documentation of this file.
1 /* pvRecord.cpp */
11 #include <list>
12 #include <epicsGuard.h>
13 #include <epicsThread.h>
14 #include <pv/status.h>
15 #include <pv/pvAccess.h>
16 #include <pv/createRequest.h>
17 #include <pv/pvaVersion.h>
18 #include <pv/pvaVersionNum.h>
19 #include <pv/monitor.h>
20 #include <pv/convert.h>
21 #include <pv/rpcService.h>
22 #include <pv/timeStamp.h>
23 #include <pv/pvData.h>
24 #include <pv/rpcService.h>
25 #include <pv/pvTimeStamp.h>
26 
27 #define epicsExportSharedSymbols
28 #include "pv/pvStructureCopy.h"
29 #include "pv/pvDatabase.h"
30 
31 using std::tr1::static_pointer_cast;
32 using namespace epics::pvData;
33 using namespace epics::pvDatabase;
34 using namespace std;
35 
36 namespace epics { namespace pvDatabase {
37 
38 PVRecordPtr PVRecord::create(
39  string const &recordName,
40  PVStructurePtr const & pvStructure,
41  int asLevel,
42  const std::string& asGroup)
43 {
44  PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure,asLevel,asGroup));
45  if(!pvRecord->init()) {
46  pvRecord.reset();
47  }
48  return pvRecord;
49 }
50 
51 
52 PVRecord::PVRecord(
53  string const & recordName,
54  PVStructurePtr const & pvStructure,
55  int asLevel_,
56  const std::string& asGroup_)
57 : recordName(recordName),
58  pvStructure(pvStructure),
59  depthGroupPut(0),
60  traceLevel(0),
61  isAddListener(false),
62  asLevel(asLevel_),
63  asGroup(asGroup_)
64 {
65 }
66 
68 {
69  if(traceLevel>0) {
70  cout << "~PVRecord() " << recordName << endl;
71  }
72 }
73 
74 void PVRecord::unlistenClients()
75 {
76  epicsGuard<epics::pvData::Mutex> guard(mutex);
77  for(std::list<PVListenerWPtr>::iterator iter = pvListenerList.begin();
78  iter!=pvListenerList.end();
79  iter++ )
80  {
81  PVListenerPtr listener = iter->lock();
82  if(!listener) continue;
83  if(traceLevel>0) {
84  cout << "PVRecord::remove() calling listener->unlisten " << recordName << endl;
85  }
86  listener->unlisten(shared_from_this());
87  }
88  pvListenerList.clear();
89  for (std::list<PVRecordClientWPtr>::iterator iter = clientList.begin();
90  iter!=clientList.end();
91  iter++ )
92  {
93  PVRecordClientPtr client = iter->lock();
94  if(!client) continue;
95  if(traceLevel>0) {
96  cout << "PVRecord::remove() calling client->detach " << recordName << endl;
97  }
98  client->detach(shared_from_this());
99  }
100  clientList.clear();
101 }
102 
103 
105 {
106  if(traceLevel>0) {
107  cout << "PVRecord::remove() " << recordName << endl;
108  }
109  unlistenClients();
110  epicsGuard<epics::pvData::Mutex> guard(mutex);
111  PVDatabasePtr pvDatabase(PVDatabase::getMaster());
112  if(pvDatabase) pvDatabase->removeFromMap(shared_from_this());
113  pvTimeStamp.detach();
114 }
115 
117 {
118  PVRecordStructurePtr parent;
119  pvRecordStructure = PVRecordStructurePtr(
120  new PVRecordStructure(pvStructure,parent,shared_from_this()));
121  pvRecordStructure->init();
122  PVFieldPtr pvField = pvStructure->getSubField("timeStamp");
123  if(pvField) pvTimeStamp.attach(pvField);
124 }
125 
127 {
128  if(traceLevel>2) {
129  cout << "PVRecord::process() " << recordName << endl;
130  }
131  if(pvTimeStamp.isAttached()) {
132  pvTimeStamp.get(timeStamp);
133  timeStamp.getCurrent();
134  pvTimeStamp.set(timeStamp);
135  }
136 }
137 
138 
139 PVRecordFieldPtr PVRecord::findPVRecordField(PVFieldPtr const & pvField)
140 {
141  return findPVRecordField(pvRecordStructure,pvField);
142 }
143 
145  PVRecordStructurePtr const & pvrs,
146  PVFieldPtr const & pvField)
147 {
148  size_t desiredOffset = pvField->getFieldOffset();
149  PVFieldPtr pvf = pvrs->getPVField();
150  size_t offset = pvf->getFieldOffset();
151  if(offset==desiredOffset) return pvrs;
152  PVRecordFieldPtrArrayPtr pvrfpap = pvrs->getPVRecordFields();
153  PVRecordFieldPtrArray::iterator iter;
154  for (iter = pvrfpap.get()->begin(); iter!=pvrfpap.get()->end(); iter++ ) {
155  PVRecordFieldPtr pvrf = *iter;
156  pvf = pvrf->getPVField();
157  offset = pvf->getFieldOffset();
158  if(offset==desiredOffset) return pvrf;
159  size_t nextOffset = pvf->getNextFieldOffset();
160  if(nextOffset<=desiredOffset) continue;
161  return findPVRecordField(
162  static_pointer_cast<PVRecordStructure>(pvrf),
163  pvField);
164  }
165  throw std::logic_error(
166  recordName + " pvField "
167  + pvField->getFieldName() + " not in PVRecord");
168 }
169 
171  if(traceLevel>2) {
172  cout << "PVRecord::lock() " << recordName << endl;
173  }
174  mutex.lock();
175 }
176 
178  if(traceLevel>2) {
179  cout << "PVRecord::unlock() " << recordName << endl;
180  }
181  mutex.unlock();
182 }
183 
185  if(traceLevel>2) {
186  cout << "PVRecord::tryLock() " << recordName << endl;
187  }
188  return mutex.tryLock();
189 }
190 
191 void PVRecord::lockOtherRecord(PVRecordPtr const & otherRecord)
192 {
193  if(traceLevel>2) {
194  cout << "PVRecord::lockOtherRecord() " << recordName << endl;
195  }
196  if(this<otherRecord.get()) {
197  otherRecord->lock();
198  return;
199  }
200  unlock();
201  otherRecord->lock();
202  lock();
203 }
204 
205 bool PVRecord::addPVRecordClient(PVRecordClientPtr const & pvRecordClient)
206 {
207  if(traceLevel>1) {
208  cout << "PVRecord::addPVRecordClient() " << recordName << endl;
209  }
210  epicsGuard<epics::pvData::Mutex> guard(mutex);
211  // clean clientList
212  bool clientListClean = false;
213  while(!clientListClean) {
214  if(clientList.empty()) break;
215  clientListClean = true;
216  std::list<PVRecordClientWPtr>::iterator iter;
217  for (iter = clientList.begin();
218  iter!=clientList.end();
219  iter++ )
220  {
221  PVRecordClientPtr client = iter->lock();
222  if(client) continue;
223  if(traceLevel>1) {
224  cout << "PVRecord::addPVRecordClient() erasing client"
225  << recordName << endl;
226  }
227  clientList.erase(iter);
228  clientListClean = false;
229  break;
230  }
231  }
232  clientList.push_back(pvRecordClient);
233  return true;
234 }
235 
237  PVListenerPtr const & pvListener,
238  epics::pvCopy::PVCopyPtr const & pvCopy)
239 {
240  if(traceLevel>1) {
241  cout << "PVRecord::addListener() " << recordName << endl;
242  }
243  epicsGuard<epics::pvData::Mutex> guard(mutex);
244  pvListenerList.push_back(pvListener);
245  this->pvListener = pvListener;
246  isAddListener = true;
247  pvCopy->traverseMaster(shared_from_this());
248  this->pvListener = PVListenerPtr();;
249  return true;
250 }
251 
252 void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
253 {
254  PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
255  PVListenerPtr listener = pvListener.lock();
256  if(!listener.get()) return;
257  if(isAddListener) {
258  pvRecordField->addListener(listener);
259  } else {
260  pvRecordField->removeListener(listener);
261  }
262 }
263 
265  PVListenerPtr const & pvListener,
266  epics::pvCopy::PVCopyPtr const & pvCopy)
267 {
268  if(traceLevel>1) {
269  cout << "PVRecord::removeListener() " << recordName << endl;
270  }
271  epicsGuard<epics::pvData::Mutex> guard(mutex);
272  std::list<PVListenerWPtr>::iterator iter;
273  for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
274  {
275  PVListenerPtr listener = iter->lock();
276  if(!listener.get()) continue;
277  if(listener.get()==pvListener.get()) {
278  pvListenerList.erase(iter);
279  this->pvListener = pvListener;
280  isAddListener = false;
281  pvCopy->traverseMaster(shared_from_this());
282  this->pvListener = PVListenerPtr();
283  return true;
284  }
285  }
286  return false;
287 }
288 
290 {
291  if(++depthGroupPut>1) return;
292  if(traceLevel>2) {
293  cout << "PVRecord::beginGroupPut() " << recordName << endl;
294  }
295  std::list<PVListenerWPtr>::iterator iter;
296  for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
297  {
298  PVListenerPtr listener = iter->lock();
299  if(!listener.get()) continue;
300  listener->beginGroupPut(shared_from_this());
301  }
302 }
303 
305 {
306  if(--depthGroupPut>0) return;
307  if(traceLevel>2) {
308  cout << "PVRecord::endGroupPut() " << recordName << endl;
309  }
310  std::list<PVListenerWPtr>::iterator iter;
311  for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
312  {
313  PVListenerPtr listener = iter->lock();
314  if(!listener.get()) continue;
315  listener->endGroupPut(shared_from_this());
316  }
317 }
318 
319 std::ostream& operator<<(std::ostream& o, const PVRecord& record)
320 {
321  o << format::indent() << "record " << record.getRecordName() << endl;
322  {
323  format::indent_scope s(o);
324  o << *record.getPVRecordStructure()->getPVStructure();
325  }
326  return o;
327 }
328 
330  PVFieldPtr const & pvField,
331  PVRecordStructurePtr const &parent,
332  PVRecordPtr const & pvRecord)
333 : pvField(pvField),
334  isStructure(pvField->getField()->getType()==structure ? true : false),
335  master(),
336  parent(parent),
337  pvRecord(pvRecord)
338 {
339 }
340 
342 {
343  fullFieldName = pvField.lock()->getFieldName();
344  PVRecordStructurePtr pvParent(parent.lock());
345  while(pvParent) {
346  string parentName = pvParent->getPVField()->getFieldName();
347  if(parentName.size()>0) {
348  fullFieldName = pvParent->getPVField()->getFieldName()
349  + '.' + fullFieldName;
350  }
351  pvParent = pvParent->getParent();
352  }
353  PVRecordPtr pvRecord(this->pvRecord.lock());
354  if(fullFieldName.size()>0) {
355  fullName = pvRecord->getRecordName() + '.' + fullFieldName;
356  } else {
357  fullName = pvRecord->getRecordName();
358  }
359  pvField.lock()->setPostHandler(shared_from_this());
360 }
361 
363 {
364  return parent.lock();
365 }
366 
367 PVFieldPtr PVRecordField::getPVField() {return pvField.lock();}
368 
369 string PVRecordField::getFullFieldName() {return fullFieldName; }
370 
371 string PVRecordField::getFullName() {return fullName; }
372 
373 PVRecordPtr PVRecordField::getPVRecord() {return pvRecord.lock();}
374 
375 bool PVRecordField::addListener(PVListenerPtr const & pvListener)
376 {
377  PVRecordPtr pvRecord(this->pvRecord.lock());
378  if(pvRecord && pvRecord->getTraceLevel()>1) {
379  cout << "PVRecordField::addListener() " << getFullName() << endl;
380  }
381  pvListenerList.push_back(pvListener);
382  return true;
383 }
384 
385 void PVRecordField::removeListener(PVListenerPtr const & pvListener)
386 {
387  PVRecordPtr pvRecord(this->pvRecord.lock());
388  if(pvRecord && pvRecord->getTraceLevel()>1) {
389  cout << "PVRecordField::removeListener() " << getFullName() << endl;
390  }
391  std::list<PVListenerWPtr>::iterator iter;
392  for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
393  PVListenerPtr listener = iter->lock();
394  if(!listener.get()) continue;
395  if(listener.get()==pvListener.get()) {
396  pvListenerList.erase(iter);
397  return;
398  }
399  }
400 }
401 
403 {
404  PVRecordStructurePtr parent(this->parent.lock());;
405  if(parent) {
406  parent->postParent(shared_from_this());
407  }
408  postSubField();
409 }
410 
412 {
413  PVRecordStructurePtr pvrs = static_pointer_cast<PVRecordStructure>(shared_from_this());
414  std::list<PVListenerWPtr>::iterator iter;
415  for(iter = pvListenerList.begin(); iter != pvListenerList.end(); ++iter)
416  {
417  PVListenerPtr listener = iter->lock();
418  if(!listener.get()) continue;
419  listener->dataPut(pvrs,subField);
420  }
421  PVRecordStructurePtr parent(this->parent.lock());
422  if(parent) {
423  parent->postParent(subField);
424  }
425 }
426 
428 {
429  // Master field pointer will be set in only one subfield
430  PVRecordStructurePtr master(this->master.lock());
431  if(master) {
432  master->callListener();
433  }
434  callListener();
435  if(isStructure) {
436  PVRecordStructurePtr pvrs =
437  static_pointer_cast<PVRecordStructure>(shared_from_this());
438  PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
439  PVRecordFieldPtrArray::iterator iter;
440  for(iter = pvRecordFields->begin() ; iter !=pvRecordFields->end(); iter++) {
441  (*iter)->postSubField();
442  }
443  }
444 }
445 
446 void PVRecordField::callListener()
447 {
448  std::list<PVListenerWPtr>::iterator iter;
449  for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
450  PVListenerPtr listener = iter->lock();
451  if(!listener.get()) continue;
452  listener->dataPut(shared_from_this());
453  }
454 }
455 
457  PVStructurePtr const &pvStructure,
458  PVRecordStructurePtr const &parent,
459  PVRecordPtr const & pvRecord)
460 :
461  PVRecordField(pvStructure,parent,pvRecord),
462  pvStructure(pvStructure),
463  pvRecordFields(new PVRecordFieldPtrArray)
464 {
465 }
466 
468 {
470  const PVFieldPtrArray & pvFields = pvStructure.lock()->getPVFields();
471  size_t numFields = pvFields.size();
472  pvRecordFields->reserve( numFields);
473  PVRecordStructurePtr self =
474  static_pointer_cast<PVRecordStructure>(shared_from_this());
475  PVRecordPtr pvRecord = getPVRecord();
476  static bool masterFieldCallbackSet = false;
477  bool isMasterField = (!getFullFieldName().size());
478  if (isMasterField) {
479  masterFieldCallbackSet = false;
480  }
481  for(size_t i=0; i<numFields; i++) {
482  PVFieldPtr pvField = pvFields[i];
483  if(pvField->getField()->getType()==structure) {
484  PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
485  PVRecordStructurePtr pvRecordStructure(
486  new PVRecordStructure(xxx,self,pvRecord));
487  pvRecordFields->push_back(pvRecordStructure);
488  pvRecordStructure->init();
489  } else {
490  PVRecordFieldPtr pvRecordField(
491  new PVRecordField(pvField,self,pvRecord));
492  pvRecordFields->push_back(pvRecordField);
493  pvRecordField->init();
494  // Master field listeners will be called before
495  // calling listeners for the first subfield
496  if (!masterFieldCallbackSet) {
497  masterFieldCallbackSet = true;
498  // Find master field
499  PVRecordStructurePtr p = pvRecordField->parent.lock();
500  while (p) {
501  pvRecordField->master = p;
502  p = p->parent.lock();
503  }
504  }
505  }
506  }
507 }
508 
510 {
511  return pvRecordFields;
512 }
513 
514 PVStructurePtr PVRecordStructure::getPVStructure() {return pvStructure.lock();}
515 
516 }}
bool removeListener(PVListenerPtr const &pvListener, epics::pvCopy::PVCopyPtr const &pvCopy)
Remove a listener.
Definition: pvRecord.cpp:264
bool addPVRecordClient(PVRecordClientPtr const &pvRecordClient)
Add a client that wants to access the record.
Definition: pvRecord.cpp:205
virtual void process()
Optional method for derived class.
Definition: pvRecord.cpp:126
epics::pvData::PVStructurePtr getPVStructure()
Get the data structure/.
Definition: pvRecord.cpp:514
std::tr1::shared_ptr< PVListener > PVListenerPtr
Definition: pvDatabase.h:39
std::tr1::shared_ptr< PVCopy > PVCopyPtr
Definition: pvPlugin.h:25
void lockOtherRecord(PVRecordPtr const &otherRecord)
Lock another record.
Definition: pvRecord.cpp:191
virtual void remove()
remove record from database.
Definition: pvRecord.cpp:104
STL namespace.
void lock()
Lock the record.
Definition: pvRecord.cpp:170
std::tr1::shared_ptr< PVRecordClient > PVRecordClientPtr
Definition: pvDatabase.h:35
PVRecordField(epics::pvData::PVFieldPtr const &pvField, PVRecordStructurePtr const &parent, PVRecordPtr const &pvRecord)
Constructor.
Definition: pvRecord.cpp:329
void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField)
PVCopyTraverseMasterCallback method.
Definition: pvRecord.cpp:252
epics::pvData::PVFieldPtr getPVField()
Get the PVField.
Definition: pvRecord.cpp:367
Base interface for a PVRecord.
Definition: pvDatabase.h:56
bool tryLock()
Try to lock the record.
Definition: pvRecord.cpp:184
PVRecordFieldPtrArrayPtr getPVRecordFields()
Get the sub fields.
Definition: pvRecord.cpp:509
std::tr1::shared_ptr< PVDatabase > PVDatabasePtr
Definition: pvDatabase.h:43
PVRecordPtr getPVRecord()
Return the PVRecord to which this field belongs.
Definition: pvRecord.cpp:373
void endGroupPut()
Ends a group of puts.
Definition: pvRecord.cpp:304
PVRecordStructure(epics::pvData::PVStructurePtr const &pvStructure, PVRecordStructurePtr const &parent, PVRecordPtr const &pvRecord)
Constructor.
Definition: pvRecord.cpp:456
std::string getFullName()
Get the recordName plus the full name of the field, i.e. recordName.field,field,..
Definition: pvRecord.cpp:371
void beginGroupPut()
Begins a group of puts.
Definition: pvRecord.cpp:289
PVRecordStructurePtr getPVRecordStructure() const
Get the top level PVRecordStructure.
Definition: pvDatabase.h:135
Interface for a field of a record.
Definition: pvDatabase.h:314
std::string getFullFieldName()
Get the full name of the field, i.e. field,field,..
Definition: pvRecord.cpp:369
PVRecordStructurePtr getParent()
Get the parent.
Definition: pvRecord.cpp:362
static PVDatabasePtr getMaster()
Get the master database.
Definition: pvDatabase.cpp:38
bool addListener(PVListenerPtr const &pvListener, epics::pvCopy::PVCopyPtr const &pvCopy)
Add a PVListener.
Definition: pvRecord.cpp:236
std::tr1::shared_ptr< PVRecord > PVRecordPtr
Definition: pvDatabase.h:21
virtual void postPut()
This is called by the code that implements the data interface. It is called whenever the put method i...
Definition: pvRecord.cpp:402
std::vector< PVRecordFieldPtr > PVRecordFieldPtrArray
Definition: pvDatabase.h:28
void initPVRecord()
Initializes the base class.
Definition: pvRecord.cpp:116
void unlock()
Unlock the record.
Definition: pvRecord.cpp:177
std::tr1::shared_ptr< PVRecordStructure > PVRecordStructurePtr
Definition: pvDatabase.h:31
std::string getRecordName() const
Get the name of the record.
Definition: pvDatabase.h:129
std::tr1::shared_ptr< PVRecordField > PVRecordFieldPtr
Definition: pvDatabase.h:26
Interface for a field that is a structure.
Definition: pvDatabase.h:394
PVRecordFieldPtr findPVRecordField(epics::pvData::PVFieldPtr const &pvField)
Find the PVRecordField for the PVField.
std::tr1::shared_ptr< PVRecordFieldPtrArray > PVRecordFieldPtrArrayPtr
Definition: pvDatabase.h:29
std::ostream & operator<<(std::ostream &o, const PVRecord &record)
Definition: pvRecord.cpp:319
virtual void init()
Called by implementation code of PVRecord.
Definition: pvRecord.cpp:467
virtual void postParent(PVRecordFieldPtr const &subField)
Definition: pvRecord.cpp:411