|  |  | 
|  | /* | 
|  | * 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) | 
|  | { | 
|  | ngx_atomic_uint_t  readers; | 
|  |  | 
|  | readers = *lock; | 
|  |  | 
|  | if (readers == NGX_RWLOCK_WLOCK) { | 
|  | *lock = 0; | 
|  | return; | 
|  | } | 
|  |  | 
|  | for ( ;; ) { | 
|  |  | 
|  | if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | readers = *lock; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #else | 
|  |  | 
|  | #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE) | 
|  |  | 
|  | #error ngx_atomic_cmp_set() is not defined! | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #endif |