|  | 
 | /* | 
 |  * 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 |