6 #include "../lib/array.h"
12 #define INITSCHEDSIZE 1000
13 #define GROWSCHEDSIZE 500
26 /* Local prototypes */
27 void schedulestats(int hooknum
, void *arg
);
31 schedadds
=scheddels
=schedexes
=scheddelfast
=0;
32 registerhook(HOOK_CORE_STATSREQUEST
, &schedulestats
);
34 heapmax
=INITSCHEDSIZE
;
35 events
=(schedule
**)malloc(INITSCHEDSIZE
*sizeof(schedule
*));
39 deregisterhook(HOOK_CORE_STATSREQUEST
, &schedulestats
);
43 void schedule_heapify(int index
) {
47 /* If this node is a leaf, do nothing */
48 if ((index
*2)+1 >= heapsize
) {
52 /* Check left child */
53 if (events
[index
]->nextschedule
> events
[(index
*2)+1]->nextschedule
) {
54 firstindex
=(index
*2)+1;
57 /* Check right (if exists) */
58 if ((index
*2)+2 < heapsize
) {
59 if (events
[firstindex
]->nextschedule
> events
[(index
*2)+2]->nextschedule
) {
60 firstindex
=(index
*2)+2;
64 /* If both children were scheduled after us, we're done */
65 if (firstindex
==index
) {
69 /* Swap the two pointers around in the heap */
70 ep
=events
[firstindex
];
71 events
[firstindex
]=events
[index
];
74 /* Fix up the "index" field in the structures */
75 events
[firstindex
]->index
=firstindex
;
76 events
[index
]->index
=index
;
78 schedule_heapify(firstindex
);
81 void insertschedule (schedule
*sp
) {
86 if (heapsize
>=heapmax
) {
87 /* We need to grow the heap */
88 heapmax
+=GROWSCHEDSIZE
;
89 events
=(schedule
**)realloc((void *)events
,heapmax
*sizeof(schedule
*));
94 /* Travel up the heap looking for a slot for this new element */
95 /* mypos points at a (vacant) candidate space; we either put the element
96 * in this space, or pull it's parent down and try again with it's parent's space */
99 if (mypos
==0 || (sp
->nextschedule
>= events
[myparent
]->nextschedule
)) {
100 /* We reached the top, or our parent is scheduled before us -- end */
105 /* Pull the parent into this space and move up the heap */
106 events
[mypos
]=events
[myparent
];
107 events
[mypos
]->index
=mypos
;
113 void schedule_remove (int index
) {
117 assert(index
<heapsize
);
120 Error("schedule",ERR_DEBUG
,"schedule_remove: %d",index
);
129 /* Move the last element into the position we just deleted, then heapify
130 * If we happen to be deleting the last element, do nothing */
131 if (index
!=heapsize
) {
132 events
[index
]->index
=-1;
133 events
[index
]=events
[heapsize
];
134 events
[index
]->index
=index
;
135 schedule_heapify(index
);
137 /* Now we may need to float the element up the heap, similar to the insert case */
140 myparent
=(mypos
-1)/2;
141 if (mypos
==0 || (events
[mypos
]->nextschedule
>= events
[myparent
]->nextschedule
)) {
144 /* Swap the element up the tree */
146 events
[myparent
]=events
[mypos
];
148 /* Fix up the index members */
149 events
[myparent
]->index
=myparent
;
150 events
[mypos
]->index
=mypos
;
158 void *scheduleoneshot(time_t when
, ScheduleCallback callback
, void *arg
) {
163 sp
->nextschedule
=when
;
164 sp
->type
=SCHEDULE_ONESHOT
;
165 sp
->repeatinterval
=0;
167 sp
->callback
=callback
;
168 sp
->callbackparam
=arg
;
174 Error("schedule",ERR_DEBUG
,"scheduleoneshot: (%ld, %x, %x) = %x",when
, (unsigned int)callback
, (unsigned int)arg
, (unsigned int)sp
);
180 void *schedulerecurring(time_t first
, int count
, time_t interval
, ScheduleCallback callback
, void *arg
) {
184 return scheduleoneshot(first
, callback
, arg
);
189 sp
->nextschedule
=first
;
190 sp
->type
=SCHEDULE_REPEATING
;
191 sp
->repeatinterval
=interval
;
192 sp
->repeatcount
=(count
-1);
193 sp
->callback
=callback
;
194 sp
->callbackparam
=arg
;
202 void deleteschedule(void *sch
, ScheduleCallback callback
, void *arg
) {
206 /* New (optional) faster path: Clients can track the schedule pointer if they wish and
207 * pass it in here for an O(1) *cough* O(lg n) delete */
210 Error("schedule",ERR_DEBUG
,"deleteschedule(%x,%x,%x)",(unsigned int)sch
,(unsigned int)callback
, (unsigned int)arg
);
215 /* Double check the params are correct:
216 * it's perfectly OK to delete a schedule that has been executed,
217 * we're just marking the schedule as deleted here so that it can be
218 * cleaned up by doscheduledevents later on. */
220 if (sp
->callback
==callback
&& sp
->callbackparam
==arg
&& !sp
->deleted
) {
225 Error("schedule",ERR_DEBUG
,"deleted schedule that was previously marked as deleted");
231 /* Argh, have to find it by brute force */
233 for(i
=0;i
<heapsize
;i
++) {
234 if (events
[i
]->callback
==callback
&& events
[i
]->callbackparam
==arg
&& !events
[i
]->deleted
) {
242 void deleteallschedules(ScheduleCallback callback
) {
247 /* OK, this gets to be REALLY cheesy and stupidly slow as well */
249 for(i
=0;i
<heapsize
;i
++) {
250 if (events
[i
]->callback
==callback
) {
252 schedule_remove(sp
->index
);
259 void doscheduledevents(time_t when
) {
264 while (heapsize
&& events
[0] && events
[0]->nextschedule
<= when
) {
265 /* Pick out the first element first */
267 sp
->index
=-1; /* Invalidate index so that an explicit delete doesn't screw us up */
269 /* Remove from the top of the heap */
271 events
[0]=events
[heapsize
];
275 /* This schedule was previously marked as deleted and we're now lazily cleaning it up. */
281 if (sp
->callback
==NULL
) {
282 Error("core",ERR_ERROR
,"Tried to call NULL function in doscheduledevents(): (%p, %p, %p)",sp
,sp
->callback
,sp
->callbackparam
);
286 /* Store the callback */
287 arg
=(sp
->callbackparam
);
290 /* Update the structures _before_ doing the callback.. */
292 case SCHEDULE_ONESHOT
:
296 case SCHEDULE_REPEATING
:
297 sp
->nextschedule
+=sp
->repeatinterval
;
299 * 0 for repeat forever
300 * 1 for repeat set number of times..
302 * When we schedule it for the last time, change it to a ONESHOT event
304 if (sp
->repeatcount
>0) {
306 if (sp
->repeatcount
==0) {
307 sp
->type
=SCHEDULE_ONESHOT
;
316 Error("schedule",ERR_DEBUG
,"exec schedule:(%x, %x, %x)", (unsigned int)sp
, (unsigned int)sc
, (unsigned int)arg
);
320 Error("schedule",ERR_DEBUG
,"schedule run OK");
326 void schedulestats(int hooknum
, void *arg
) {
327 long level
=(long)arg
;
331 sprintf(buf
,"Schedule:%7d events scheduled, %7d events executed",schedadds
,schedexes
);
332 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
333 sprintf(buf
,"Schedule:%7d events deleted, %7d fast deletes (%.2f%%)",scheddels
,scheddelfast
,(float)(scheddelfast
*100)/scheddels
);
334 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
335 sprintf(buf
,"Schedule:%7d events currently in queue",heapsize
);
336 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);