diff --git a/include/lighttpd/base.h b/include/lighttpd/base.h index 8e72206..981c8c4 100644 --- a/include/lighttpd/base.h +++ b/include/lighttpd/base.h @@ -21,12 +21,13 @@ } while (0) #include -#include #include #include #include +#include + #include #include #include diff --git a/include/lighttpd/utils.h b/include/lighttpd/utils.h index ae4d6b3..d8b7930 100644 --- a/include/lighttpd/utils.h +++ b/include/lighttpd/utils.h @@ -13,23 +13,6 @@ typedef enum { } counter_type; -struct waitqueue_elem { - gboolean queued; - ev_tstamp ts; - waitqueue_elem *prev; - waitqueue_elem *next; - gpointer data; -}; - -struct waitqueue { - waitqueue_elem *head; - waitqueue_elem *tail; - ev_timer timer; - struct ev_loop *loop; - gdouble delay; -}; - - LI_API void fatal(const gchar* msg); @@ -70,24 +53,4 @@ LI_API GString *mimetype_get(vrequest *vr, GString *filename); /* converts a sock_addr to a human readable string. ipv4 and ipv6 supported. if dest is NULL, a new string will be allocated */ LI_API GString *sockaddr_to_string(sock_addr *saddr, GString *dest); - -/* - * waitqueues are queues used to implement delays for certain tasks in a lightweight, non-blocking way - * they are used for io timeouts or throttling for example - * waitqueue_push, waitqueue_pop and waitqueue_remove have O(1) complexity - */ - -/* initializes a waitqueue by creating and starting the ev_timer. precision is sub-seconds */ -LI_API void waitqueue_init(waitqueue *queue, struct ev_loop *loop, waitqueue_cb callback, gdouble delay, gpointer data); -/* stops the waitqueue. to restart it, simply call waitqueue_update */ -LI_API void waitqueue_stop(waitqueue *queue); -/* updates the timeout of the waitqueue, you should allways call this at the end of your callback */ -LI_API void waitqueue_update(waitqueue *queue); -/* moves the element to the end of the queue if already queued, appends it to the end otherwise */ -LI_API void waitqueue_push(waitqueue *queue, waitqueue_elem *elem); -/* pops the first ready! element from the queue or NULL if none ready yet. this should be called in your callback */ -LI_API waitqueue_elem *waitqueue_pop(waitqueue *queue); -/* removes an element from the queue */ -LI_API void waitqueue_remove(waitqueue *queue, waitqueue_elem *elem); - #endif diff --git a/include/lighttpd/waitqueue.h b/include/lighttpd/waitqueue.h new file mode 100644 index 0000000..d408828 --- /dev/null +++ b/include/lighttpd/waitqueue.h @@ -0,0 +1,43 @@ +#ifndef _LIGHTTPD_WAITQUEUE_H_ +#define _LIGHTTPD_WAITQUEUE_H_ + +#ifndef _LIGHTTPD_BASE_H_ +#error Please include instead of this file +#endif + +struct waitqueue_elem { + gboolean queued; + ev_tstamp ts; + waitqueue_elem *prev; + waitqueue_elem *next; + gpointer data; +}; + +struct waitqueue { + waitqueue_elem *head; + waitqueue_elem *tail; + ev_timer timer; + struct ev_loop *loop; + gdouble delay; +}; + +/* + * waitqueues are queues used to implement delays for certain tasks in a lightweight, non-blocking way + * they are used for io timeouts or throttling for example + * waitqueue_push, waitqueue_pop and waitqueue_remove have O(1) complexity + */ + +/* initializes a waitqueue by creating and starting the ev_timer. precision is sub-seconds */ +LI_API void waitqueue_init(waitqueue *queue, struct ev_loop *loop, waitqueue_cb callback, gdouble delay, gpointer data); +/* stops the waitqueue. to restart it, simply call waitqueue_update */ +LI_API void waitqueue_stop(waitqueue *queue); +/* updates the timeout of the waitqueue, you should allways call this at the end of your callback */ +LI_API void waitqueue_update(waitqueue *queue); +/* moves the element to the end of the queue if already queued, appends it to the end otherwise */ +LI_API void waitqueue_push(waitqueue *queue, waitqueue_elem *elem); +/* pops the first ready! element from the queue or NULL if none ready yet. this should be called in your callback */ +LI_API waitqueue_elem *waitqueue_pop(waitqueue *queue); +/* removes an element from the queue */ +LI_API void waitqueue_remove(waitqueue *queue, waitqueue_elem *elem); + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf5d472..459ef5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -291,6 +291,7 @@ SET(COMMON_SRC utils.c value.c virtualrequest.c + waitqueue.c worker.c plugin_core.c diff --git a/src/utils.c b/src/utils.c index 2f979c7..ae90440 100644 --- a/src/utils.c +++ b/src/utils.c @@ -510,105 +510,3 @@ GString *sockaddr_to_string(sock_addr *saddr, GString *dest) { return dest; } - - -void waitqueue_init(waitqueue *queue, struct ev_loop *loop, waitqueue_cb callback, gdouble delay, gpointer data) { - ev_timer_init(&queue->timer, callback, delay, delay); - ev_timer_start(loop, &queue->timer); - - queue->timer.data = data; - queue->head = queue->tail = NULL; - queue->loop = loop; - queue->delay = delay; -} - -void waitqueue_stop(waitqueue *queue) { - ev_timer_stop(queue->loop, &queue->timer); -} - -void waitqueue_update(waitqueue *queue) { - ev_tstamp repeat; - - if (queue->head) { - repeat = queue->head->ts + queue->delay - ev_now(queue->loop); - } else - repeat = queue->delay; - - if (queue->timer.repeat != repeat) - { - queue->timer.repeat = repeat; - ev_timer_again(queue->loop, &queue->timer); - } -} - -void waitqueue_push(waitqueue *queue, waitqueue_elem *elem) { - elem->ts = ev_now(queue->loop); - - if (!elem->queued) { - elem->queued = TRUE; - /* not in the queue yet, insert at the end */ - if (!queue->head) { - /* queue is empty */ - queue->head = elem; - queue->tail = elem; - elem->prev = NULL; - elem->next = NULL; - } else { - /* queue not empty */ - elem->prev = queue->tail; - elem->next = NULL; - queue->tail->next = elem; - queue->tail = elem; - } - } else { - /* already queued, move to end */ - if (elem == queue->tail) - return; - - if (elem == queue->head) { - queue->head = elem->next; - if (elem->next) - elem->next->prev = NULL; - } - - elem->prev = queue->tail; - elem->next = NULL; - queue->tail->next = elem; - queue->tail = elem; - } -} - -waitqueue_elem *waitqueue_pop(waitqueue *queue) { - waitqueue_elem *elem = queue->head; - ev_tstamp now = ev_now(queue->loop); - - if (!elem || (elem->ts + queue->delay) >= now) { - return NULL; - } - - if (elem != queue->tail) - elem->next->prev = NULL; - - queue->head = elem->next; - - elem->queued = FALSE; - - return elem; -} - -void waitqueue_remove(waitqueue *queue, waitqueue_elem *elem) { - if (!elem->queued) - return; - - if (elem == queue->head) - queue->head = elem->next; - else - elem->prev->next = elem->next; - - if (elem == queue->tail) - queue->tail = elem->prev; - else - elem->next->prev = elem->prev; - - elem->queued = FALSE; -} diff --git a/src/waitqueue.c b/src/waitqueue.c new file mode 100644 index 0000000..eba0aa0 --- /dev/null +++ b/src/waitqueue.c @@ -0,0 +1,103 @@ + +#include + +void waitqueue_init(waitqueue *queue, struct ev_loop *loop, waitqueue_cb callback, gdouble delay, gpointer data) { + ev_timer_init(&queue->timer, callback, delay, delay); + ev_timer_start(loop, &queue->timer); + + queue->timer.data = data; + queue->head = queue->tail = NULL; + queue->loop = loop; + queue->delay = delay; +} + +void waitqueue_stop(waitqueue *queue) { + ev_timer_stop(queue->loop, &queue->timer); +} + +void waitqueue_update(waitqueue *queue) { + ev_tstamp repeat; + + if (queue->head) { + repeat = queue->head->ts + queue->delay - ev_now(queue->loop); + } else + repeat = queue->delay; + + if (queue->timer.repeat != repeat) + { + queue->timer.repeat = repeat; + ev_timer_again(queue->loop, &queue->timer); + } +} + +void waitqueue_push(waitqueue *queue, waitqueue_elem *elem) { + elem->ts = ev_now(queue->loop); + + if (!elem->queued) { + elem->queued = TRUE; + /* not in the queue yet, insert at the end */ + if (!queue->head) { + /* queue is empty */ + queue->head = elem; + queue->tail = elem; + elem->prev = NULL; + elem->next = NULL; + } else { + /* queue not empty */ + elem->prev = queue->tail; + elem->next = NULL; + queue->tail->next = elem; + queue->tail = elem; + } + } else { + /* already queued, move to end */ + if (elem == queue->tail) + return; + + if (elem == queue->head) { + queue->head = elem->next; + if (elem->next) + elem->next->prev = NULL; + } + + elem->prev = queue->tail; + elem->next = NULL; + queue->tail->next = elem; + queue->tail = elem; + } +} + +waitqueue_elem *waitqueue_pop(waitqueue *queue) { + waitqueue_elem *elem = queue->head; + ev_tstamp now = ev_now(queue->loop); + + if (!elem || (elem->ts + queue->delay) >= now) { + return NULL; + } + + if (elem != queue->tail) + elem->next->prev = NULL; + + queue->head = elem->next; + + elem->queued = FALSE; + + return elem; +} + +void waitqueue_remove(waitqueue *queue, waitqueue_elem *elem) { + if (!elem->queued) + return; + + if (elem == queue->head) + queue->head = elem->next; + else + elem->prev->next = elem->next; + + if (elem == queue->tail) + queue->tail = elem->prev; + else + elem->next->prev = elem->prev; + + elem->queued = FALSE; +} diff --git a/src/wscript b/src/wscript index 672195a..0696820 100644 --- a/src/wscript +++ b/src/wscript @@ -36,6 +36,7 @@ common_source=''' utils.c value.c virtualrequest.c + waitqueue.c worker.c plugin_core.c