]> git.ipfire.org Git - thirdparty/squid.git/blame - src/event.cc
Prep for 3.3.12 and 3.4.4
[thirdparty/squid.git] / src / event.cc
CommitLineData
48f44632 1/*
f43e2ec2 2 * DEBUG: section 41 Event Processing
48f44632 3 * AUTHOR: Henrik Nordstrom
4 *
2b6662ba 5 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 6 * ----------------------------------------------------------
48f44632 7 *
2b6662ba 8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
48f44632 16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
48f44632 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
48f44632 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
cbdec147 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 30 *
48f44632 31 */
32
f7f3304a 33#include "squid.h"
27bc2077 34#include "compat/drand48.h"
27bc2077 35#include "event.h"
8822ebee 36#include "mgr/Registration.h"
582c2af2 37#include "profiler/Profiler.h"
602d9612
A
38#include "SquidTime.h"
39#include "Store.h"
5bed43d6 40#include "tools.h"
48f44632 41
074d6a40 42#include <cmath>
aa14d759 43
48f44632 44/* The list of event processes */
62e76326 45
4ba55996 46static OBJH eventDump;
236b1f2a 47static const char *last_event_ran = NULL;
48f44632 48
26ac0430 49// This AsyncCall dialer can be configured to check that the event cbdata is
5dee3116 50// valid before calling the event handler
51class EventDialer: public CallDialer
52{
53public:
54 typedef CallDialer Parent;
55
56 EventDialer(EVH *aHandler, void *anArg, bool lockedArg);
57 EventDialer(const EventDialer &d);
58 virtual ~EventDialer();
59
60 virtual void print(std::ostream &os) const;
61 virtual bool canDial(AsyncCall &call);
62
63 void dial(AsyncCall &) { theHandler(theArg); }
64
65private:
66 EVH *theHandler;
67 void *theArg;
68 bool isLockedArg;
69};
70
71EventDialer::EventDialer(EVH *aHandler, void *anArg, bool lockedArg):
26ac0430 72 theHandler(aHandler), theArg(anArg), isLockedArg(lockedArg)
5dee3116 73{
74 if (isLockedArg)
451bde6d 75 (void)cbdataReference(theArg);
5dee3116 76}
77
78EventDialer::EventDialer(const EventDialer &d):
26ac0430 79 theHandler(d.theHandler), theArg(d.theArg), isLockedArg(d.isLockedArg)
5dee3116 80{
81 if (isLockedArg)
451bde6d 82 (void)cbdataReference(theArg);
5dee3116 83}
84
85EventDialer::~EventDialer()
86{
87 if (isLockedArg)
88 cbdataReferenceDone(theArg);
89}
90
91bool
26ac0430
AJ
92EventDialer::canDial(AsyncCall &call)
93{
5dee3116 94 // TODO: add Parent::canDial() that always returns true
95 //if (!Parent::canDial())
96 // return false;
97
98 if (isLockedArg && !cbdataReferenceValid(theArg))
99 return call.cancel("stale handler data");
100
101 return true;
102}
103
104void
105EventDialer::print(std::ostream &os) const
106{
107 os << '(';
108 if (theArg)
109 os << theArg << (isLockedArg ? "*?" : "");
110 os << ')';
111}
112
d5f8d05f
FC
113ev_entry::ev_entry(char const * aName, EVH * aFunction, void * aArgument, double evWhen,
114 int aWeight, bool haveArgument) : name(aName), func(aFunction),
115 arg(haveArgument ? cbdataReference(aArgument) : aArgument), when(evWhen), weight(aWeight),
e053c141 116 cbdata(haveArgument)
5dee3116 117{
118}
119
120ev_entry::~ev_entry()
121{
122 if (cbdata)
123 cbdataReferenceDone(arg);
124}
a553a5a3 125
48f44632 126void
601af4c6 127eventAdd(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
48f44632 128{
a553a5a3 129 EventScheduler::GetInstance()->schedule(name, func, arg, when, weight, cbdata);
48f44632 130}
131
8f3db324 132/* same as eventAdd but adds a random offset within +-1/3 of delta_ish */
133void
52040193 134eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int weight)
8f3db324 135{
52040193 136 if (delta_ish >= 3.0) {
62e76326 137 const double two_third = (2.0 * delta_ish) / 3.0;
138 delta_ish = two_third + (drand48() * two_third);
139 /*
140 * I'm sure drand48() isn't portable. Tell me what function
141 * you have that returns a random double value in the range 0,1.
142 */
8f3db324 143 }
62e76326 144
f720985e 145 eventAdd(name, func, arg, delta_ish, weight);
8f3db324 146}
147
93775f90 148void
582b6456 149eventDelete(EVH * func, void *arg)
93775f90 150{
a553a5a3 151 EventScheduler::GetInstance()->cancel(func, arg);
152}
62e76326 153
a553a5a3 154void
15b3c0d7 155eventInit(void)
a553a5a3 156{
8822ebee 157 Mgr::RegisterAction("events", "Event Queue", eventDump, 0, 1);
a553a5a3 158}
62e76326 159
a553a5a3 160static void
161eventDump(StoreEntry * sentry)
162{
163 EventScheduler::GetInstance()->dump(sentry);
164}
165
166void
167eventFreeMemory(void)
168{
169 EventScheduler::GetInstance()->clean();
170}
171
172int
173eventFind(EVH * func, void *arg)
174{
175 return EventScheduler::GetInstance()->find(func, arg);
176}
177
5dee3116 178EventScheduler EventScheduler::_instance;
a553a5a3 179
5dee3116 180EventScheduler::EventScheduler(): tasks(NULL)
a553a5a3 181{}
182
183EventScheduler::~EventScheduler()
184{
185 clean();
186}
187
188void
189EventScheduler::cancel(EVH * func, void *arg)
190{
191 ev_entry **E;
192 ev_entry *event;
62e76326 193
79d39a72 194 for (E = &tasks; (event = *E) != NULL; E = &(*E)->next) {
62e76326 195 if (event->func != func)
196 continue;
197
aa93f210 198 if (arg && event->arg != arg)
62e76326 199 continue;
200
201 *E = event->next;
202
62ee09ca 203 delete event;
62e76326 204
26ac0430
AJ
205 if (arg)
206 return;
207 /*
208 * DPW 2007-04-12
209 * Since this method may now delete multiple events (when
210 * arg is NULL) it no longer returns after a deletion and
211 * we have a potential NULL pointer problem. If we just
212 * deleted the last event in the list then *E is now equal
213 * to NULL. We need to break here or else we'll get a NULL
214 * pointer dereference in the last clause of the for loop.
215 */
216 if (NULL == *E)
217 break;
93775f90 218 }
62e76326 219
aa93f210 220 if (arg)
26ac0430 221 debug_trap("eventDelete: event not found");
93775f90 222}
223
aa14d759
AR
224// The event API does not guarantee exact timing, but guarantees that no event
225// is fired before it is due. We may delay firing, but never fire too early.
a553a5a3 226int
aa14d759 227EventScheduler::timeRemaining() const
a553a5a3 228{
229 if (!tasks)
aa839030 230 return EVENT_IDLE;
a553a5a3 231
aa14d759
AR
232 if (tasks->when <= current_dtime) // we are on time or late
233 return 0; // fire the event ASAP
8ff3fa2e 234
aa14d759
AR
235 const double diff = tasks->when - current_dtime; // microseconds
236 // Round UP: If we come back a nanosecond earlier, we will wait again!
237 const int timeLeft = static_cast<int>(ceil(1000*diff)); // milliseconds
238 // Avoid hot idle: A series of rapid select() calls with zero timeout.
239 const int minDelay = 1; // millisecond
240 return max(minDelay, timeLeft);
a553a5a3 241}
242
243int
8ff3fa2e 244EventScheduler::checkEvents(int timeout)
48f44632 245{
aa14d759
AR
246 int result = timeRemaining();
247 if (result != 0)
248 return result;
62e76326 249
1d5161bd 250 PROF_start(eventRun);
251
aa14d759
AR
252 do {
253 ev_entry *event = tasks;
254 assert(event);
62e76326 255
5dee3116 256 /* XXX assumes event->name is static memory! */
257 AsyncCall::Pointer call = asyncCall(41,5, event->name,
26ac0430 258 EventDialer(event->func, event->arg, event->cbdata));
5dee3116 259 ScheduleCallHere(call);
260
261 last_event_ran = event->name; // XXX: move this to AsyncCallQueue
262 const bool heavy = event->weight &&
26ac0430 263 (!event->cbdata || cbdataReferenceValid(event->arg));
62e76326 264
265 tasks = event->next;
5dee3116 266 delete event;
62e76326 267
aa14d759
AR
268 result = timeRemaining();
269
5dee3116 270 // XXX: We may be called again during the same event loop iteration.
271 // Is there a point in breaking now?
26ac0430 272 if (heavy)
5dee3116 273 break; // do not dequeue events following a heavy event
aa14d759 274 } while (result == 0);
1d5161bd 275
276 PROF_stop(eventRun);
aa14d759 277 return result;
48f44632 278}
279
a553a5a3 280void
281EventScheduler::clean()
48f44632 282{
a553a5a3 283 while (ev_entry * event = tasks) {
284 tasks = event->next;
a553a5a3 285 delete event;
286 }
287
288 tasks = NULL;
4ba55996 289}
290
a553a5a3 291void
292EventScheduler::dump(StoreEntry * sentry)
4ba55996 293{
62e76326 294
cb9f32a9 295 ev_entry *e = tasks;
62e76326 296
236b1f2a 297 if (last_event_ran)
62e76326 298 storeAppendPrintf(sentry, "Last event to run: %s\n\n", last_event_ran);
299
cc192b50 300 storeAppendPrintf(sentry, "%-25s\t%-15s\t%s\t%s\n",
62e76326 301 "Operation",
302 "Next Execution",
303 "Weight",
304 "Callback Valid?");
305
4ba55996 306 while (e != NULL) {
cc192b50 307 storeAppendPrintf(sentry, "%-25s\t%0.3f sec\t%5d\t %s\n",
32f10aa5 308 e->name, e->when ? e->when - current_dtime : 0, e->weight,
601af4c6 309 (e->arg && e->cbdata) ? cbdataReferenceValid(e->arg) ? "yes" : "no" : "N/A");
62e76326 310 e = e->next;
4ba55996 311 }
312}
f1fc2a8d 313
a553a5a3 314bool
315EventScheduler::find(EVH * func, void * arg)
f1fc2a8d 316{
62e76326 317
cb9f32a9 318 ev_entry *event;
62e76326 319
a553a5a3 320 for (event = tasks; event != NULL; event = event->next) {
321 if (event->func == func && event->arg == arg)
322 return true;
f1fc2a8d 323 }
62e76326 324
a553a5a3 325 return false;
f1fc2a8d 326}
46ca5fc6 327
a553a5a3 328EventScheduler *
329EventScheduler::GetInstance()
46ca5fc6 330{
a553a5a3 331 return &_instance;
332}
62e76326 333
a553a5a3 334void
335EventScheduler::schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
336{
a5a02499 337 // Use zero timestamp for when=0 events: Many of them are async calls that
338 // must fire in the submission order. We cannot use current_dtime for them
339 // because it may decrease if system clock is adjusted backwards.
340 const double timestamp = when > 0.0 ? current_dtime + when : 0;
cb9f32a9 341 ev_entry *event = new ev_entry(name, func, arg, timestamp, weight, cbdata);
a553a5a3 342
cb9f32a9 343 ev_entry **E;
d65986ae 344 debugs(41, 7, HERE << "schedule: Adding '" << name << "', in " << when << " seconds");
a553a5a3 345 /* Insert after the last event with the same or earlier time */
346
347 for (E = &tasks; *E; E = &(*E)->next) {
348 if ((*E)->when > event->when)
349 break;
46ca5fc6 350 }
62e76326 351
a553a5a3 352 event->next = *E;
353 *E = event;
46ca5fc6 354}