]> git.ipfire.org Git - thirdparty/squid.git/blame - src/event.cc
Removed CVS $ markers
[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"
e6ccf245 37#include "Store.h"
cc192b50 38#include "SquidTime.h"
582c2af2 39#include "profiler/Profiler.h"
5bed43d6 40#include "tools.h"
48f44632 41
42/* The list of event processes */
62e76326 43
4ba55996 44static OBJH eventDump;
236b1f2a 45static const char *last_event_ran = NULL;
48f44632 46
26ac0430 47// This AsyncCall dialer can be configured to check that the event cbdata is
5dee3116 48// valid before calling the event handler
49class EventDialer: public CallDialer
50{
51public:
52 typedef CallDialer Parent;
53
54 EventDialer(EVH *aHandler, void *anArg, bool lockedArg);
55 EventDialer(const EventDialer &d);
56 virtual ~EventDialer();
57
58 virtual void print(std::ostream &os) const;
59 virtual bool canDial(AsyncCall &call);
60
61 void dial(AsyncCall &) { theHandler(theArg); }
62
63private:
64 EVH *theHandler;
65 void *theArg;
66 bool isLockedArg;
67};
68
69EventDialer::EventDialer(EVH *aHandler, void *anArg, bool lockedArg):
26ac0430 70 theHandler(aHandler), theArg(anArg), isLockedArg(lockedArg)
5dee3116 71{
72 if (isLockedArg)
451bde6d 73 (void)cbdataReference(theArg);
5dee3116 74}
75
76EventDialer::EventDialer(const EventDialer &d):
26ac0430 77 theHandler(d.theHandler), theArg(d.theArg), isLockedArg(d.isLockedArg)
5dee3116 78{
79 if (isLockedArg)
451bde6d 80 (void)cbdataReference(theArg);
5dee3116 81}
82
83EventDialer::~EventDialer()
84{
85 if (isLockedArg)
86 cbdataReferenceDone(theArg);
87}
88
89bool
26ac0430
AJ
90EventDialer::canDial(AsyncCall &call)
91{
5dee3116 92 // TODO: add Parent::canDial() that always returns true
93 //if (!Parent::canDial())
94 // return false;
95
96 if (isLockedArg && !cbdataReferenceValid(theArg))
97 return call.cancel("stale handler data");
98
99 return true;
100}
101
102void
103EventDialer::print(std::ostream &os) const
104{
105 os << '(';
106 if (theArg)
107 os << theArg << (isLockedArg ? "*?" : "");
108 os << ')';
109}
110
d5f8d05f
FC
111ev_entry::ev_entry(char const * aName, EVH * aFunction, void * aArgument, double evWhen,
112 int aWeight, bool haveArgument) : name(aName), func(aFunction),
113 arg(haveArgument ? cbdataReference(aArgument) : aArgument), when(evWhen), weight(aWeight),
e053c141 114 cbdata(haveArgument)
5dee3116 115{
116}
117
118ev_entry::~ev_entry()
119{
120 if (cbdata)
121 cbdataReferenceDone(arg);
122}
a553a5a3 123
48f44632 124void
601af4c6 125eventAdd(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
48f44632 126{
a553a5a3 127 EventScheduler::GetInstance()->schedule(name, func, arg, when, weight, cbdata);
48f44632 128}
129
8f3db324 130/* same as eventAdd but adds a random offset within +-1/3 of delta_ish */
131void
52040193 132eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int weight)
8f3db324 133{
52040193 134 if (delta_ish >= 3.0) {
62e76326 135 const double two_third = (2.0 * delta_ish) / 3.0;
136 delta_ish = two_third + (drand48() * two_third);
137 /*
138 * I'm sure drand48() isn't portable. Tell me what function
139 * you have that returns a random double value in the range 0,1.
140 */
8f3db324 141 }
62e76326 142
f720985e 143 eventAdd(name, func, arg, delta_ish, weight);
8f3db324 144}
145
93775f90 146void
582b6456 147eventDelete(EVH * func, void *arg)
93775f90 148{
a553a5a3 149 EventScheduler::GetInstance()->cancel(func, arg);
150}
62e76326 151
a553a5a3 152void
15b3c0d7 153eventInit(void)
a553a5a3 154{
8822ebee 155 Mgr::RegisterAction("events", "Event Queue", eventDump, 0, 1);
a553a5a3 156}
62e76326 157
a553a5a3 158static void
159eventDump(StoreEntry * sentry)
160{
161 EventScheduler::GetInstance()->dump(sentry);
162}
163
164void
165eventFreeMemory(void)
166{
167 EventScheduler::GetInstance()->clean();
168}
169
170int
171eventFind(EVH * func, void *arg)
172{
173 return EventScheduler::GetInstance()->find(func, arg);
174}
175
5dee3116 176EventScheduler EventScheduler::_instance;
a553a5a3 177
5dee3116 178EventScheduler::EventScheduler(): tasks(NULL)
a553a5a3 179{}
180
181EventScheduler::~EventScheduler()
182{
183 clean();
184}
185
186void
187EventScheduler::cancel(EVH * func, void *arg)
188{
189 ev_entry **E;
190 ev_entry *event;
62e76326 191
79d39a72 192 for (E = &tasks; (event = *E) != NULL; E = &(*E)->next) {
62e76326 193 if (event->func != func)
194 continue;
195
aa93f210 196 if (arg && event->arg != arg)
62e76326 197 continue;
198
199 *E = event->next;
200
62ee09ca 201 delete event;
62e76326 202
26ac0430
AJ
203 if (arg)
204 return;
205 /*
206 * DPW 2007-04-12
207 * Since this method may now delete multiple events (when
208 * arg is NULL) it no longer returns after a deletion and
209 * we have a potential NULL pointer problem. If we just
210 * deleted the last event in the list then *E is now equal
211 * to NULL. We need to break here or else we'll get a NULL
212 * pointer dereference in the last clause of the for loop.
213 */
214 if (NULL == *E)
215 break;
93775f90 216 }
62e76326 217
aa93f210 218 if (arg)
26ac0430 219 debug_trap("eventDelete: event not found");
93775f90 220}
221
a553a5a3 222int
223EventScheduler::checkDelay()
224{
225 if (!tasks)
aa839030 226 return EVENT_IDLE;
a553a5a3 227
8ff3fa2e 228 int result = (int) ((tasks->when - current_dtime) * 1000);
229
230 if (result < 0)
231 return 0;
232
233 return result;
a553a5a3 234}
235
236int
8ff3fa2e 237EventScheduler::checkEvents(int timeout)
48f44632 238{
62e76326 239
cb9f32a9 240 ev_entry *event = NULL;
62e76326 241
c43f5247 242 if (NULL == tasks)
a553a5a3 243 return checkDelay();
62e76326 244
c43f5247 245 if (tasks->when > current_dtime)
a553a5a3 246 return checkDelay();
62e76326 247
1d5161bd 248 PROF_start(eventRun);
249
15584534 250 debugs(41, 5, HERE << "checkEvents");
62e76326 251
c43f5247 252 while ((event = tasks)) {
62e76326 253 if (event->when > current_dtime)
254 break;
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
5dee3116 268 // XXX: We may be called again during the same event loop iteration.
269 // Is there a point in breaking now?
26ac0430 270 if (heavy)
5dee3116 271 break; // do not dequeue events following a heavy event
d90c79ee 272 }
1d5161bd 273
274 PROF_stop(eventRun);
a553a5a3 275 return checkDelay();
48f44632 276}
277
a553a5a3 278void
279EventScheduler::clean()
48f44632 280{
a553a5a3 281 while (ev_entry * event = tasks) {
282 tasks = event->next;
a553a5a3 283 delete event;
284 }
285
286 tasks = NULL;
4ba55996 287}
288
a553a5a3 289void
290EventScheduler::dump(StoreEntry * sentry)
4ba55996 291{
62e76326 292
cb9f32a9 293 ev_entry *e = tasks;
62e76326 294
236b1f2a 295 if (last_event_ran)
62e76326 296 storeAppendPrintf(sentry, "Last event to run: %s\n\n", last_event_ran);
297
cc192b50 298 storeAppendPrintf(sentry, "%-25s\t%-15s\t%s\t%s\n",
62e76326 299 "Operation",
300 "Next Execution",
301 "Weight",
302 "Callback Valid?");
303
4ba55996 304 while (e != NULL) {
cc192b50 305 storeAppendPrintf(sentry, "%-25s\t%0.3f sec\t%5d\t %s\n",
32f10aa5 306 e->name, e->when ? e->when - current_dtime : 0, e->weight,
601af4c6 307 (e->arg && e->cbdata) ? cbdataReferenceValid(e->arg) ? "yes" : "no" : "N/A");
62e76326 308 e = e->next;
4ba55996 309 }
310}
f1fc2a8d 311
a553a5a3 312bool
313EventScheduler::find(EVH * func, void * arg)
f1fc2a8d 314{
62e76326 315
cb9f32a9 316 ev_entry *event;
62e76326 317
a553a5a3 318 for (event = tasks; event != NULL; event = event->next) {
319 if (event->func == func && event->arg == arg)
320 return true;
f1fc2a8d 321 }
62e76326 322
a553a5a3 323 return false;
f1fc2a8d 324}
46ca5fc6 325
a553a5a3 326EventScheduler *
327EventScheduler::GetInstance()
46ca5fc6 328{
a553a5a3 329 return &_instance;
330}
62e76326 331
a553a5a3 332void
333EventScheduler::schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata)
334{
a5a02499 335 // Use zero timestamp for when=0 events: Many of them are async calls that
336 // must fire in the submission order. We cannot use current_dtime for them
337 // because it may decrease if system clock is adjusted backwards.
338 const double timestamp = when > 0.0 ? current_dtime + when : 0;
cb9f32a9 339 ev_entry *event = new ev_entry(name, func, arg, timestamp, weight, cbdata);
a553a5a3 340
cb9f32a9 341 ev_entry **E;
d65986ae 342 debugs(41, 7, HERE << "schedule: Adding '" << name << "', in " << when << " seconds");
a553a5a3 343 /* Insert after the last event with the same or earlier time */
344
345 for (E = &tasks; *E; E = &(*E)->next) {
346 if ((*E)->when > event->when)
347 break;
46ca5fc6 348 }
62e76326 349
a553a5a3 350 event->next = *E;
351 *E = event;
46ca5fc6 352}