]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/event.cc
2 * DEBUG: section 41 Event Processing
3 * AUTHOR: Henrik Nordstrom
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
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.
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.
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.
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
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "compat/drand48.h"
36 #include "mgr/Registration.h"
37 #include "profiler/Profiler.h"
38 #include "SquidTime.h"
44 /* The list of event processes */
46 static OBJH eventDump
;
47 static const char *last_event_ran
= NULL
;
49 // This AsyncCall dialer can be configured to check that the event cbdata is
50 // valid before calling the event handler
51 class EventDialer
: public CallDialer
54 typedef CallDialer Parent
;
56 EventDialer(EVH
*aHandler
, void *anArg
, bool lockedArg
);
57 EventDialer(const EventDialer
&d
);
58 virtual ~EventDialer();
60 virtual void print(std::ostream
&os
) const;
61 virtual bool canDial(AsyncCall
&call
);
63 void dial(AsyncCall
&) { theHandler(theArg
); }
71 EventDialer::EventDialer(EVH
*aHandler
, void *anArg
, bool lockedArg
):
72 theHandler(aHandler
), theArg(anArg
), isLockedArg(lockedArg
)
75 (void)cbdataReference(theArg
);
78 EventDialer::EventDialer(const EventDialer
&d
):
79 theHandler(d
.theHandler
), theArg(d
.theArg
), isLockedArg(d
.isLockedArg
)
82 (void)cbdataReference(theArg
);
85 EventDialer::~EventDialer()
88 cbdataReferenceDone(theArg
);
92 EventDialer::canDial(AsyncCall
&call
)
94 // TODO: add Parent::canDial() that always returns true
95 //if (!Parent::canDial())
98 if (isLockedArg
&& !cbdataReferenceValid(theArg
))
99 return call
.cancel("stale handler data");
105 EventDialer::print(std::ostream
&os
) const
109 os
<< theArg
<< (isLockedArg
? "*?" : "");
113 ev_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
),
120 ev_entry::~ev_entry()
123 cbdataReferenceDone(arg
);
127 eventAdd(const char *name
, EVH
* func
, void *arg
, double when
, int weight
, bool cbdata
)
129 EventScheduler::GetInstance()->schedule(name
, func
, arg
, when
, weight
, cbdata
);
132 /* same as eventAdd but adds a random offset within +-1/3 of delta_ish */
134 eventAddIsh(const char *name
, EVH
* func
, void *arg
, double delta_ish
, int weight
)
136 if (delta_ish
>= 3.0) {
137 const double two_third
= (2.0 * delta_ish
) / 3.0;
138 delta_ish
= two_third
+ (drand48() * two_third
);
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.
145 eventAdd(name
, func
, arg
, delta_ish
, weight
);
149 eventDelete(EVH
* func
, void *arg
)
151 EventScheduler::GetInstance()->cancel(func
, arg
);
157 Mgr::RegisterAction("events", "Event Queue", eventDump
, 0, 1);
161 eventDump(StoreEntry
* sentry
)
163 EventScheduler::GetInstance()->dump(sentry
);
167 eventFreeMemory(void)
169 EventScheduler::GetInstance()->clean();
173 eventFind(EVH
* func
, void *arg
)
175 return EventScheduler::GetInstance()->find(func
, arg
);
178 EventScheduler
EventScheduler::_instance
;
180 EventScheduler::EventScheduler(): tasks(NULL
)
183 EventScheduler::~EventScheduler()
189 EventScheduler::cancel(EVH
* func
, void *arg
)
194 for (E
= &tasks
; (event
= *E
) != NULL
; E
= &(*E
)->next
) {
195 if (event
->func
!= func
)
198 if (arg
&& event
->arg
!= arg
)
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.
221 debug_trap("eventDelete: event not found");
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.
227 EventScheduler::timeRemaining() const
232 if (tasks
->when
<= current_dtime
) // we are on time or late
233 return 0; // fire the event ASAP
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
);
244 EventScheduler::checkEvents(int timeout
)
246 int result
= timeRemaining();
250 PROF_start(eventRun
);
253 ev_entry
*event
= tasks
;
256 /* XXX assumes event->name is static memory! */
257 AsyncCall::Pointer call
= asyncCall(41,5, event
->name
,
258 EventDialer(event
->func
, event
->arg
, event
->cbdata
));
259 ScheduleCallHere(call
);
261 last_event_ran
= event
->name
; // XXX: move this to AsyncCallQueue
262 const bool heavy
= event
->weight
&&
263 (!event
->cbdata
|| cbdataReferenceValid(event
->arg
));
268 result
= timeRemaining();
270 // XXX: We may be called again during the same event loop iteration.
271 // Is there a point in breaking now?
273 break; // do not dequeue events following a heavy event
274 } while (result
== 0);
281 EventScheduler::clean()
283 while (ev_entry
* event
= tasks
) {
292 EventScheduler::dump(StoreEntry
* sentry
)
298 storeAppendPrintf(sentry
, "Last event to run: %s\n\n", last_event_ran
);
300 storeAppendPrintf(sentry
, "%-25s\t%-15s\t%s\t%s\n",
307 storeAppendPrintf(sentry
, "%-25s\t%0.3f sec\t%5d\t %s\n",
308 e
->name
, e
->when
? e
->when
- current_dtime
: 0, e
->weight
,
309 (e
->arg
&& e
->cbdata
) ? cbdataReferenceValid(e
->arg
) ? "yes" : "no" : "N/A");
315 EventScheduler::find(EVH
* func
, void * arg
)
320 for (event
= tasks
; event
!= NULL
; event
= event
->next
) {
321 if (event
->func
== func
&& event
->arg
== arg
)
329 EventScheduler::GetInstance()
335 EventScheduler::schedule(const char *name
, EVH
* func
, void *arg
, double when
, int weight
, bool cbdata
)
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;
341 ev_entry
*event
= new ev_entry(name
, func
, arg
, timestamp
, weight
, cbdata
);
344 debugs(41, 7, HERE
<< "schedule: Adding '" << name
<< "', in " << when
<< " seconds");
345 /* Insert after the last event with the same or earlier time */
347 for (E
= &tasks
; *E
; E
= &(*E
)->next
) {
348 if ((*E
)->when
> event
->when
)