This is Unofficial EPICS BASE Doxygen Site
timer.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 Versions 3.13.7
7 * and higher are distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /*
12  * Author Jeffrey O. Hill
13  * johill@lanl.gov
14  * 505 665 1831
15  */
16 
17 #include <typeinfo>
18 #include <string>
19 #include <stdexcept>
20 #include <stdio.h>
21 
22 #include "epicsGuard.h"
23 #include "timerPrivate.h"
24 #include "errlog.h"
25 
26 #ifdef _MSC_VER
27 # pragma warning ( push )
28 # pragma warning ( disable:4660 )
29 #endif
30 
31 template class tsFreeList < timer, 0x20 >;
32 
33 #ifdef _MSC_VER
34 # pragma warning ( pop )
35 #endif
36 
37 timer::timer ( timerQueue & queueIn ) :
38  queue ( queueIn ), curState ( stateLimbo ), pNotify ( 0 )
39 {
40 }
41 
43 {
44  this->cancel ();
45 }
46 
48 {
49  timerQueue & queueTmp = this->queue;
50  this->~timer ();
51  queueTmp.timerFreeList.release ( this );
52 }
53 
54 void timer::start ( epicsTimerNotify & notify, double delaySeconds )
55 {
56  this->start ( notify, epicsTime::getCurrent () + delaySeconds );
57 }
58 
59 void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
60 {
61  epicsGuard < epicsMutex > locker ( this->queue.mutex );
62  this->privateStart ( notify, expire );
63 }
64 
65 void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
66 {
67  this->pNotify = & notify;
68  this->exp = expire - ( this->queue.notify.quantum () / 2.0 );
69 
70  bool reschedualNeeded = false;
71  if ( this->curState == stateActive ) {
72  // above expire time and notify will override any restart parameters
73  // that may be returned from the timer expire callback
74  return;
75  }
76  else if ( this->curState == statePending ) {
77  this->queue.timerList.remove ( *this );
78  if ( this->queue.timerList.first() == this &&
79  this->queue.timerList.count() > 0 ) {
80  reschedualNeeded = true;
81  }
82  }
83 
84 # ifdef DEBUG
85  unsigned preemptCount=0u;
86 # endif
87 
88  //
89  // insert into the pending queue
90  //
91  // Finds proper time sorted location using a linear search.
92  //
93  // **** this should use a binary tree ????
94  //
95  tsDLIter < timer > pTmr = this->queue.timerList.lastIter ();
96  while ( true ) {
97  if ( ! pTmr.valid () ) {
98  //
99  // add to the beginning of the list
100  //
101  this->queue.timerList.push ( *this );
102  reschedualNeeded = true;
103  break;
104  }
105  if ( pTmr->exp <= this->exp ) {
106  //
107  // add after the item found that expires earlier
108  //
109  this->queue.timerList.insertAfter ( *this, *pTmr );
110  break;
111  }
112 # ifdef DEBUG
113  preemptCount++;
114 # endif
115  --pTmr;
116  }
117 
118  this->curState = timer::statePending;
119 
120  if ( reschedualNeeded ) {
121  this->queue.notify.reschedule ();
122  }
123 
124 # if defined(DEBUG) && 0
125  this->show ( 10u );
126  this->queue.show ( 10u );
127 # endif
128 
129  debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n",
130  typeid ( this->notify ).name (),
131  expire - epicsTime::getCurrent (),
132  this, preemptCount ) );
133 }
134 
136 {
137  bool reschedual = false;
138  bool wakeupCancelBlockingThreads = false;
139  {
140  epicsGuard < epicsMutex > locker ( this->queue.mutex );
141  this->pNotify = 0;
142  if ( this->curState == statePending ) {
143  this->queue.timerList.remove ( *this );
144  this->curState = stateLimbo;
145  if ( this->queue.timerList.first() == this &&
146  this->queue.timerList.count() > 0 ) {
147  reschedual = true;
148  }
149  }
150  else if ( this->curState == stateActive ) {
151  this->queue.cancelPending = true;
152  this->curState = timer::stateLimbo;
153  if ( this->queue.processThread != epicsThreadGetIdSelf() ) {
154  // make certain timer expire() does not run after cancel () returns,
155  // but dont require that lock is applied while calling expire()
156  while ( this->queue.cancelPending &&
157  this->queue.pExpireTmr == this ) {
158  epicsGuardRelease < epicsMutex > autoRelease ( locker );
159  this->queue.cancelBlockingEvent.wait ();
160  }
161  // in case other threads are waiting
162  wakeupCancelBlockingThreads = true;
163  }
164  }
165  }
166  if ( reschedual ) {
167  this->queue.notify.reschedule ();
168  }
169  if ( wakeupCancelBlockingThreads ) {
170  this->queue.cancelBlockingEvent.signal ();
171  }
172 }
173 
174 epicsTimer::expireInfo timer::getExpireInfo () const
175 {
176  // taking a lock here guarantees that users will not
177  // see brief intervals when a timer isnt active because
178  // it is is canceled when start is called
179  epicsGuard < epicsMutex > locker ( this->queue.mutex );
180  if ( this->curState == statePending || this->curState == stateActive ) {
181  return expireInfo ( true, this->exp );
182  }
183  return expireInfo ( false, epicsTime() );
184 }
185 
186 void timer::show ( unsigned int level ) const
187 {
188  epicsGuard < epicsMutex > locker ( this->queue.mutex );
189  double delay;
190  if ( this->curState == statePending || this->curState == stateActive ) {
191  try {
192  delay = this->exp - epicsTime::getCurrent();
193  }
194  catch ( ... ) {
195  delay = - DBL_MAX;
196  }
197  }
198  else {
199  delay = -DBL_MAX;
200  }
201  const char *pStateName;
202  if ( this->curState == statePending ) {
203  pStateName = "pending";
204  }
205  else if ( this->curState == stateActive ) {
206  pStateName = "active";
207  }
208  else if ( this->curState == stateLimbo ) {
209  pStateName = "limbo";
210  }
211  else {
212  pStateName = "corrupt";
213  }
214  printf ( "timer, state = %s, delay = %f\n",
215  pStateName, delay );
216  if ( level >= 1u && this->pNotify ) {
217  this->pNotify->show ( level - 1u );
218  }
219 }
220 
221 void timer::operator delete ( void * )
222 {
223  // Visual C++ .net appears to require operator delete if
224  // placement operator delete is defined? I smell a ms rat
225  // because if I declare placement new and delete, but
226  // comment out the placement delete definition there are
227  // no undefined symbols.
228  errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
229  __FILE__, __LINE__ );
230 }
231 
232 void epicsTimerForC::operator delete ( void * )
233 {
234  // Visual C++ .net appears to require operator delete if
235  // placement operator delete is defined? I smell a ms rat
236  // because if I declare placement new and delete, but
237  // comment out the placement delete definition there are
238  // no undefined symbols.
239  errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
240  __FILE__, __LINE__ );
241 }
242 
void show(unsigned int level) const
Definition: timer.cpp:186
void insertAfter(T &item, T &itemBefore)
Definition: tsDLList.h:339
void show(unsigned int level) const
Definition: timerQueue.cpp:214
void destroy()
Definition: timer.cpp:47
#define printf
Definition: epicsStdio.h:41
unsigned count() const
Definition: tsDLList.h:181
epicsPlacementDeleteOperator((void *, tsFreeList< timer, 0x20 > &)) protecte ~timer)()
Definition: timerPrivate.h:46
bool valid() const
Definition: tsDLList.h:607
expireInfo getExpireInfo() const
Definition: timer.cpp:174
timerQueue queue
Definition: timerPrivate.h:188
timerQueue & queue
Definition: timerPrivate.h:47
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
void cancel()
Definition: timer.cpp:135
void push(T &item)
Definition: tsDLList.h:416
void release(void *p)
Definition: tsFreeList.h:176
void remove(T &item)
Definition: tsDLList.h:219
#define debugPrintf(argsInParen)
Definition: iocinf.h:30
tsDLIterConst< T > lastIter() const
Definition: tsDLList.h:471
void start(class epicsTimerNotify &, const epicsTime &)
Definition: timer.cpp:59
T * first(void) const
Definition: tsDLList.h:190
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810