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