00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <stddef.h>
00021 #include <stdlib.h>
00022 #include <limits.h>
00023 #include <string.h>
00024 #include <ccn/schedule.h>
00025
00026
00027
00028
00029
00030
00031 struct ccn_schedule_heap_item {
00032 intptr_t event_time;
00033 struct ccn_scheduled_event *ev;
00034 };
00035
00036 struct ccn_schedule {
00037 void *clienth;
00038 const struct ccn_gettime *clock;
00039 struct ccn_schedule_heap_item *heap;
00040 int heap_n;
00041 int heap_limit;
00042 int heap_height;
00043 int now;
00044 struct ccn_timeval lasttime;
00045 int time_has_passed;
00046 };
00047
00048
00049
00050
00051 static void
00052 update_epoch(struct ccn_schedule *sched)
00053 {
00054 struct ccn_schedule_heap_item *heap;
00055 int n;
00056 int i;
00057 int t = sched->now;
00058 heap = sched->heap;
00059 n = sched->heap_n;
00060 for (i = 0; i < n; i++)
00061 heap[i].event_time -= t;
00062 sched->now = 0;
00063 }
00064
00065 static void
00066 update_time(struct ccn_schedule *sched)
00067 {
00068 struct ccn_timeval now = { 0 };
00069 int elapsed;
00070 if (sched->time_has_passed < 0)
00071 return;
00072 sched->clock->gettime(sched->clock, &now);
00073
00074 if ((unsigned)(now.s - sched->lasttime.s) >= INT_MAX/4000000) {
00075
00076 sched->lasttime = now;
00077 }
00078 sched->time_has_passed = 1;
00079 elapsed = now.micros - sched->lasttime.micros +
00080 sched->clock->micros_per_base * (now.s - sched->lasttime.s);
00081 if (elapsed + sched->now < elapsed)
00082 update_epoch(sched);
00083 sched->now += elapsed;
00084 sched->lasttime = now;
00085 }
00086
00087 struct ccn_schedule *
00088 ccn_schedule_create(void *clienth, const struct ccn_gettime *ccnclock)
00089 {
00090 struct ccn_schedule *sched;
00091 if (ccnclock == NULL)
00092 return(NULL);
00093 sched = calloc(1, sizeof(*sched));
00094 if (sched != NULL) {
00095 sched->clienth = clienth;
00096 sched->clock = ccnclock;
00097 update_time(sched);
00098 }
00099 return(sched);
00100 }
00101
00102 void
00103 ccn_schedule_destroy(struct ccn_schedule **schedp)
00104 {
00105 struct ccn_schedule *sched;
00106 struct ccn_scheduled_event *ev;
00107 struct ccn_schedule_heap_item *heap;
00108 int n;
00109 int i;
00110 sched = *schedp;
00111 if (sched == NULL)
00112 return;
00113 *schedp = NULL;
00114 heap = sched->heap;
00115 if (heap != NULL) {
00116 n = sched->heap_n;
00117 sched->heap = NULL;
00118 for (i = 0; i < n; i++) {
00119 ev = heap[i].ev;
00120 (ev->action)(sched, sched->clienth, ev, CCN_SCHEDULE_CANCEL);
00121 free(ev);
00122 }
00123 free(heap);
00124 }
00125 free(sched);
00126 }
00127
00128 const struct ccn_gettime *
00129 ccn_schedule_get_gettime(struct ccn_schedule *schedp) {
00130 return(schedp->clock);
00131 }
00132
00133
00134
00135
00136
00137
00138 static void
00139 heap_insert(struct ccn_schedule_heap_item *heap, int micros,
00140 struct ccn_scheduled_event *ev, int h, int n)
00141 {
00142 int i;
00143 for (i = (n >> h); i < n; i = (n >> --h)) {
00144 if (micros <= heap[i-1].event_time) {
00145 intptr_t d = heap[i-1].event_time;
00146 struct ccn_scheduled_event *e = heap[i-1].ev;
00147 heap[i-1].ev = ev;
00148 heap[i-1].event_time = micros;
00149 micros = d;
00150 ev = e;
00151 }
00152 }
00153 heap[n-1].event_time = micros;
00154 heap[n-1].ev = ev;
00155 }
00156
00157
00158
00159
00160
00161 static void
00162 heap_sift(struct ccn_schedule_heap_item *heap, int n)
00163 {
00164 int i, j;
00165 int micros;
00166 if (n < 1)
00167 return;
00168 micros = heap[n-1].event_time;
00169 for (i = 1, j = 2; j < n; i = j, j = 2 * j) {
00170 if (j + 1 < n && heap[j-1].event_time > heap[j].event_time)
00171 j += 1;
00172 if (micros < heap[j-1].event_time)
00173 break;
00174 heap[i-1] = heap[j-1];
00175 }
00176 heap[i-1] = heap[n-1];
00177 heap[n-1].ev = NULL;
00178 heap[n-1].event_time = 0;
00179 }
00180
00181
00182
00183
00184
00185 static struct ccn_scheduled_event *
00186 reschedule_event(
00187 struct ccn_schedule *sched,
00188 int micros,
00189 struct ccn_scheduled_event *ev)
00190 {
00191 int lim;
00192 int n;
00193 int h;
00194 struct ccn_schedule_heap_item *heap;
00195 if (micros + sched->now < micros)
00196 update_epoch(sched);
00197 micros += sched->now;
00198 heap = sched->heap;
00199 n = sched->heap_n + 1;
00200 if (n > sched->heap_limit) {
00201 lim = sched->heap_limit + n;
00202 heap = realloc(sched->heap, lim * sizeof(heap[0]));
00203 if (heap == NULL) return(NULL);
00204 memset(&(heap[sched->heap_limit]), 0, (lim - n) * sizeof(heap[0]));
00205 sched->heap_limit = lim;
00206 sched->heap = heap;
00207 }
00208 sched->heap_n = n;
00209 h = sched->heap_height;
00210 while ((n >> h) > 1)
00211 sched->heap_height = ++h;
00212 while ((n >> h) < 1)
00213 sched->heap_height = --h;
00214 heap_insert(heap, micros, ev, h, n);
00215 return(ev);
00216 }
00217
00218
00219
00220
00221 struct ccn_scheduled_event *
00222 ccn_schedule_event(
00223 struct ccn_schedule *sched,
00224 int micros,
00225 ccn_scheduled_action action,
00226 void *evdata,
00227 intptr_t evint)
00228 {
00229 struct ccn_scheduled_event *ev;
00230 ev = calloc(1, sizeof(*ev));
00231 if (ev == NULL) return(NULL);
00232 ev->action = action;
00233 ev->evdata = evdata;
00234 ev->evint = evint;
00235 update_time(sched);
00236 return(reschedule_event(sched, micros, ev));
00237 }
00238
00239
00240 static int
00241 ccn_schedule_cancelled_event(struct ccn_schedule *sched, void *clienth,
00242 struct ccn_scheduled_event *ev, int flags)
00243 {
00244 return(0);
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 int
00254 ccn_schedule_cancel(struct ccn_schedule *sched, struct ccn_scheduled_event *ev)
00255 {
00256 int res;
00257 if (ev == NULL)
00258 return(-1);
00259 res = (ev->action)(sched, sched->clienth, ev, CCN_SCHEDULE_CANCEL);
00260 if (res > 0)
00261 abort();
00262 ev->action = &ccn_schedule_cancelled_event;
00263 ev->evdata = NULL;
00264 ev->evint = 0;
00265 return(0);
00266 }
00267
00268 static void
00269 ccn_schedule_run_next(struct ccn_schedule *sched)
00270 {
00271 struct ccn_scheduled_event *ev;
00272 int micros;
00273 int res;
00274 if (sched->heap_n == 0) return;
00275 ev = sched->heap[0].ev;
00276 sched->heap[0].ev = NULL;
00277 micros = sched->heap[0].event_time - sched->now;
00278 heap_sift(sched->heap, sched->heap_n--);
00279 res = (ev->action)(sched, sched->clienth, ev, 0);
00280 if (res <= 0) {
00281 free(ev);
00282 return;
00283 }
00284
00285
00286
00287
00288
00289 if (micros < -(int)(sched->clock->micros_per_base))
00290 micros = 0;
00291 reschedule_event(sched, micros + res, ev);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300 int
00301 ccn_schedule_run(struct ccn_schedule *sched)
00302 {
00303 update_time(sched);
00304 while (sched->heap_n > 0 && sched->heap[0].event_time <= sched->now) {
00305 sched->time_has_passed = 0;
00306 ccn_schedule_run_next(sched);
00307 if (sched->time_has_passed)
00308 update_time(sched);
00309 }
00310 if (sched->heap_n == 0)
00311 return(-1);
00312 return(sched->heap[0].event_time - sched->now);
00313 }
00314
00315 #ifdef TESTSCHEDULE
00316
00317 #include <stdio.h>
00318 #include <sys/time.h>
00319
00320 static void
00321 my_gettime(const struct ccn_gettime *self, struct ccn_timeval *result)
00322 {
00323 struct timeval now = {0};
00324 gettimeofday(&now, 0);
00325 result->s = now.tv_sec;
00326 result->micros = now.tv_usec;
00327 }
00328
00329 static struct ccn_gettime gt = {"getTOD", &my_gettime, 1000000, NULL};
00330
00331 static void
00332 testtick(struct ccn_schedule *sched)
00333 {
00334 sched->now = sched->heap[0].event_time + 1;
00335 printf("%ld: ", (long)sched->heap[0].event_time);
00336 ccn_schedule_run_next(sched);
00337 printf("\n");
00338 }
00339 static char dd[] = "ABDEFGHI";
00340 #define SARGS struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags
00341 static int A(SARGS) { if (flags & CCN_SCHEDULE_CANCEL) return(0);
00342 printf("A"); return 70000000; }
00343 static int B(SARGS) { printf("B"); return 0; }
00344 static int C(SARGS) { printf("C"); return 0; }
00345 static int D(SARGS) { if (flags & CCN_SCHEDULE_CANCEL) return(0);
00346 printf("D"); return 30000000; }
00347 static struct ccn_schedule_heap_item tst[7];
00348 int TESTSCHEDULE()
00349 {
00350 struct ccn_schedule *s = ccn_schedule_create(dd+5, >);
00351 int i;
00352 struct ccn_scheduled_event *victim = NULL;
00353
00354 s->time_has_passed = -1;
00355 ccn_schedule_event(s, 11111, A, dd+4, 11111);
00356 ccn_schedule_event(s, 1, A, dd, 1);
00357 ccn_schedule_event(s, 111, C, dd+2, 111);
00358 victim = ccn_schedule_event(s, 1111111, A, dd+6, 1111111);
00359 ccn_schedule_event(s, 11, B, dd+1, 11);
00360 testtick(s);
00361 ccn_schedule_event(s, 1111, D, dd+3, 1111);
00362 ccn_schedule_event(s, 111111, B, dd+5, 111111);
00363 for (i = 0; i < 100; i++) {
00364 if (i == 50) { ccn_schedule_cancel(s, victim); victim = NULL; }
00365 testtick(s);
00366 }
00367 ccn_schedule_destroy(&s);
00368 return(0);
00369 }
00370 #endif