diff options
| author | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-09 18:26:23 +0100 |
|---|---|---|
| committer | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-11 15:26:46 +0100 |
| commit | 59905999ce145a81e0003766d468945c2444a90e (patch) | |
| tree | b4b2f566942c2a4b90ab7a6d6111c73c49e4afc5 /evloop/timeheap.c | |
| parent | 4457c1268a923d2a662ab23ca1b8d7920811ae51 (diff) | |
| download | btpd-59905999ce145a81e0003766d468945c2444a90e.tar.gz btpd-59905999ce145a81e0003766d468945c2444a90e.zip | |
Add evloop, btpd's new event loop. This will replace libevent.
Diffstat (limited to 'evloop/timeheap.c')
| -rw-r--r-- | evloop/timeheap.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/evloop/timeheap.c b/evloop/timeheap.c new file mode 100644 index 0000000..470feaf --- /dev/null +++ b/evloop/timeheap.c @@ -0,0 +1,152 @@ +#include <sys/time.h> +#include <assert.h> +#include <stdlib.h> + +#include "timeheap.h" + +struct th_entry { + struct timespec t; + struct th_handle *h; +}; + +static struct th_entry *heap; +static int heap_cap; +static int heap_use; + +static int +cmptime_lt(struct timespec a, struct timespec b) +{ + if (a.tv_sec == b.tv_sec) + return a.tv_nsec < b.tv_nsec; + else + return a.tv_sec < b.tv_sec; +} + +static int +cmpentry_lt(int a, int b) +{ + return cmptime_lt(heap[a].t, heap[b].t); +} + +static void +swap(int i, int j) +{ + struct th_entry tmp = heap[i]; + heap[i] = heap[j]; + heap[i].h->i = i; + heap[j] = tmp; + heap[j].h->i = j; +} + +static void +bubble_up(int i) +{ + while (i != 0) { + int p = (i-1)/2; + if (cmpentry_lt(i, p)) { + swap(i, p); + i = p; + } else + return; + } +} + +static void +bubble_down(int i) +{ + int li, ri, ci; +loop: + li = 2*i+1; + ri = 2*i+2; + if (ri < heap_use) + ci = cmpentry_lt(li, ri) ? li : ri; + else if (li < heap_use) + ci = li; + else + return; + if (cmpentry_lt(ci, i)) { + swap(i, ci); + i = ci; + goto loop; + } +} + +int +timeheap_init(void) +{ + heap_cap = 10; + heap_use = 0; + if ((heap = malloc(sizeof(struct th_entry) * heap_cap)) == NULL) + return -1; + else + return 0; +} + +int +timeheap_size(void) +{ + return heap_use; +} + +int +timeheap_insert(struct th_handle *h, struct timespec *t) +{ + if (heap_use == heap_cap) { + int ncap = heap_cap * 2; + struct th_entry *nheap = realloc(heap, ncap * sizeof(struct th_entry)); + if (nheap == NULL) + return -1; + heap_cap = ncap; + heap = nheap; + } + heap[heap_use].t = *t; + heap[heap_use].h = h; + h->i = heap_use; + heap_use++; + bubble_up(h->i); + return 0; +} + +void +timeheap_remove(struct th_handle *h) +{ + assert(h->i >= 0 && h->i < heap_use); + heap_use--; + if (heap_use > 0) { + int i = h->i; + int earlier = cmpentry_lt(heap_use, i); + heap[i] = heap[heap_use]; + heap[i].h->i = i; + if (earlier) + bubble_up(i); + else + bubble_down(i); + } +} + +void +timeheap_change(struct th_handle *h, struct timespec *t) +{ + assert(h->i >= 0 && h->i < heap_use); + int earlier = cmptime_lt(*t, heap[h->i].t); + heap[h->i].t = *t; + if (earlier) + bubble_up(h->i); + else + bubble_down(h->i); +} + +struct timespec +timeheap_top(void) +{ + return heap[0].t; +} + +void * +timeheap_remove_top(void) +{ + void *ret = heap[0].h->data; + struct th_handle h = { 0, NULL }; + timeheap_remove(&h); + return ret; +} |