| |
| /* |
| * Copyright (C) Ruslan Ermilov |
| * Copyright (C) Nginx, Inc. |
| */ |
| |
| |
| #include <ngx_config.h> |
| #include <ngx_core.h> |
| |
| |
| #if (NGX_HAVE_ATOMIC_OPS) |
| |
| |
| #define NGX_RWLOCK_SPIN 2048 |
| #define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1) |
| |
| |
| void |
| ngx_rwlock_wlock(ngx_atomic_t *lock) |
| { |
| ngx_uint_t i, n; |
| |
| for ( ;; ) { |
| |
| if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) { |
| return; |
| } |
| |
| if (ngx_ncpu > 1) { |
| |
| for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) { |
| |
| for (i = 0; i < n; i++) { |
| ngx_cpu_pause(); |
| } |
| |
| if (*lock == 0 |
| && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) |
| { |
| return; |
| } |
| } |
| } |
| |
| ngx_sched_yield(); |
| } |
| } |
| |
| |
| void |
| ngx_rwlock_rlock(ngx_atomic_t *lock) |
| { |
| ngx_uint_t i, n; |
| ngx_atomic_uint_t readers; |
| |
| for ( ;; ) { |
| readers = *lock; |
| |
| if (readers != NGX_RWLOCK_WLOCK |
| && ngx_atomic_cmp_set(lock, readers, readers + 1)) |
| { |
| return; |
| } |
| |
| if (ngx_ncpu > 1) { |
| |
| for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) { |
| |
| for (i = 0; i < n; i++) { |
| ngx_cpu_pause(); |
| } |
| |
| readers = *lock; |
| |
| if (readers != NGX_RWLOCK_WLOCK |
| && ngx_atomic_cmp_set(lock, readers, readers + 1)) |
| { |
| return; |
| } |
| } |
| } |
| |
| ngx_sched_yield(); |
| } |
| } |
| |
| |
| void |
| ngx_rwlock_unlock(ngx_atomic_t *lock) |
| { |
| if (*lock == NGX_RWLOCK_WLOCK) { |
| (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); |
| } else { |
| (void) ngx_atomic_fetch_add(lock, -1); |
| } |
| } |
| |
| |
| void |
| ngx_rwlock_downgrade(ngx_atomic_t *lock) |
| { |
| if (*lock == NGX_RWLOCK_WLOCK) { |
| *lock = 1; |
| } |
| } |
| |
| |
| #else |
| |
| #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE) |
| |
| #error ngx_atomic_cmp_set() is not defined! |
| |
| #endif |
| |
| #endif |