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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors