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
*));
39 void schedule_heapify(int index
) {
43 /* If this node is a leaf, do nothing */
44 if ((index
*2)+1 >= heapsize
) {
48 /* Check left child */
49 if (events
[index
]->nextschedule
> events
[(index
*2)+1]->nextschedule
) {
50 firstindex
=(index
*2)+1;
53 /* Check right (if exists) */
54 if ((index
*2)+2 < heapsize
) {
55 if (events
[firstindex
]->nextschedule
> events
[(index
*2)+2]->nextschedule
) {
56 firstindex
=(index
*2)+2;
60 /* If both children were scheduled after us, we're done */
61 if (firstindex
==index
) {
65 /* Swap the two pointers around in the heap */
66 ep
=events
[firstindex
];
67 events
[firstindex
]=events
[index
];
70 /* Fix up the "index" field in the structures */
71 events
[firstindex
]->index
=firstindex
;
72 events
[index
]->index
=index
;
74 schedule_heapify(firstindex
);
77 void insertschedule (schedule
*sp
) {
82 if (heapsize
>=heapmax
) {
83 /* We need to grow the heap */
84 heapmax
+=GROWSCHEDSIZE
;
85 events
=(schedule
**)realloc((void *)events
,heapmax
*sizeof(schedule
*));
90 /* Travel up the heap looking for a slot for this new element */
91 /* mypos points at a (vacant) candidate space; we either put the element
92 * in this space, or pull it's parent down and try again with it's parent's space */
95 if (mypos
==0 || (sp
->nextschedule
>= events
[myparent
]->nextschedule
)) {
96 /* We reached the top, or our parent is scheduled before us -- end */
101 /* Pull the parent into this space and move up the heap */
102 events
[mypos
]=events
[myparent
];
103 events
[mypos
]->index
=mypos
;
109 void schedule_remove (int index
) {
113 assert(index
<heapsize
);
116 Error("schedule",ERR_DEBUG
,"schedule_remove: %d",index
);
125 /* Move the last element into the position we just deleted, then heapify
126 * If we happen to be deleting the last element, do nothing */
127 if (index
!=heapsize
) {
128 events
[index
]->index
=-1;
129 events
[index
]=events
[heapsize
];
130 events
[index
]->index
=index
;
131 schedule_heapify(index
);
133 /* Now we may need to float the element up the heap, similar to the insert case */
136 myparent
=(mypos
-1)/2;
137 if (mypos
==0 || (events
[mypos
]->nextschedule
>= events
[myparent
]->nextschedule
)) {
140 /* Swap the element up the tree */
142 events
[myparent
]=events
[mypos
];
144 /* Fix up the index members */
145 events
[myparent
]->index
=myparent
;
146 events
[mypos
]->index
=mypos
;
154 void *scheduleoneshot(time_t when
, ScheduleCallback callback
, void *arg
) {
159 sp
->nextschedule
=when
;
160 sp
->type
=SCHEDULE_ONESHOT
;
161 sp
->repeatinterval
=0;
163 sp
->callback
=callback
;
164 sp
->callbackparam
=arg
;
169 Error("schedule",ERR_DEBUG
,"scheduleoneshot: (%ld, %x, %x) = %x",when
, callback
, arg
, sp
);
175 void *schedulerecurring(time_t first
, int count
, time_t interval
, ScheduleCallback callback
, void *arg
) {
179 return scheduleoneshot(first
, callback
, arg
);
184 sp
->nextschedule
=first
;
185 sp
->type
=SCHEDULE_REPEATING
;
186 sp
->repeatinterval
=interval
;
187 sp
->repeatcount
=(count
-1);
188 sp
->callback
=callback
;
189 sp
->callbackparam
=arg
;
196 void deleteschedule(void *sch
, ScheduleCallback callback
, void *arg
) {
200 /* New (optional) faster path: Clients can track the schedule pointer if they wish and
201 * pass it in here for an O(1) *cough* O(lg n) delete */
204 Error("schedule",ERR_DEBUG
,"deleteschedule(%x,%x,%x)",sch
,callback
, arg
);
209 /* Double check the params are correct:
210 * because we recycle and never free schedule structs it's
211 * actually OK to try and delete a schedule that has been executed... */
213 if (sp
->callback
==callback
&& sp
->callbackparam
==arg
) {
215 schedule_remove(sp
->index
);
221 /* Argh, have to find it by brute force */
223 for(i
=0;i
<heapsize
;i
++) {
224 if ((events
[i
]->callback
==callback
) && (events
[i
]->callbackparam
==arg
)) {
226 schedule_remove(sp
->index
);
233 void deleteallschedules(ScheduleCallback callback
) {
238 /* OK, this gets to be REALLY cheesy and stupidly slow as well */
240 for(i
=0;i
<heapsize
;i
++) {
241 if (events
[i
]->callback
==callback
) {
243 schedule_remove(sp
->index
);
250 void doscheduledevents(time_t when
) {
255 while (heapsize
&& events
[0] && events
[0]->nextschedule
<= when
) {
256 /* Pick out the first element first */
258 sp
->index
=-1; /* Invalidate index so that an explicit delete doesn't screw us up */
260 /* Remove from the top of the heap */
262 events
[0]=events
[heapsize
];
266 if (sp
->callback
==NULL
) {
267 Error("core",ERR_ERROR
,"Tried to call NULL function in doscheduledevents(): (%x, %x, %x)",sp
,sp
->callback
,sp
->callbackparam
);
271 /* Store the callback */
272 arg
=(sp
->callbackparam
);
275 /* Update the structures _before_ doing the callback.. */
277 case SCHEDULE_ONESHOT
:
281 case SCHEDULE_REPEATING
:
282 sp
->nextschedule
+=sp
->repeatinterval
;
284 * 0 for repeat forever
285 * 1 for repeat set number of times..
287 * When we schedule it for the last time, change it to a ONESHOT event
289 if (sp
->repeatcount
>0) {
291 if (sp
->repeatcount
==0) {
292 sp
->type
=SCHEDULE_ONESHOT
;
299 Error("schedule",ERR_DEBUG
,"exec schedule:(%x, %x, %x)", sp
, sc
, arg
);
303 Error("schedule",ERR_DEBUG
,"schedule run OK");
309 void schedulestats(int hooknum
, void *arg
) {
310 long level
=(long)arg
;
314 sprintf(buf
,"Schedule:%7d events scheduled, %7d events executed",schedadds
,schedexes
);
315 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
316 sprintf(buf
,"Schedule:%7d events deleted, %7d fast deletes (%.2f%%)",scheddels
,scheddelfast
,(float)(scheddelfast
*100)/scheddels
);
317 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);
318 sprintf(buf
,"Schedule:%7d events currently in queue",heapsize
);
319 triggerhook(HOOK_CORE_STATSREPLY
,(void *)buf
);