event.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 "base/Random.h"
13 #include "event.h"
14 #include "mgr/Registration.h"
15 #include "Store.h"
16 #include "tools.h"
17 
18 #include <cmath>
19 
20 /* The list of event processes */
21 
22 static OBJH eventDump;
23 static const char *last_event_ran = nullptr;
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  ~EventDialer() override;
35 
36  void print(std::ostream &os) const override;
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(nullptr)
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  static std::mt19937 rng(RandomSeed32());
118  auto third = (delta_ish/3.0);
119  std::uniform_real_distribution<> thirdIsh(delta_ish - third, delta_ish + third);
120  delta_ish = thirdIsh(rng);
121  }
122 
123  eventAdd(name, func, arg, delta_ish, weight);
124 }
125 
126 void
127 eventDelete(EVH * func, void *arg)
128 {
129  EventScheduler::GetInstance()->cancel(func, arg);
130 }
131 
132 void
134 {
135  Mgr::RegisterAction("events", "Event Queue", eventDump, 0, 1);
136 }
137 
138 static void
140 {
142 }
143 
144 int
145 eventFind(EVH * func, void *arg)
146 {
147  return EventScheduler::GetInstance()->find(func, arg);
148 }
149 
151 
153 {}
154 
156 {
157  clean();
158 }
159 
160 void
161 EventScheduler::cancel(EVH * func, void *arg)
162 {
163  ev_entry **E;
164  ev_entry *event;
165 
166  for (E = &tasks; (event = *E) != nullptr; E = &(*E)->next) {
167  if (event->func != func)
168  continue;
169 
170  if (arg && event->arg != arg)
171  continue;
172 
173  *E = event->next;
174 
175  delete event;
176 
177  if (arg)
178  return;
179  /*
180  * DPW 2007-04-12
181  * Since this method may now delete multiple events (when
182  * arg is NULL) it no longer returns after a deletion and
183  * we have a potential NULL pointer problem. If we just
184  * deleted the last event in the list then *E is now equal
185  * to NULL. We need to break here or else we'll get a NULL
186  * pointer dereference in the last clause of the for loop.
187  */
188  if (nullptr == *E)
189  break;
190  }
191 
192  if (arg)
193  debug_trap("eventDelete: event not found");
194 }
195 
196 // The event API does not guarantee exact timing, but guarantees that no event
197 // is fired before it is due. We may delay firing, but never fire too early.
198 int
200 {
201  if (!tasks)
202  return EVENT_IDLE;
203 
204  if (tasks->when <= current_dtime) // we are on time or late
205  return 0; // fire the event ASAP
206 
207  const double diff = tasks->when - current_dtime; // seconds
208  // Round UP: If we come back a nanosecond earlier, we will wait again!
209  const int timeLeft = static_cast<int>(ceil(1000*diff)); // milliseconds
210  // Avoid hot idle: A series of rapid select() calls with zero timeout.
211  const int minDelay = 1; // millisecond
212  return max(minDelay, timeLeft);
213 }
214 
215 int
217 {
218  int result = timeRemaining();
219  if (result != 0)
220  return result;
221 
222  do {
223  ev_entry *event = tasks;
224  assert(event);
225 
226  /* XXX assumes event->name is static memory! */
227  AsyncCall::Pointer call = asyncCall(41,5, event->name,
228  EventDialer(event->func, event->arg, event->cbdata));
229  ScheduleCallHere(call);
230 
231  last_event_ran = event->name; // XXX: move this to AsyncCallQueue
232  const bool heavy = event->weight &&
233  (!event->cbdata || cbdataReferenceValid(event->arg));
234 
235  tasks = event->next;
236  delete event;
237 
238  result = timeRemaining();
239 
240  // XXX: We may be called again during the same event loop iteration.
241  // Is there a point in breaking now?
242  if (heavy)
243  break; // do not dequeue events following a heavy event
244  } while (result == 0);
245 
246  return result;
247 }
248 
249 void
251 {
252  while (ev_entry * event = tasks) {
253  tasks = event->next;
254  delete event;
255  }
256 
257  tasks = nullptr;
258 }
259 
260 void
262 {
263  if (last_event_ran)
264  out->appendf("Last event to run: %s\n\n", last_event_ran);
265 
266  out->appendf("%-25s\t%-15s\t%s\t%s\n",
267  "Operation",
268  "Next Execution",
269  "Weight",
270  "Callback Valid?");
271 
272  for (auto *e = tasks; e; e = e->next) {
273  out->appendf("%-25s\t%0.3f sec\t%5d\t %s\n",
274  e->name, (e->when ? e->when - current_dtime : 0), e->weight,
275  (e->arg && e->cbdata) ? cbdataReferenceValid(e->arg) ? "yes" : "no" : "N/A");
276  }
277 }
278 
279 bool
280 EventScheduler::find(EVH * func, void * arg)
281 {
282 
283  ev_entry *event;
284 
285  for (event = tasks; event != nullptr; event = event->next) {
286  if (event->func == func && event->arg == arg)
287  return true;
288  }
289 
290  return false;
291 }
292 
295 {
296  return &_instance;
297 }
298 
299 void
300 EventScheduler::schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
301 {
302  // Use zero timestamp for when=0 events: Many of them are async calls that
303  // must fire in the submission order. We cannot use current_dtime for them
304  // because it may decrease if system clock is adjusted backwards.
305  const double timestamp = when > 0.0 ? current_dtime + when : 0;
306  ev_entry *event = new ev_entry(name, func, arg, timestamp, weight, cbdata);
307 
308  ev_entry **E;
309  debugs(41, 7, "schedule: Adding '" << name << "', in " << when << " seconds");
310  /* Insert after the last event with the same or earlier time */
311 
312  for (E = &tasks; *E; E = &(*E)->next) {
313  if ((*E)->when > event->when)
314  break;
315  }
316 
317  event->next = *E;
318  *E = event;
319 }
320 
bool cancel(const char *reason)
Definition: AsyncCall.cc:56
EVH * func
Definition: event.h:34
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:145
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
ev_entry * next
Definition: event.h:41
void eventDelete(EVH *func, void *arg)
Definition: event.cc:127
~EventScheduler() override
Definition: event.cc:155
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
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
void dump(Packable *)
Definition: event.cc:261
const A & max(A const &lhs, A const &rhs)
EventScheduler()
Definition: event.cc:152
Definition: cbdata.cc:37
bool find(EVH *func, void *arg)
Definition: event.cc:280
static char E[KS]
Definition: encrypt.c:92
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
#define cbdataReference(var)
Definition: cbdata.h:348
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
static EventScheduler * GetInstance()
Definition: event.cc:294
void dial(AsyncCall &)
Definition: event.cc:39
std::mt19937::result_type RandomSeed32()
Definition: Random.cc:13
EventDialer(EVH *aHandler, void *anArg, bool lockedArg)
Definition: event.cc:47
void OBJH(StoreEntry *)
Definition: forward.h:44
void * arg
Definition: event.h:35
virtual bool canDial(AsyncCall &call)
Definition: event.cc:68
int timeRemaining() const
Definition: event.cc:199
~ev_entry()
Definition: event.cc:100
void debug_trap(const char *message)
Definition: tools.cc:458
#define assert(EX)
Definition: assert.h:17
#define cbdataReferenceDone(var)
Definition: cbdata.h:357
Definition: event.h:26
void schedule(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata=true)
Definition: event.cc:300
void EVH(void *)
Definition: event.h:18
double when
Definition: event.h:36
ev_entry * tasks
Definition: event.h:68
void cancel(EVH *func, void *arg)
Definition: event.cc:161
~EventDialer() override
Definition: event.cc:61
static EventScheduler _instance
Definition: event.h:67
void * theArg
Definition: event.cc:43
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
void print(std::ostream &os) const override
Definition: event.cc:81
bool isLockedArg
Definition: event.cc:44
void eventAddIsh(const char *name, EVH *func, void *arg, double delta_ish, int weight)
Definition: event.cc:114
void eventInit(void)
Definition: event.cc:133
void clean()
Definition: event.cc:250
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
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
int checkEvents(int timeout) override
Definition: event.cc:216
EVH * theHandler
Definition: event.cc:42

 

Introduction

Documentation

Support

Miscellaneous