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