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