# HG changeset patch # User Igor Sysoev # Date 1078262077 0 # Node ID a2d1ccc96111ea05963822899b15dff65aa8a2f1 # Parent b836469c37c31e88f98f766a9514dc8dd1dde76d nginx-0.0.2-2004-03-03-00:14:37 import diff --git a/auto/cc b/auto/cc --- a/auto/cc +++ b/auto/cc @@ -6,9 +6,9 @@ case $CC in # optimization #CFLAGS="$CFLAGS -O2 -fomit-frame-pointer" # optimize for Pentium Pro, Pentium II and Pentium III - CFLAGS="$CFLAGS -mcpu=pentiumpro" + #CFLAGS="$CFLAGS -march=pentiumpro" # optimize for Pentium 4, gcc 3.x - #CFLAGS="$CFLAGS -mcpu=pentium4" + #CFLAGS="$CFLAGS -march=pentium4" # warnings CFLAGS="$CFLAGS -O -W" @@ -44,9 +44,9 @@ case $CC in # optimization CFLAGS="$CFLAGS -O" # optimize for Pentium Pro, Pentium II and Pentium III - CFLAGS="$CFLAGS -mcpu=pentiumpro" + CFLAGS="$CFLAGS -mcpu=pentiumpro -march=pentiumpro" # optimize for Pentium 4, default - #CFLAGS="$CFLAGS -mcpu=pentium4" + #CFLAGS="$CFLAGS -march=pentium4" # warnings CFLAGS="$CFLAGS -w1" diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -52,12 +52,13 @@ EVENT_INCS="-I src/event -I src/event/mo EVENT_DEPS="src/event/ngx_event.h \ src/event/ngx_event_timer.h \ + src/event/ngx_event_busy_lock.h \ src/event/ngx_event_connect.h \ src/event/ngx_event_pipe.h" EVENT_SRCS="src/event/ngx_event.c \ src/event/ngx_event_timer.c \ - src/event/ngx_event_mutex.c \ + src/event/ngx_event_busy_lock.c \ src/event/ngx_event_accept.c \ src/event/ngx_event_connect.c \ src/event/ngx_event_pipe.c" diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -48,14 +48,10 @@ typedef struct ngx_connection_s ngx_con #define NGX_OK 0 #define NGX_ERROR -1 #define NGX_AGAIN -2 -#define NGX_DONE -3 -#define NGX_DECLINED -4 -#define NGX_ABORT -5 - -/* #define NGX_BUSY -3 -#define NGX_ALERT -5 -*/ +#define NGX_DONE -4 +#define NGX_DECLINED -5 +#define NGX_ABORT -6 #define LF 10 diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -45,7 +45,10 @@ ngx_event_actions_t ngx_event_actions static int ngx_event_max_module; -volatile ngx_event_t *ngx_posted_events; +ngx_thread_volatile ngx_event_t *ngx_posted_events; +#if (NGX_THREADS) +ngx_mutex_t *ngx_posted_events_mutex; +#endif static ngx_str_t events_name = ngx_string("events"); @@ -134,6 +137,12 @@ static int ngx_event_init(ngx_cycle_t *c #endif +#if (NGX_THREADS) + if (!(ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0))) { + return NGX_ERROR; + } +#endif + if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -6,6 +6,9 @@ #include +typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); + + #define NGX_INVALID_INDEX 0xd0d0d0d0 @@ -30,8 +33,9 @@ typedef struct { struct ngx_event_s { void *data; + /* TODO rename to handler */ - void (*event_handler)(ngx_event_t *ev); + ngx_event_handler_pt event_handler; u_int index; @@ -381,7 +385,10 @@ typedef struct { -extern volatile ngx_event_t *ngx_posted_events; +extern ngx_thread_volatile ngx_event_t *ngx_posted_events; +#if (NGX_THREADS) +extern ngx_mutex_t *ngx_posted_events_mutex; +#endif extern int ngx_event_flags; extern ngx_module_t ngx_events_module; @@ -406,6 +413,7 @@ int ngx_event_post_acceptex(ngx_listenin #include +#include #if (WIN32) #include diff --git a/src/event/ngx_event_busy_lock.c b/src/event/ngx_event_busy_lock.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_busy_lock.c @@ -0,0 +1,345 @@ + +#include +#include +#include + +/* + * TODO: eliminate mutex and use atomic_xchg(): + * ev->next = ev; ngx_atomic_xchg(ngx_posted_events, ev->next); + * in ngx_event_busy_unlock() and ngx_event_busy_lock_handler() + */ + + +static int ngx_event_busy_lock_look_cachable(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx); +static void ngx_event_busy_lock_handler(ngx_event_t *ev); +static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev); + + +/* + * NGX_OK: the busy lock is held + * NGX_BUSY: there are many the busy locks or many the waiting locks + * NGX_AGAIN: the all busy locks are held but we will wait the specified time + * NGX_ERROR: there was error while the mutex locking + */ + +ngx_int_t ngx_event_busy_lock(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx) +{ + ngx_int_t rc; + +#if (NGX_THREADS) + if (ngx_mutex_lock(bl->mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0, + "event busy lock: b:%d mb:%d", + bl->busy, bl->max_busy); + + if (bl->busy < bl->max_busy) { + bl->busy++; + rc = NGX_OK; + + } else if (ctx->timer && bl->waiting < bl->max_waiting) { + bl->waiting++; + ngx_add_timer(ctx->event, ctx->timer); + ctx->event->event_handler = ngx_event_busy_lock_handler; + + if (bl->events == NULL) { + bl->events = ctx; + } else { + bl->last->next = ctx; + } + bl->last = ctx; + + rc = NGX_AGAIN; + + } else { + rc = NGX_BUSY; + } + +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + + return rc; +} + + +ngx_int_t ngx_event_busy_lock_cachable(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx) +{ + ngx_int_t rc; + +#if (NGX_THREADS) + if (ngx_mutex_lock(bl->mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + rc = ngx_event_busy_lock_look_cachable(bl, ctx); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0, + "event busy lock: %d w:%d mw:%d", + rc, bl->waiting, bl->max_waiting); + + /* + * NGX_OK: no the same request, there is free slot and we locked it + * NGX_BUSY: no the same request and there is no free slot + * NGX_AGAIN: the same request is processing + */ + + if (rc == NGX_AGAIN) { + + if (ctx->timer && bl->waiting < bl->max_waiting) { + bl->waiting++; + ngx_add_timer(ctx->event, ctx->timer); + ctx->event->event_handler = ngx_event_busy_lock_handler; + + if (bl->events == NULL) { + bl->events = ctx; + } else { + bl->last->next = ctx; + } + bl->last = ctx; + + } else { + rc = NGX_BUSY; + } + } + +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + + return rc; +} + + +ngx_int_t ngx_event_busy_unlock(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx) +{ + ngx_event_t *ev; + ngx_event_busy_lock_ctx_t *wakeup; + +#if (NGX_THREADS) + if (ngx_mutex_lock(bl->mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + if (bl->events) { + wakeup = bl->events; + bl->events = bl->events->next; + + } else { + wakeup = NULL; + bl->busy--; + } + + /* + * MP: + * nocachable (bl->md5 == NULL): ngx_shared_mutex_unlock(mutex, !wakeup) + * cachable (bl->md5): ??? + */ + + if (wakeup == NULL) { +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + return NGX_OK; + } + + if (ctx->md5) { + for (wakeup = bl->events; wakeup; wakeup = wakeup->next) { + if (wakeup->md5 == NULL) { + continue; + } + + if (ngx_memcmp(ctx->md5, wakeup->md5, 16) != 0) { + continue; + } + + wakeup->handler = ngx_event_busy_lock_posted_handler; + wakeup->cache_updated = 1; + + ev = wakeup->event; + +#if (NGX_THREADS) + if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + ev->next = (ngx_event_t *) ngx_posted_events; + ngx_posted_events = ev; + +#if (NGX_THREADS) + ngx_mutex_unlock(ngx_posted_events_mutex); +#endif + } + +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + + } else { + bl->waiting--; + +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + + wakeup->handler = ngx_event_busy_lock_posted_handler; + wakeup->locked = 1; + + ev = wakeup->event; + + if (ev->timer_set) { + ngx_del_timer(ev); + } + +#if (NGX_THREADS) + if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + ev->next = (ngx_event_t *) ngx_posted_events; + ngx_posted_events = ev; + +#if (NGX_THREADS) + ngx_mutex_unlock(ngx_posted_events_mutex); +#endif + } + + return NGX_OK; +} + + +ngx_int_t ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx) +{ + ngx_event_busy_lock_ctx_t *c, *p; + +#if (NGX_THREADS) + if (ngx_mutex_lock(bl->mutex) == NGX_ERROR) { + return NGX_ERROR; + } +#endif + + bl->waiting--; + + if (ctx == bl->events) { + bl->events = ctx->next; + + } else { + p = bl->events; + for (c = bl->events->next; c; c = c->next) { + if (c == ctx) { + p->next = ctx->next; + break; + } + p = c; + } + } + +#if (NGX_THREADS) + ngx_mutex_unlock(bl->mutex); +#endif + + return NGX_OK; +} + + +static int ngx_event_busy_lock_look_cachable(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx) +{ + ngx_int_t free; + ngx_uint_t i, bit, cachable, mask; + + bit = 0; + cachable = 0; + free = -1; + +#if (NGX_SUPPRESS_WARN) + mask = 0; +#endif + + for (i = 0; i < bl->max_busy; i++) { + + if ((bit & 7) == 0) { + mask = bl->md5_mask[i / 8]; + } + + if (mask & 1) { + if (ngx_memcmp(&bl->md5[i * 16], ctx->md5, 16) == 0) { + return NGX_AGAIN; + } + cachable++; + + } else if (free == -1) { + free = i; + } + + if (cachable == bl->cachable) { + if (free == -1 && cachable < bl->max_busy) { + free = i + 1; + } + + break; + } + + mask >>= 1; + bit++; + } + + if (free == -1) { + return NGX_BUSY; + } + +#if 0 + if (bl->busy == bl->max_busy) { + return NGX_BUSY; + } +#endif + + ngx_memcpy(&bl->md5[free * 16], ctx->md5, 16); + bl->md5_mask[free / 8] |= 1 << (free & 7); + ctx->slot = free; + + bl->cachable++; + bl->busy++; + + return NGX_OK; +} + + +static void ngx_event_busy_lock_handler(ngx_event_t *ev) +{ + ev->event_handler = ngx_event_busy_lock_posted_handler; + +#if (NGX_THREADS) + if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { + return; + } +#endif + + ev->next = (ngx_event_t *) ngx_posted_events; + ngx_posted_events = ev; + +#if (NGX_THREADS) + ngx_mutex_unlock(ngx_posted_events_mutex); +#endif +} + + +static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev) +{ + ngx_event_busy_lock_ctx_t *ctx; + + ctx = ev->data; + ctx->handler(ev); +} diff --git a/src/event/ngx_event_busy_lock.h b/src/event/ngx_event_busy_lock.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_busy_lock.h @@ -0,0 +1,57 @@ +#ifndef _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ +#define _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ + + +#include +#include +#include + +typedef struct ngx_event_busy_lock_ctx_s ngx_event_busy_lock_ctx_t; + +struct ngx_event_busy_lock_ctx_s { + ngx_event_t *event; + ngx_event_handler_pt handler; + void *data; + ngx_msec_t timer; + + unsigned locked:1; + unsigned cache_updated:1; + + char *md5; + ngx_int_t slot; + + ngx_event_busy_lock_ctx_t *next; +}; + + +typedef struct { + u_char *md5_mask; + char *md5; + ngx_uint_t cachable; + + ngx_uint_t busy; + ngx_uint_t max_busy; + + ngx_uint_t waiting; + ngx_uint_t max_waiting; + + ngx_event_busy_lock_ctx_t *events; + ngx_event_busy_lock_ctx_t *last; + +#if (NGX_THREADS) + ngx_mutex_t *mutex; +#endif +} ngx_event_busy_lock_t; + + +ngx_int_t ngx_event_busy_lock(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx); +ngx_int_t ngx_event_busy_lock_cachable(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx); +ngx_int_t ngx_event_busy_unlock(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx); +ngx_int_t ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl, + ngx_event_busy_lock_ctx_t *ctx); + + +#endif /* _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ */ diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c --- a/src/http/ngx_http_busy_lock.c +++ b/src/http/ngx_http_busy_lock.c @@ -288,7 +288,7 @@ char *ngx_http_set_busy_lock_slot(ngx_co if (bl->timeout == 0 && bl->max_waiting) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "busy lock waiting is useless with zero timeout"); + "busy lock waiting is useless with zero timeout, ignoring"); } return NGX_CONF_OK;