6 #include "../lib/array.h"
12 #define INITSCHEDSIZE 1000
13 #define GROWSCHEDSIZE 500
26 /* Local prototypes */
27 void schedulestats(int hooknum
, void *arg
);
32 schedadds
=scheddels
=schedexes
=scheddelfast
=0;
33 registerhook(HOOK_CORE_STATSREQUEST
, &schedulestats
);
35 heapmax
=INITSCHEDSIZE
;
36 events
=(schedule
**)malloc(INITSCHEDSIZE
*sizeof(schedule
*));
40 deregisterhook(HOOK_CORE_STATSREQUEST
, &schedulestats
);
44 void schedule_heapify(int index
) {
48 /* If this node is a leaf, do nothing */
49 if ((index
*2)+1 >= heapsize
) {
53 /* Check left child */
54 if (events
[index
]->nextschedule
> events
[(index
*2)+1]->nextschedule
) {
55 firstindex
=(index
*2)+1;
58 /* Check right (if exists) */
59 if ((index
*2)+2 < heapsize
) {
60 if (events
[firstindex
]->nextschedule
> events
[(index
*2)+2]->nextschedule
) {
61 firstindex
=(index
*2)+2;
65 /* If both children were scheduled after us, we're done */
66 if (firstindex
==index
) {
70 /* Swap the two pointers around in the heap */
71 ep
=events
[firstindex
];
72 events
[firstindex
]=events
[index
];
75 /* Fix up the "index" field in the structures */
76 events
[firstindex
]->index
=firstindex
;
77 events
[index
]->index
=index
;
79 schedule_heapify(firstindex
);
82 void insertschedule (schedule
*sp
) {
87 if (heapsize
>=heapmax
) {
88 /* We need to grow the heap */
89 heapmax
+=GROWSCHEDSIZE
;
90 events
=(schedule
**)realloc((void *)events
,heapmax
*sizeof(schedule
*));
95 /* Travel up the heap looking for a slot for this new element */
96 /* mypos points at a (vacant) candidate space; we either put the element
97 * in this space, or pull it's parent down and try again with it's parent's space */
100 if (mypos
==0 || (sp
->nextschedule
>= events
[myparent
]->nextschedule
)) {
101 /* We reached the top, or our parent is scheduled before us -- end */
106 /* Pull the parent into this space and move up the heap */
107 events
[mypos
]=events
[myparent
];
108 events
[mypos
]->index
=mypos
;
114 void schedule_remove (int index
) {
118 assert(index
<heapsize
);
121 Error("schedule",ERR_DEBUG
,"schedule_remove: %d",index
);
130 /* Move the last element into the position we just deleted, then heapify
131 * If we happen to be deleting the last element, do nothing */
132 if (index
!=heapsize
) {
133 events
[index
]->index
=-1;
134 events
[index
]=events
[heapsize
];
135 events
[index
]->index
=index
;
136 schedule_heapify(index
);
138 /* Now we may need to float the element up the heap, similar to the insert case */
141 myparent
=(mypos
-1)/2;
142 if (mypos
==0 || (events
[mypos
]->nextschedule
>= events
[myparent
]->nextschedule
)) {
145 /* Swap the element up the tree */
147 events
[myparent
]=events
[mypos
];
149 /* Fix up the index members */
150 events
[myparent
]->index
=myparent
;
151 events
[mypos
]->index
=mypos
;
159 void *scheduleoneshot(time_t when
, ScheduleCallback callback
, void *arg
) {
164 sp
->nextschedule
=when
;
165 sp
->type
=SCHEDULE_ONESHOT
;
166 sp
->repeatinterval
=0;
168 sp
->callback
=callback
;
169 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
;
201 void deleteschedule(void *sch
, ScheduleCallback callback
, void *arg
) {
205 /* New (optional) faster path: Clients can track the schedule pointer if they wish and
206 * pass it in here for an O(1) *cough* O(lg n) delete */
209 Error("schedule",ERR_DEBUG
,"deleteschedule(%x,%x,%x)",(unsigned int)sch
,(unsigned int)callback
, (unsigned int)arg
);
214 /* Double check the params are correct:
215 * because we recycle and never free schedule structs it's
216 * actually OK to try and delete a schedule that has been executed... */
218 if (sp
->callback
==callback
&& sp
->callbackparam
==arg
) {
220 schedule_remove(sp
->index
);
226 /* Argh, have to find it by brute force */
228 for(i
=0;i
<heapsize
;i
++) {
229 if ((events
[i
]->callback
==callback
) && (events
[i
]->callbackparam
==arg
)) {
231 schedule_remove(sp
->index
);
238 void deleteallschedules(ScheduleCallback callback
) {
243 /* OK, this gets to be REALLY cheesy and stupidly slow as well */
245 for(i
=0;i
<heapsize
;i
++) {
246 if (events
[i
]->callback
==callback
) {
248 schedule_remove(sp
->index
);
255 void doscheduledevents(time_t when
) {
260 while (heapsize
&& events
[0] && events
[0]->nextschedule
<= when
) {
261 /* Pick out the first element first */
263 sp
->index
=-1; /* Invalidate index so that an explicit delete doesn't screw us up */
265 /* Remove from the top of the heap */
267 events
[0]=events
[heapsize
];
271 if (sp
->callback
==NULL
) {
272 Error("core",ERR_ERROR
,"Tried to call NULL function in doscheduledevents(): (%p, %p, %p)",sp
,sp
->callback
,sp
->callbackparam
);
276 /* Store the callback */
277 arg
=(sp
->callbackparam
);
280 /* Update the structures _before_ doing the callback.. */
282 case SCHEDULE_ONESHOT
:
286 case SCHEDULE_REPEATING
:
287 sp
->nextschedule
+=sp
->repeatinterval
;
289 * 0 for repeat forever
290 * 1 for repeat set number of times..
292 * When we schedule it for the last time, change it to a ONESHOT event
294 if (sp
->repeatcount
>0) {
296 if (sp
->repeatcount
==0) {
297 sp
->type
=SCHEDULE_ONESHOT
;
304 Error("schedule",ERR_DEBUG
,"exec schedule:(%x, %x, %x)", (unsigned int)sp
, (unsigned int)sc
, (unsigned int)arg
);
308 Error("schedule",ERR_DEBUG
,"schedule run OK");
314 void schedulestats(int hooknum
, void *arg
) {
315 long level
=(long)arg
;
319 sprintf(buf
,"Schedule:%7d events scheduled, %7d events executed",schedadds
,schedexes
);
320 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
321 sprintf(buf
,"Schedule:%7d events deleted, %7d fast deletes (%.2f%%)",scheddels
,scheddelfast
,(float)(scheddelfast
*100)/scheddels
);
322 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
323 sprintf(buf
,"Schedule:%7d events currently in queue",heapsize
);
324 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);