diff --git a/auto/sources b/auto/sources index 14bb80d83..fa2b2df17 100644 --- a/auto/sources +++ b/auto/sources @@ -16,6 +16,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_file.h \ src/core/ngx_crc.h \ src/core/ngx_regex.h \ + src/core/ngx_rbtree.h \ src/core/ngx_times.h \ src/core/ngx_connection.h \ src/core/ngx_conf_file.h \ @@ -32,6 +33,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_inet.c \ src/core/ngx_file.c \ src/core/ngx_regex.c \ + src/core/ngx_rbtree.c \ src/core/ngx_times.c \ src/core/ngx_conf_file.c \ src/core/ngx_garbage_collector.c" diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 5b76d86c7..97819b6ff 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -30,6 +30,7 @@ typedef struct ngx_connection_s ngx_connection_t; #include #include #include +#include #include #include #include diff --git a/src/core/ngx_rbtree.c b/src/core/ngx_rbtree.c new file mode 100644 index 000000000..2bc4650f0 --- /dev/null +++ b/src/core/ngx_rbtree.c @@ -0,0 +1,296 @@ + +#include +#include + + +/* + * The code is based on the algorithm described in the "Introduction + * to Algorithms" by Cormen, Leiserson and Rivest. + */ + +#define ngx_rbt_red(node) ((uintptr_t) (node)->data |= 1) +#define ngx_rbt_black(node) ((uintptr_t) (node)->data &= ~1) +#define ngx_rbt_is_red(node) ((uintptr_t) (node)->data & 1) +#define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node)) +#define ngx_rbt_copy_color(n1, n2) \ + ((uintptr_t) (n1)->data |= (uintptr_t) (n2)->data & 1) + + +ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_t **root, ngx_rbtree_t *node); +ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_t **root, + ngx_rbtree_t *node); + +ngx_rbtree_t sentinel; + + +void ngx_rbtree_insert(ngx_rbtree_t **root, ngx_rbtree_t *node) +{ + ngx_rbtree_t *temp; + + /* a binary tree insert */ + + if (*root == &sentinel) { + node->parent = &sentinel; + node->left = &sentinel; + node->right = &sentinel; + ngx_rbt_black(node); + *root = node; + + return; + } + + temp = *root; + + for ( ;; ) { + if (node->key < temp->key) { + if (temp->left == &sentinel) { + temp->left = node; + break; + } + + temp = temp->left; + continue; + } + + if (temp->right == &sentinel) { + temp->right = node; + break; + } + + temp = temp->right; + continue; + } + + node->parent = temp; + node->left = &sentinel; + node->right = &sentinel; + + + /* re-balance tree */ + + ngx_rbt_red(node); + + while (node->parent && ngx_rbt_is_red(node->parent)) { + + if (node->parent == node->parent->parent->left) { + temp = node->parent->parent->right; + + if (ngx_rbt_is_red(temp)) { + ngx_rbt_black(node->parent); + ngx_rbt_black(temp); + ngx_rbt_red(node->parent->parent); + node = node->parent->parent; + + } else { + if (node == node->parent->right) { + node = node->parent; + ngx_rbtree_left_rotate(root, node); + } + + ngx_rbt_black(node->parent); + ngx_rbt_red(node->parent->parent); + ngx_rbtree_right_rotate(root, node->parent->parent); + } + + } else { + temp = node->parent->parent->left; + + if (ngx_rbt_is_red(temp)) { + ngx_rbt_black(node->parent); + ngx_rbt_black(temp); + ngx_rbt_red(node->parent->parent); + node = node->parent->parent; + + } else { + if (node == node->parent->left) { + node = node->parent; + ngx_rbtree_right_rotate(root, node); + } + + ngx_rbt_black(node->parent); + ngx_rbt_red(node->parent->parent); + ngx_rbtree_left_rotate(root, node->parent->parent); + } + } + + } + + ngx_rbt_black(*root); +} + + +void ngx_rbtree_delete(ngx_rbtree_t **root, ngx_rbtree_t *node) +{ + ngx_rbtree_t *subst, *temp, *w; + + /* a binary tree delete */ + + if (node->left == &sentinel || node->right == &sentinel) { + subst = node; + + } else { + + /* find a node successor */ + + if (node->right == &sentinel) { + temp = node; + subst = node->parent; + + while (subst != &sentinel && temp == subst->right) { + temp = subst; + subst = subst->parent; + } + + } else { + subst = ngx_rbtree_min(node->right); + } + } + + if (subst->left != &sentinel) { + temp = subst->left; + } else { + temp = subst->right; + } + + temp->parent = subst->parent; + + if (subst->parent == &sentinel) { + *root = temp; + + } else if (subst == subst->parent->left) { + subst->parent->left = temp; + + } else { + subst->parent->right = temp; + } + + if (subst != node) { + node->key = subst->key; + node->data = subst->data; + } + + if (ngx_rbt_is_red(subst)) { + return; + } + + /* a delete fixup */ + + while (temp->parent != &sentinel && ngx_rbt_is_black(temp)) { + if (temp == temp->parent->left) { + w = temp->parent->right; + + if (ngx_rbt_is_red(w)) { + ngx_rbt_black(w); + ngx_rbt_red(temp->parent); + ngx_rbtree_left_rotate(root, temp->parent); + w = temp->parent->right; + } + + if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) { + ngx_rbt_red(w); + temp = temp->parent; + + } else { + if (ngx_rbt_is_black(w->right)) { + ngx_rbt_black(w->left); + ngx_rbt_red(w); + ngx_rbtree_right_rotate(root, w); + w = temp->parent->right; + } + + ngx_rbt_copy_color(w, temp->parent); + ngx_rbt_black(temp->parent); + ngx_rbt_black(w->right); + ngx_rbtree_left_rotate(root, temp->parent); + temp = *root; + } + + } else { + w = temp->parent->left; + + if (ngx_rbt_is_red(w)) { + ngx_rbt_black(w); + ngx_rbt_red(temp->parent); + ngx_rbtree_right_rotate(root, temp->parent); + w = temp->parent->left; + } + + if (ngx_rbt_is_black(w->right) && ngx_rbt_is_black(w->left)) { + ngx_rbt_red(w); + temp = temp->parent; + + } else { + if (ngx_rbt_is_black(w->left)) { + ngx_rbt_black(w->right); + ngx_rbt_red(w); + ngx_rbtree_left_rotate(root, w); + w = temp->parent->left; + } + + ngx_rbt_copy_color(w, temp->parent); + ngx_rbt_black(temp->parent); + ngx_rbt_black(w->left); + ngx_rbtree_right_rotate(root, temp->parent); + temp = *root; + } + } + } + + ngx_rbt_black(temp); +} + + +ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_t **root, ngx_rbtree_t *node) +{ + ngx_rbtree_t *temp; + + temp = node->right; + node->right = temp->left; + + if (temp->left != &sentinel) { + temp->left->parent = node; + } + + temp->parent = node->parent; + + if (node->parent == &sentinel) { + *root = temp; + + } else if (node == node->parent->left) { + node->parent->left = temp; + + } else { + node->parent->right = temp; + } + + temp->left = node; + node->parent = temp; +} + + +ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_t **root, ngx_rbtree_t *node) +{ + ngx_rbtree_t *temp; + + temp = node->left; + node->left = temp->right; + + if (temp->right != &sentinel) { + temp->right->parent = node; + } + + temp->parent = node->parent; + + if (node->parent == &sentinel) { + *root = temp; + + } else if (node == node->parent->right) { + node->parent->right = temp; + + } else { + node->parent->left = temp; + } + + temp->right = node; + node->parent = temp; +} diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h new file mode 100644 index 000000000..de6fef904 --- /dev/null +++ b/src/core/ngx_rbtree.h @@ -0,0 +1,36 @@ +#ifndef _NGX_RBTREE_H_INCLUDED_ +#define _NGX_RBTREE_H_INCLUDED_ + + +#include +#include + + +typedef struct ngx_rbtree_s ngx_rbtree_t; + +struct ngx_rbtree_s { + ngx_int_t key; + ngx_rbtree_t *left; + ngx_rbtree_t *right; + ngx_rbtree_t *parent; + void *data; +}; + +extern ngx_rbtree_t sentinel; + + +void ngx_rbtree_insert(ngx_rbtree_t **root, ngx_rbtree_t *node); +void ngx_rbtree_delete(ngx_rbtree_t **root, ngx_rbtree_t *node); + + +ngx_inline static ngx_rbtree_t *ngx_rbtree_min(ngx_rbtree_t *root) +{ + while (root->left != &sentinel) { + root = root->left; + } + + return root; +} + + +#endif /* _NGX_RBTREE_H_INCLUDED_ */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index e1706baa2..12dc229c0 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -3,9 +3,11 @@ #include -time_t ngx_cached_time; +time_t ngx_cached_time; +ngx_epoch_msec_t ngx_elapsed_msec; +ngx_epoch_msec_t ngx_start_msec; -ngx_tm_t ngx_cached_gmtime; +ngx_tm_t ngx_cached_gmtime; static char cached_err_log_time[] = "1970/09/28 12:00:00"; ngx_str_t ngx_cached_err_log_time; @@ -37,6 +39,9 @@ void ngx_time_init() ngx_gettimeofday(&tv); ngx_cached_time = tv.tv_sec; + ngx_start_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; + ngx_elapsed_msec = 0; + ngx_time_update(); } diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h index b765dd8e0..6ff316d3f 100644 --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -14,10 +14,13 @@ void ngx_gmtime(time_t t, ngx_tm_t *tp); #define ngx_time() ngx_cached_time -extern time_t ngx_cached_time; -extern ngx_str_t ngx_cached_err_log_time; -extern ngx_str_t ngx_cached_http_time; -extern ngx_str_t ngx_cached_http_log_time; +extern time_t ngx_cached_time; +extern ngx_epoch_msec_t ngx_elapsed_msec; +extern ngx_epoch_msec_t ngx_start_msec; + +extern ngx_str_t ngx_cached_err_log_time; +extern ngx_str_t ngx_cached_http_time; +extern ngx_str_t ngx_cached_http_log_time; #endif /* _NGX_TIMES_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c index 9371ecee1..393c4d1ef 100644 --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -360,8 +360,10 @@ static int ngx_kqueue_process_events(ngx_log_t *log) ts.tv_nsec = (timer % 1000) * 1000000; tp = &ts; +#if 0 ngx_gettimeofday(&tv); delta = tv.tv_sec * 1000 + tv.tv_usec / 1000; +#endif } else { delta = 0; @@ -384,28 +386,31 @@ static int ngx_kqueue_process_events(ngx_log_t *log) ngx_gettimeofday(&tv); +#if 1 + delta = ngx_elapsed_msec; +#endif + ngx_elapsed_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000 - ngx_start_msec; + if (ngx_cached_time != tv.tv_sec) { ngx_cached_time = tv.tv_sec; ngx_time_update(); } if (timer) { - delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; - -#if (NGX_DEBUG_EVENT) - ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ (int) delta); -#endif + delta = ngx_elapsed_msec - delta; #if 0 + delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; + /* * The expired timers must be handled before a processing of the events * because the new timers can be added during a processing */ ngx_event_expire_timers((ngx_msec_t) delta); -#endif ngx_event_set_timer_delta((ngx_msec_t) delta); +#endif } else { if (events == 0) { @@ -413,11 +418,11 @@ static int ngx_kqueue_process_events(ngx_log_t *log) "kevent() returned no events without timeout"); return NGX_ERROR; } + } #if (NGX_DEBUG_EVENT) ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ (int) delta); #endif - } if (err) { ngx_log_error(NGX_LOG_ALERT, log, err, "kevent() failed"); @@ -510,9 +515,15 @@ static int ngx_kqueue_process_events(ngx_log_t *log) } } + if (timer && delta) { + ngx_event_expire_timers((ngx_msec_t) delta); + } + +#if 0 if (timer) { ngx_event_expire_timers((ngx_msec_t) delta); } +#endif return NGX_OK; } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 71bf45d16..8a0856d86 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -200,21 +200,10 @@ ngx_log_debug(cycle->log, "TYPE: %d" _ ecf->use); /* required by iocp in "c->write->active = 1" */ c->write = wev; -#if 0 - ngx_test_null(rev->log, ngx_palloc(cycle->pool, sizeof(ngx_log_t)), - NGX_ERROR); - - ngx_memcpy(rev->log, c->log, sizeof(ngx_log_t)); -#endif - rev->log = c->log; rev->data = c; rev->index = NGX_INVALID_INDEX; -#if 0 - rev->listening = 1; -#endif - rev->available = 0; #if (HAVE_DEFERRED_ACCEPT) diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 8e4ce4484..1454cdb7c 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -31,11 +31,14 @@ struct ngx_event_s { ngx_event_t *prev; ngx_event_t *next; + ngx_rbtree_t rbtree; + +#if 0 ngx_event_t *timer_prev; ngx_event_t *timer_next; ngx_msec_t timer_delta; - ngx_msec_t timer; +#endif ngx_log_t *log; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index ea63724e9..bba5aa55f 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -175,6 +175,9 @@ void ngx_event_accept(ngx_event_t *ev) rev->index = NGX_INVALID_INDEX; wev->index = NGX_INVALID_INDEX; + rev->rbtree.data = rev; + wev->rbtree.data = wev; + rev->data = c; wev->data = c; diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 8176ed1c4..296c748ee 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -4,6 +4,81 @@ #include +ngx_rbtree_t *ngx_event_timer_rbtree; + + +int ngx_event_timer_init(ngx_cycle_t *cycle) +{ + ngx_event_timer_rbtree = &sentinel; + sentinel.left = &sentinel; + sentinel.right = &sentinel; + sentinel.parent = &sentinel; + + return NGX_OK; +} + + +void ngx_event_timer_done(ngx_cycle_t *cycle) +{ +} + + +int ngx_event_find_timer(void) +{ + ngx_rbtree_t *node; + + node = ngx_rbtree_min(ngx_event_timer_rbtree); + + if (node == &sentinel) { + return 0; + + } else { + return node->key * NGX_TIMER_RESOLUTION - ngx_elapsed_msec; + } +} + + +void ngx_event_expire_timers(ngx_msec_t timer) +{ + ngx_event_t *ev; + ngx_rbtree_t *node; + + for ( ;; ) { + node = ngx_rbtree_min(ngx_event_timer_rbtree); + + if (node == &sentinel) { + break; + } + + if ((ngx_msec_t) node->key <= + (ngx_elapsed_msec + timer) / NGX_TIMER_RESOLUTION) + { + ev = (ngx_event_t *) + ((char *) node - offsetof(ngx_event_t, rbtree)); + + ngx_del_timer(ev); + + if (ev->delayed) { + ev->delayed = 0; + if (ev->ready == 0) { + continue; + } + + } else { + ev->timedout = 1; + } + + ev->event_handler(ev); + continue; + } + + break; + } +} + + +#if 0 + /* TODO: in multithreaded enviroment all timer operations must be protected by the single mutex */ @@ -275,3 +350,6 @@ void ngx_event_expire_timers(ngx_msec_t timer) } #endif } + + +#endif diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h index 911667d14..ea8105ee3 100644 --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -7,14 +7,58 @@ #include +/* + * 1 msec - 49 days + * 10 msec - 1 years 4 months + * 50 msec - 6 years 10 months + * 100 msec - 13 years 8 months + */ + +#define NGX_TIMER_RESOLUTION 50 + + +int ngx_event_timer_init(ngx_cycle_t *cycle); +void ngx_event_timer_done(ngx_cycle_t *cycle); +int ngx_event_find_timer(void); +void ngx_event_expire_timers(ngx_msec_t timer); + +#if 0 int ngx_event_timer_init(ngx_cycle_t *cycle); void ngx_event_timer_done(ngx_cycle_t *cycle); void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer); int ngx_event_find_timer(void); void ngx_event_set_timer_delta(ngx_msec_t timer); void ngx_event_expire_timers(ngx_msec_t timer); +#endif +extern ngx_rbtree_t *ngx_event_timer_rbtree; + + +ngx_inline static void ngx_event_del_timer(ngx_event_t *ev) +{ + ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->rbtree); + + ev->timer_set = 0; +} + + +ngx_inline static void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer) +{ + if (ev->timer_set) { + ngx_del_timer(ev); + } + + ev->rbtree.key = (ngx_int_t) + (ngx_elapsed_msec + timer) / NGX_TIMER_RESOLUTION; + + ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->rbtree); + + ev->timer_set = 1; +} + + +#if 0 ngx_inline static void ngx_event_del_timer(ngx_event_t *ev) { @@ -45,5 +89,7 @@ ngx_inline static void ngx_event_del_timer(ngx_event_t *ev) ev->timer_set = 0; } +#endif + #endif /* _NGX_EVENT_TIMER_H_INCLUDED_ */ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 3046ca882..547e028e5 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -514,13 +514,7 @@ ngx_log_debug(r->connection->log, "trans: %s: %d" _ } if (clcf->handler) { - /* - * if the location already has content handler then skip - * the translation phase - */ - r->content_handler = clcf->handler; - r->phase++; } return NGX_OK;