event.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 41 Event Processing */
10 
11 #include "squid.h"
12 #include "event.h"
13 #include "mgr/Registration.h"
14 #include "profiler/Profiler.h"
15 #include "SquidTime.h"
16 #include "Store.h"
17 #include "tools.h"
18 
19 #include <cmath>
20 #include <random>
21 
22 /* The list of event processes */
23 
24 static OBJH eventDump;
25 static const char *last_event_ran = NULL;
26 
27 // This AsyncCall dialer can be configured to check that the event cbdata is
28 // valid before calling the event handler
29 class EventDialer: public CallDialer
30 {
31 public:
32  typedef CallDialer Parent;
33 
34  EventDialer(EVH *aHandler, void *anArg, bool lockedArg);
35  EventDialer(const EventDialer &d);
36  virtual ~EventDialer();
37 
38  virtual void print(std::ostream &os) const;
39  virtual bool canDial(AsyncCall &call);
40 
42 
43 private:
45  void *theArg;
47 };
48 
49 EventDialer::EventDialer(EVH *aHandler, void *anArg, bool lockedArg):
50  theHandler(aHandler), theArg(anArg), isLockedArg(lockedArg)
51 {
52  if (isLockedArg)
53  (void)cbdataReference(theArg);
54 }
55 
57  theHandler(d.theHandler), theArg(d.theArg), isLockedArg(d.isLockedArg)
58 {
59  if (isLockedArg)
60  (void)cbdataReference(theArg);
61 }
62 
64 {
65  if (isLockedArg)
67 }
68 
69 bool
71 {
72  // TODO: add Parent::canDial() that always returns true
73  //if (!Parent::canDial())
74  // return false;
75 
77  return call.cancel("stale handler data");
78 
79  return true;
80 }
81 
82 void
83 EventDialer::print(std::ostream &os) const
84 {
85  os << '(';
86  if (theArg)
87  os << theArg << (isLockedArg ? "*?" : "");
88  os << ')';
89 }
90 
91 ev_entry::ev_entry(char const * aName, EVH * aFunction, void * aArgument, double evWhen, int aWeight, bool haveArg) :
92  name(aName),
93  func(aFunction),
94  arg(haveArg ? cbdataReference(aArgument) : aArgument),
95  when(evWhen),
96  weight(aWeight),
97  cbdata(haveArg),
98  next(NULL)
99 {
100 }
101 
103 {
104  if (cbdata)
106 }
107 
108 void
109 eventAdd(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
110 {
111  EventScheduler::GetInstance()->schedule(name, func, arg, when, weight, cbdata);
112 }
113 
114 /* same as eventAdd but adds a random offset within +-1/3 of delta_ish */
115 void
116 eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int weight)
117 {
118  if (delta_ish >= 3.0) {
119  // Default seed is fine. We just need values random enough
120  // relative to each other to prevent waves of synchronised activity.
121  static std::mt19937 rng;
122  auto third = (delta_ish/3.0);
123  xuniform_real_distribution<> thirdIsh(delta_ish - third, delta_ish + third);
124  delta_ish = thirdIsh(rng);
125  }
126 
127  eventAdd(name, func, arg, delta_ish, weight);
128 }
129 
130 void
132 {
133  EventScheduler::GetInstance()->cancel(func, arg);
134 }
135 
136 void
138 {
139  Mgr::RegisterAction("events", "Event Queue", eventDump, 0, 1);
140 }
141 
142 static void
144 {
146 }
147 
148 void
150 {
152 }
153 
154 int
156 {
157  return EventScheduler::GetInstance()->find(func, arg);
158 }
159 
161 
163 {}
164 
166 {
167  clean();
168 }
169 
170 void
172 {
173  ev_entry **E;
174  ev_entry *event;
175 
176  for (E = &tasks; (event = *E) != NULL; E = &(*E)->next) {
177  if (event->func != func)
178  continue;
179 
180  if (arg && event->arg != arg)
181  continue;
182 
183  *E = event->next;
184 
185  delete event;
186 
187  if (arg)
188  return;
189  /*
190  * DPW 2007-04-12
191  * Since this method may now delete multiple events (when
192  * arg is NULL) it no longer returns after a deletion and
193  * we have a potential NULL pointer problem. If we just
194  * deleted the last event in the list then *E is now equal
195  * to NULL. We need to break here or else we'll get a NULL
196  * pointer dereference in the last clause of the for loop.
197  */
198  if (NULL == *E)
199  break;
200  }
201 
202  if (arg)
203  debug_trap("eventDelete: event not found");
204 }
205 
206 // The event API does not guarantee exact timing, but guarantees that no event
207 // is fired before it is due. We may delay firing, but never fire too early.
208 int
210 {
211  if (!tasks)
212  return EVENT_IDLE;
213 
214  if (tasks->when <= current_dtime) // we are on time or late
215  return 0; // fire the event ASAP
216 
217  const double diff = tasks->when - current_dtime; // microseconds
218  // Round UP: If we come back a nanosecond earlier, we will wait again!
219  const int timeLeft = static_cast<int>(ceil(1000*diff)); // milliseconds
220  // Avoid hot idle: A series of rapid select() calls with zero timeout.
221  const int minDelay = 1; // millisecond
222  return max(minDelay, timeLeft);
223 }
224 
225 int
227 {
228  int result = timeRemaining();
229  if (result != 0)
230  return result;
231 
232  PROF_start(eventRun);
233 
234  do {
235  ev_entry *event = tasks;
236  assert(event);
237 
238  /* XXX assumes event->name is static memory! */
239  AsyncCall::Pointer call = asyncCall(41,5, event->name,
240  EventDialer(event->func, event->arg, event->cbdata));
241  ScheduleCallHere(call);
242 
243  last_event_ran = event->name; // XXX: move this to AsyncCallQueue
244  const bool heavy = event->weight &&
245  (!event->cbdata || cbdataReferenceValid(event->arg));
246 
247  tasks = event->next;
248  delete event;
249 
250  result = timeRemaining();
251 
252  // XXX: We may be called again during the same event loop iteration.
253  // Is there a point in breaking now?
254  if (heavy)
255  break; // do not dequeue events following a heavy event
256  } while (result == 0);
257 
258  PROF_stop(eventRun);
259  return result;
260 }
261 
262 void
264 {
265  while (ev_entry * event = tasks) {
266  tasks = event->next;
267  delete event;
268  }
269 
270  tasks = NULL;
271 }
272 
273 void
275 {
276 
277  ev_entry *e = tasks;
278 
279  if (last_event_ran)
280  storeAppendPrintf(sentry, "Last event to run: %s\n\n", last_event_ran);
281 
282  storeAppendPrintf(sentry, "%-25s\t%-15s\t%s\t%s\n",
283  "Operation",
284  "Next Execution",
285  "Weight",
286  "Callback Valid?");
287 
288  while (e != NULL) {
289  storeAppendPrintf(sentry, "%-25s\t%0.3f sec\t%5d\t %s\n",
290  e->name, e->when ? e->when - current_dtime : 0, e->weight,
291  (e->arg && e->cbdata) ? cbdataReferenceValid(e->arg) ? "yes" : "no" : "N/A");
292  e = e->next;
293  }
294 }
295 
296 bool
298 {
299 
300  ev_entry *event;
301 
302  for (event = tasks; event != NULL; event = event->next) {
303  if (event->func == func && event->arg == arg)
304  return true;
305  }
306 
307  return false;
308 }
309 
312 {
313  return &_instance;
314 }
315 
316 void
317 EventScheduler::schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
318 {
319  // Use zero timestamp for when=0 events: Many of them are async calls that
320  // must fire in the submission order. We cannot use current_dtime for them
321  // because it may decrease if system clock is adjusted backwards.
322  const double timestamp = when > 0.0 ? current_dtime + when : 0;
323  ev_entry *event = new ev_entry(name, func, arg, timestamp, weight, cbdata);
324 
325  ev_entry **E;
326  debugs(41, 7, HERE << "schedule: Adding '" << name << "', in " << when << " seconds");
327  /* Insert after the last event with the same or earlier time */
328 
329  for (E = &tasks; *E; E = &(*E)->next) {
330  if ((*E)->when > event->when)
331  break;
332  }
333 
334  event->next = *E;
335  *E = event;
336 }
337 
static const char * last_event_ran
Definition: event.cc:25
EVH * func
Definition: event.h:36
#define assert(EX)
Definition: assert.h:17
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
Definition: cbdata.cc:60
ev_entry * next
Definition: event.h:43
Definition: event.h:28
void * arg
Definition: event.h:37
void EVH void double delta_ish
Definition: stub_event.cc:16
void * theArg
Definition: event.cc:45
ev_entry * tasks
Definition: event.h:70
void eventAddIsh(const char *name, EVH *func, void *arg, double delta_ish, int weight)
Definition: event.cc:116
ev_entry(char const *name, EVH *func, void *arg, double when, int weight, bool cbdata=true)
Definition: event.cc:91
bool isLockedArg
Definition: event.cc:46
bool cancel(const char *reason)
Definition: AsyncCall.cc:52
void OBJH(StoreEntry *)
Definition: forward.h:44
A const & max(A const &lhs, A const &rhs)
virtual void print(std::ostream &os) const
Definition: event.cc:83
void clean()
Definition: event.cc:263
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
~EventScheduler()
Definition: event.cc:165
virtual ~EventDialer()
Definition: event.cc:63
void EVH void * arg
Definition: stub_event.cc:16
void EVH(void *)
Definition: event.h:19
double when
Definition: event.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define cbdataReference(var)
Definition: cbdata.h:341
int eventFind(EVH *func, void *arg)
Definition: event.cc:155
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
int checkEvents(int timeout)
Definition: event.cc:226
void dump(StoreEntry *)
Definition: event.cc:274
CallDialer Parent
Definition: event.cc:32
EVH * theHandler
Definition: event.cc:44
static OBJH eventDump
Definition: event.cc:24
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
void eventDelete(EVH *func, void *arg)
Definition: event.cc:131
const char * name
Definition: event.h:35
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:109
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
int timeRemaining() const
Definition: event.cc:209
EventScheduler()
Definition: event.cc:162
#define PROF_start(probename)
Definition: Profiler.h:62
static EventScheduler * GetInstance()
Definition: event.cc:311
double current_dtime
Definition: stub_time.cc:16
bool find(EVH *func, void *arg)
Definition: event.cc:297
void dial(AsyncCall &)
Definition: event.cc:41
int weight
Definition: event.h:40
static char E[KS]
Definition: encrypt.c:92
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:412
~ev_entry()
Definition: event.cc:102
#define PROF_stop(probename)
Definition: Profiler.h:63
void EVH * func
Definition: stub_event.cc:16
bool cbdata
Definition: event.h:41
static EventScheduler _instance
Definition: event.h:69
void debug_trap(const char *message)
Definition: tools.cc:403
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:904
void eventFreeMemory(void)
Definition: event.cc:149
virtual bool canDial(AsyncCall &call)
Definition: event.cc:70
EventDialer(EVH *aHandler, void *anArg, bool lockedArg)
Definition: event.cc:49
#define NULL
Definition: types.h:166
void schedule(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata=true)
Definition: event.cc:317
void eventInit(void)
Definition: event.cc:137
void cancel(EVH *func, void *arg)
Definition: event.cc:171

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors