Mercurial > hg > nginx
diff src/core/ngx_shmtx.c @ 3909:0daede16d68b
use POSIX semaphores in shmtx instead of sched_yield()
number of spinlock spins are increased twice
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 10 May 2011 11:39:13 +0000 |
parents | 01884449985f |
children | 3f6040cd731e 4919fb357a5d |
line wrap: on
line diff
--- a/src/core/ngx_shmtx.c +++ b/src/core/ngx_shmtx.c @@ -16,9 +16,166 @@ ngx_shmtx_create(ngx_shmtx_t *mtx, void { mtx->lock = addr; + if (mtx->spin == (ngx_uint_t) -1) { + return NGX_OK; + } + + mtx->spin = 2048; + +#if (NGX_HAVE_POSIX_SEM) + + if (sem_init(&mtx->sem, 1, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, + "sem_init() failed"); + } else { + mtx->semaphore = 1; + } + +#endif + return NGX_OK; } + +void +ngx_shmtx_destory(ngx_shmtx_t *mtx) +{ +#if (NGX_HAVE_POSIX_SEM) + + if (mtx->semaphore) { + if (sem_destroy(&mtx->sem) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, + "sem_destroy() failed"); + } + } + +#endif +} + + +ngx_uint_t +ngx_shmtx_trylock(ngx_shmtx_t *mtx) +{ + ngx_atomic_uint_t val; + + val = *mtx->lock; + + return ((val & 0x80000000) == 0 + && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000)); +} + + +void +ngx_shmtx_lock(ngx_shmtx_t *mtx) +{ + ngx_uint_t i, n; + ngx_atomic_uint_t val; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock"); + + for ( ;; ) { + + val = *mtx->lock; + + if ((val & 0x80000000) == 0 + && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000)) + { + return; + } + + if (ngx_ncpu > 1) { + + for (n = 1; n < mtx->spin; n <<= 1) { + + for (i = 0; i < n; i++) { + ngx_cpu_pause(); + } + + val = *mtx->lock; + + if ((val & 0x80000000) == 0 + && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000)) + { + return; + } + } + } + +#if (NGX_HAVE_POSIX_SEM) + + if (mtx->semaphore) { + val = *mtx->lock; + + if ((val & 0x80000000) + && ngx_atomic_cmp_set(mtx->lock, val, val + 1)) + { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "shmtx wait %XA", val); + + while (sem_wait(&mtx->sem) == -1) { + ngx_err_t err; + + err = ngx_errno; + + if (err != NGX_EINTR) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, + "sem_wait() failed while waiting on shmtx"); + break; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "shmtx awoke"); + } + + continue; + } + +#endif + + ngx_sched_yield(); + } +} + + +void +ngx_shmtx_unlock(ngx_shmtx_t *mtx) +{ + ngx_atomic_uint_t val, old, wait; + + if (mtx->spin != (ngx_uint_t) -1) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock"); + } + + for ( ;; ) { + + old = *mtx->lock; + wait = old & 0x7fffffff; + val = wait ? wait - 1 : 0; + + if (ngx_atomic_cmp_set(mtx->lock, old, val)) { + break; + } + } + +#if (NGX_HAVE_POSIX_SEM) + + if (wait == 0 || !mtx->semaphore) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "shmtx wake %XA", old); + + if (sem_post(&mtx->sem) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, + "sem_post() failed while wake shmtx"); + } + +#endif +} + + #else @@ -65,4 +222,62 @@ ngx_shmtx_destory(ngx_shmtx_t *mtx) } +ngx_uint_t +ngx_shmtx_trylock(ngx_shmtx_t *mtx) +{ + ngx_err_t err; + + err = ngx_trylock_fd(mtx->fd); + + if (err == 0) { + return 1; + } + + if (err == NGX_EAGAIN) { + return 0; + } + +#if __osf__ /* Tru64 UNIX */ + + if (err == NGX_EACCESS) { + return 0; + } + #endif + + ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name); + + return 0; +} + + +void +ngx_shmtx_lock(ngx_shmtx_t *mtx) +{ + ngx_err_t err; + + err = ngx_lock_fd(mtx->fd); + + if (err == 0) { + return; + } + + ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name); +} + + +void +ngx_shmtx_unlock(ngx_shmtx_t *mtx) +{ + ngx_err_t err; + + err = ngx_unlock_fd(mtx->fd); + + if (err == 0) { + return; + } + + ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name); +} + +#endif