This is Unofficial EPICS BASE Doxygen Site
reftrack.cpp
Go to the documentation of this file.
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 
6 #include <iostream>
7 #include <sstream>
8 #include <stdexcept>
9 #include <memory>
10 
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <epicsString.h>
15 #include <epicsGuard.h>
16 #include <epicsMutex.h>
17 #include <epicsEvent.h>
18 #include <epicsThread.h>
19 #include <epicsTime.h>
20 
21 #define epicsExportSharedSymbols
22 #include <pv/pvdVersion.h>
23 #include <pv/sharedPtr.h>
24 #include "pv/reftrack.h"
25 
26 namespace {
27 
30 
31 struct refgbl_t {
33  typedef std::map<std::string, const size_t*> counters_t;
34  counters_t counters;
35 } *refgbl;
36 
37 void refgbl_init(void *)
38 {
39  try {
40  refgbl = new refgbl_t;
41  } catch(std::exception& e) {
42  std::cerr<<"Failed to initialize global ref. counter registry :"<<e.what()<<"\n";
43  }
44 }
45 
47 
48 void refgbl_setup()
49 {
50  epicsThreadOnce(&refgbl_once, &refgbl_init, 0);
51  if(!refgbl)
52  throw std::runtime_error("Failed to initialize global ref. counter registry");
53 }
54 
55 } // namespace
56 
57 namespace epics {
58 
59 void registerRefCounter(const char *name, const size_t* counter)
60 {
61  refgbl_setup();
62  Guard G(refgbl->lock);
63  refgbl->counters[name] = counter;
64 }
65 
66 void unregisterRefCounter(const char *name, const size_t* counter)
67 {
68  refgbl_setup();
69  Guard G(refgbl->lock);
70  refgbl_t::counters_t::iterator it(refgbl->counters.find(name));
71  if(it!=refgbl->counters.end() && it->second==counter)
72  refgbl->counters.erase(it);
73 }
74 
75 size_t readRefCounter(const char *name)
76 {
77  refgbl_setup();
78  Guard G(refgbl->lock);
79  refgbl_t::counters_t::iterator it(refgbl->counters.find(name));
80  if(it==refgbl->counters.end())
81  return 0;
82  return atomic::get(*it->second);
83 }
84 
85 const RefSnapshot::Count&
86 RefSnapshot::operator[](const std::string& name) const
87 {
88  static const Count zero;
89 
90  cnt_map_t::const_iterator it(counts.find(name));
91  return it==counts.end() ? zero : it->second;
92 }
93 
94 void RefSnapshot::update()
95 {
96  refgbl_t::counters_t counters;
97  {
98  refgbl_setup();
99  Guard G(refgbl->lock);
100  counters = refgbl->counters; // copy
101  }
102 
103  counts.clear();
104 
105  for(refgbl_t::counters_t::const_iterator it=counters.begin(),
106  end=counters.end();
107  it!=end; ++it)
108  {
109  size_t cnt = atomic::get(*it->second);
110 
111  counts[it->first] = Count(cnt, 0);
112  }
113 }
114 
115 RefSnapshot RefSnapshot::operator-(const RefSnapshot& rhs) const
116 {
117  RefSnapshot ret;
118 
119  RefSnapshot::cnt_map_t::const_iterator lit = counts.begin(),
120  lend= counts.end(),
121  rit = rhs.counts.begin(),
122  rend= rhs.counts.end();
123 
124  while(lit!=lend || rit!=rend)
125  {
126  if(lit==lend || (rit!=rend && lit->first > rit->first)) {
127  ret.counts[rit->first] = RefSnapshot::Count(0, -long(rit->second.current));
128  ++rit;
129 
130  } else if(rit==rend || lit->first < rit->first) {
131  ret.counts[lit->first] = RefSnapshot::Count(lit->second.current, long(lit->second.current));
132  ++lit;
133 
134  } else { // !end and lit->first == rit->first
135  ret.counts[lit->first] = RefSnapshot::Count(lit->second.current,
136  long(lit->second.current) - long(rit->second.current));
137  ++lit;
138  ++rit;
139  }
140  }
141 
142  return ret;
143 }
144 
145 std::ostream& operator<<(std::ostream& strm, const RefSnapshot& snap)
146 {
147  for(RefSnapshot::const_iterator it = snap.begin(), end = snap.end(); it!=end; ++it)
148  {
149  if(it->second.delta==0) continue;
150  strm<<it->first<<":\t"<<it->second.current<<" (delta "<<it->second.delta<<")\n";
151  }
152  return strm;
153 }
154 
155 struct RefMonitor::Impl : public epicsThreadRunable
156 {
157  RefMonitor& owner;
158  epics::auto_ptr<epicsThread> worker;
161  RefSnapshot prev;
162  bool done;
163  double period;
164  Impl(RefMonitor* owner) :owner(*owner), done(false), period(10.0) {}
165  virtual ~Impl() {}
166 
167  virtual void run()
168  {
169  Guard G(lock);
170  while(!done) {
171  RefSnapshot current, P;
172  P = prev; // copy
173  {
174  UnGuard U(G);
175 
176  current.update();
177 
178  owner.show(current-P);
179  }
180 
181  prev.swap(current);
182 
183  {
184  UnGuard U(G);
185  wakeup.wait(period);
186  }
187  }
188  }
189 };
190 
191 RefMonitor::RefMonitor()
192  :impl(new Impl(this))
193 {}
194 RefMonitor::~RefMonitor()
195 {
196  stop();
197  delete impl;
198 }
199 
200 void RefMonitor::start(double period)
201 {
202  Guard G(impl->lock);
203  if(impl->worker.get()) return;
204 
205  impl->done = false;
206  impl->period = period;
207  impl->worker.reset(new epicsThread(*impl,
208  "RefMonitor",
211  impl->worker->start();
212 }
213 
214 void RefMonitor::stop()
215 {
216  epics::auto_ptr<epicsThread> W;
217  {
218  Guard G(impl->lock);
219  if(!impl->worker.get()) return;
220  epics::swap(W, impl->worker);
221  impl->done = true;
222  }
223 
224  impl->wakeup.signal();
225  W->exitWait();
226 
227  W.reset();
228 }
229 
230 bool RefMonitor::running() const
231 {
232  Guard G(impl->lock);
233  return !!impl->worker.get();
234 }
235 
236 void RefMonitor::current()
237 {
238  RefSnapshot current, P;
239  current.update();
240 
241  {
242  Guard G(impl->lock);
243  P = impl->prev; // copy
244  }
245 
246  show(current-P, true);
247 }
248 
249 void RefMonitor::show(const RefSnapshot &snap, bool complete)
250 {
251  char buf[80];
252  epicsTime::getCurrent().strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S.%f");
253  buf[sizeof(buf)-1] = '\0';
254  std::cerr<<buf<<" : References\n";
255 
256  for(RefSnapshot::const_iterator it = snap.begin(), end = snap.end(); it!=end; ++it)
257  {
258  // print if delta!=0 or (complete && current!=0)
259  if(it->second.delta==0 && (!complete || it->second.current==0)) continue;
260  std::cerr<<it->first<<":\t"<<it->second.current<<" (delta "<<it->second.delta<<")\n";
261  }
262 }
263 
264 } // namespace epics
265 
266 
268 {
269  try {
270  epics::RefSnapshot snap;
271  snap.update();
272  std::ostringstream strm;
273  strm<<snap;
274  const char *str = strm.str().c_str();
275  char *ret = (char*)malloc(strlen(str)+1);
276  if(ret)
277  strcpy(ret, str);
278  return ret;
279  }catch(std::exception& e){
280  return epicsStrDup(e.what());
281  }
282 }
size_t readRefCounter(const char *name)
Definition: reftrack.cpp:75
epicsMutexId lock
Definition: osiClockTime.c:37
epicsGuard< epicsMutex > Guard
Definition: utilities.cpp:15
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
#define str(v)
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
void unregisterRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:66
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
epicsGuardRelease< epicsMutex > UnGuard
Definition: utilities.cpp:16
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
std::ostream & operator<<(std::ostream &strm, const RefSnapshot &snap)
Definition: reftrack.cpp:145
epics::auto_ptr< epicsThread > worker
Definition: reftrack.cpp:158
virtual void run()
Definition: reftrack.cpp:167
void registerRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:59
char * epicsStrDup(const char *s)
Definition: epicsString.c:233
APIs for the epicsEvent binary semaphore.
Impl(RefMonitor *owner)
Definition: reftrack.cpp:164
char * epicsRefSnapshotCurrent()
Definition: reftrack.cpp:267
Definition: caget.c:48
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
C++ and C descriptions for a thread.
#define epicsThreadPriorityMin
Definition: epicsThread.h:72
#define false
Definition: flexdef.h:85