This is Unofficial EPICS BASE Doxygen Site
bhe.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /*
11  *
12  * L O S A L A M O S
13  * Los Alamos National Laboratory
14  * Los Alamos, New Mexico 87545
15  *
16  * Copyright, 1986, The Regents of the University of California.
17  *
18  * Author: Jeff Hill
19  */
20 
21 #include <string>
22 #include <stdexcept>
23 #include <limits.h>
24 #include <float.h>
25 
26 #define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
27 
28 #include "errlog.h"
29 
30 #include "iocinf.h"
31 #include "virtualCircuit.h"
32 #include "bhe.h"
33 
34 /*
35  * set average to -1.0 so that when the next beacon
36  * occurs we can distinguish between:
37  * o new server
38  * o existing server's beacon we are seeing
39  * for the first time shortly after program
40  * start up
41  *
42  * if creating this in response to a search reply
43  * and not in response to a beacon then
44  * we set the beacon time stamp to
45  * zero (so we can correctly compute the period
46  * between the 1st and 2nd beacons)
47  */
48 bhe::bhe ( epicsMutex & mutexIn, const epicsTime & initialTimeStamp,
49  unsigned initialBeaconNumber, const inetAddrID & addr ) :
50  inetAddrID ( addr ), timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX ),
51  mutex ( mutexIn ), pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
52 {
53 # ifdef DEBUG
54  {
55  char name[64];
56  addr.name ( name, sizeof ( name ) );
57  ::printf ( "created beacon entry for %s\n", name );
58  }
59 # endif
60 }
61 
63 {
64 }
65 
66 void bhe::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
67 {
68  guard.assertIdenticalMutex ( this->mutex );
69  if ( this->pIIU ) {
70  this->pIIU->beaconAnomalyNotify ( guard );
71  }
72 }
73 
74 #ifdef DEBUG
75 void bhe::logBeacon ( const char * pDiagnostic,
76  const double & currentPeriod,
77  const epicsTime & currentTime )
78 {
79  if ( this->pIIU ) {
80  char name[64];
81  this->name ( name, sizeof ( name ) );
82  char date[64];
83  currentTime.strftime ( date, sizeof ( date ),
84  "%a %b %d %Y %H:%M:%S.%f");
85  ::printf ( "%s cp=%g ap=%g %s %s\n",
86  pDiagnostic, currentPeriod,
87  this->averagePeriod, name, date );
88  }
89 }
90 #else
91 inline void bhe::logBeacon ( const char * /* pDiagnostic */,
92  const double & /* currentPeriod */,
93  const epicsTime & /* currentTime */ )
94 {
95 }
96 #endif
97 
98 #ifdef DEBUG
99 void bhe::logBeaconDiscard ( unsigned beaconAdvance,
100  const epicsTime & currentTime )
101 {
102  if ( this->pIIU ) {
103  char name[64];
104  this->name ( name, sizeof ( name ) );
105  char date[64];
106  currentTime.strftime ( date, sizeof ( date ),
107  "%a %b %d %Y %H:%M:%S.%f");
108  ::printf ( "bb %u %s %s\n",
109  beaconAdvance, name, date );
110  }
111 }
112 #else
113 void bhe::logBeaconDiscard ( unsigned /* beaconAdvance */,
114  const epicsTime & /* currentTime */ )
115 {
116 }
117 #endif
118 
119 /*
120  * update beacon period
121  *
122  * updates beacon period, and looks for beacon anomalies
123  */
125  epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime,
126  const epicsTime & currentTime, ca_uint32_t beaconNumber,
127  unsigned protocolRevision )
128 {
129  guard.assertIdenticalMutex ( this->mutex );
130 
131  //
132  // this block is enetered if the beacon was created as a side effect of
133  // creating a connection and so we dont yet know the first beacon time
134  // and sequence number
135  //
136  if ( this->timeStamp == epicsTime () ) {
137  if ( CA_V410 ( protocolRevision ) ) {
138  this->lastBeaconNumber = beaconNumber;
139  }
140 
141  this->beaconAnomalyNotify ( guard );
142 
143  /*
144  * this is the 1st beacon seen - the beacon time stamp
145  * was not initialized during BHE create because
146  * a TCP/IP connection created the beacon.
147  * (nothing to do but set the beacon time stamp and return)
148  */
149  this->timeStamp = currentTime;
150 
151  logBeacon ( "fb", - DBL_MAX, currentTime );
152 
153  return false;
154  }
155 
156  // 1) detect beacon duplications due to redundant routes
157  // 2) detect lost beacons due to input queue overrun or damage
158  if ( CA_V410 ( protocolRevision ) ) {
159  unsigned beaconSeqAdvance;
160  if ( beaconNumber >= this->lastBeaconNumber ) {
161  beaconSeqAdvance = beaconNumber - this->lastBeaconNumber;
162  }
163  else {
164  beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber;
165  }
166  this->lastBeaconNumber = beaconNumber;
167 
168  // throw out sequence numbers just prior to, or the same as, the last one received
169  // (this situation is probably caused by a temporary duplicate route )
170  if ( beaconSeqAdvance == 0 || beaconSeqAdvance > ca_uint32_max - 256 ) {
171  logBeaconDiscard ( beaconSeqAdvance, currentTime );
172  return false;
173  }
174 
175  // throw out sequence numbers that jump forward by only a few numbers
176  // (this situation is probably caused by a duplicate route
177  // or a beacon due to input queue overun)
178  if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
179  logBeaconDiscard ( beaconSeqAdvance, currentTime );
180  return false;
181  }
182  }
183 
184  // compute the beacon period (if we have seen at least two beacons)
185  bool netChange = false;
186  double currentPeriod = currentTime - this->timeStamp;
187 
188  if ( this->averagePeriod < 0.0 ) {
189  double totalRunningTime;
190 
191  this->beaconAnomalyNotify ( guard );
192 
193  /*
194  * this is the 2nd beacon seen. We cant tell about
195  * the change in period at this point so we just
196  * initialize the average period and return.
197  */
198  this->averagePeriod = currentPeriod;
199 
200  logBeacon ( "fp", currentPeriod, currentTime );
201 
202 
203  /*
204  * ignore beacons seen for the first time shortly after
205  * init, but do not ignore beacons arriving with a short
206  * period because the IOC was rebooted soon after the
207  * client starts up.
208  */
209  totalRunningTime = this->timeStamp - programBeginTime;
210  if ( currentPeriod <= totalRunningTime ) {
211  netChange = true;
212  }
213  }
214  else {
215 
216  /*
217  * Is this an IOC seen because of a restored
218  * network segment?
219  *
220  * It may be possible to get false triggers here
221  * if the client is busy, but this does not cause
222  * problems because the echo response will tell us
223  * that the server is available
224  */
225  if ( currentPeriod >= this->averagePeriod * 1.25 ) {
226 
227  /*
228  * trigger on any missing beacon
229  * if connected to this server
230  */
231  this->beaconAnomalyNotify ( guard );
232 
233  if ( currentPeriod >= this->averagePeriod * 3.25 ) {
234  /*
235  * trigger on any 3 contiguous missing beacons
236  * if not connected to this server
237  */
238  netChange = true;
239  }
240  logBeacon ( "bah", currentPeriod, currentTime );
241  }
242 
243  /*
244  * Is this an IOC seen because of an IOC reboot
245  * (beacon come at a higher rate just after the
246  * IOC reboots). Lower tolarance here because we
247  * dont have to worry about lost beacons.
248  *
249  * It may be possible to get false triggers here
250  * if the client is busy, but this does not cause
251  * problems because the echo response will tell us
252  * that the server is available
253  */
254  else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
255  this->beaconAnomalyNotify ( guard );
256  netChange = true;
257  logBeacon ( "bal", currentPeriod, currentTime );
258  }
259  else if ( this->pIIU ) {
260  // update state of health for active virtual circuits
261  // if the beacon looks ok
262  this->pIIU->beaconArrivalNotify ( guard );
263  logBeacon ( "vb", currentPeriod, currentTime );
264  }
265 
266  // update a running average period
267  this->averagePeriod = currentPeriod * 0.125 +
268  this->averagePeriod * 0.875;
269  }
270 
271  this->timeStamp = currentTime;
272 
273  return netChange;
274 }
275 
276 void bhe::show ( unsigned level ) const
277 {
278  epicsGuard < epicsMutex > guard ( this->mutex );
279  this->show ( guard, level );
280 }
281 
282 void bhe::show ( epicsGuard < epicsMutex > &, unsigned level ) const
283 {
284  char host [64];
285  this->name ( host, sizeof ( host ) );
286  if ( this->averagePeriod == -DBL_MAX ) {
287  ::printf ( "CA beacon hash entry for %s <no period estimate>\n",
288  host );
289  }
290  else {
291  ::printf ( "CA beacon hash entry for %s with period estimate %f\n",
292  host, this->averagePeriod );
293  }
294  if ( level > 0u ) {
295  char date[64];
296  this->timeStamp.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
297  ::printf ( "\tbeacon number %u, on %s\n",
298  this->lastBeaconNumber, date );
299  }
300 }
301 
302 double bhe::period ( epicsGuard < epicsMutex > & guard ) const
303 {
304  guard.assertIdenticalMutex ( this->mutex );
305  return this->averagePeriod;
306 }
307 
308 epicsTime bhe::updateTime ( epicsGuard < epicsMutex > & guard ) const
309 {
310  guard.assertIdenticalMutex ( this->mutex );
311  return this->timeStamp;
312 }
313 
315  epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
316 {
317  guard.assertIdenticalMutex ( this->mutex );
318  this->pIIU = & iiu;
319 }
320 
322  epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
323 {
324  guard.assertIdenticalMutex ( this->mutex );
325  if ( this->pIIU == & iiu ) {
326  this->pIIU = 0;
327  this->timeStamp = epicsTime();
328  this->averagePeriod = - DBL_MAX;
329  logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () );
330  }
331 }
332 
333 void bhe::operator delete ( void * )
334 {
335  // Visual C++ .net appears to require operator delete if
336  // placement operator delete is defined? I smell a ms rat
337  // because if I declare placement new and delete, but
338  // comment out the placement delete definition there are
339  // no undefined symbols.
340  errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
341  __FILE__, __LINE__ );
342 }
343 
344 void * bheFreeStore::allocate ( size_t size )
345 {
346  return freeList.allocate ( size );
347 }
348 
349 void bheFreeStore::release ( void * pCadaver )
350 {
351  freeList.release ( pCadaver );
352 }
353 
355 
356 
void * allocate(size_t)
Definition: bhe.cpp:344
#define CA_V410(MINOR)
Definition: caProto.h:41
LIBCA_API bhe(epicsMutex &, const epicsTime &initialTimeStamp, unsigned initialBeaconNumber, const inetAddrID &addr)
Definition: bhe.cpp:48
#define printf
Definition: epicsStdio.h:41
unsigned int ca_uint32_t
Definition: caProto.h:76
LIBCA_API bool updatePeriod(epicsGuard< epicsMutex > &, const epicsTime &programBeginTime, const epicsTime &currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision)
Definition: bhe.cpp:124
void assertIdenticalMutex(const T &) const
Definition: epicsGuard.h:80
#define ca_uint32_max
Definition: caProto.h:80
LIBCA_API void registerIIU(epicsGuard< epicsMutex > &, tcpiiu &)
Definition: bhe.cpp:314
LIBCA_API ~bhe()
Definition: bhe.cpp:62
LIBCA_API epicsTime updateTime(epicsGuard< epicsMutex > &) const
Definition: bhe.cpp:308
void release(void *)
Definition: bhe.cpp:349
epicsMutex mutex
Definition: pvAccess.cpp:71
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
LIBCA_API void show(unsigned level) const
Definition: bhe.cpp:276
void beaconArrivalNotify(epicsGuard< epicsMutex > &)
void date(const char *format)
LIBCA_API void unregisterIIU(epicsGuard< epicsMutex > &, tcpiiu &)
Definition: bhe.cpp:321
virtual ~bheMemoryManager()
Definition: bhe.cpp:354
void beaconAnomalyNotify(epicsGuard< epicsMutex > &)
LIBCA_API double period(epicsGuard< epicsMutex > &) const
Definition: bhe.cpp:302
void name(char *pBuf, unsigned bufSize) const
Definition: inetAddrID.h:64