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