|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * "casa   [r1] 0x80, r2, r0"  and | 
|  | * "casxa  [r1] 0x80, r2, r0"  do the following: | 
|  | * | 
|  | *     if ([r1] == r2) { | 
|  | *         swap(r0, [r1]); | 
|  | *     } else { | 
|  | *         r0 = [r1]; | 
|  | *     } | 
|  | * | 
|  | * so "r0 == r2" means that the operation was successfull. | 
|  | * | 
|  | * | 
|  | * The "r" means the general register. | 
|  | * The "+r" means the general register used for both input and output. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #if (NGX_PTR_SIZE == 4) | 
|  | #define NGX_CASA  "casa" | 
|  | #else | 
|  | #define NGX_CASA  "casxa" | 
|  | #endif | 
|  |  | 
|  |  | 
|  | static ngx_inline ngx_atomic_uint_t | 
|  | ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | 
|  | ngx_atomic_uint_t set) | 
|  | { | 
|  | __asm__ volatile ( | 
|  |  | 
|  | NGX_CASA " [%1] 0x80, %2, %0" | 
|  |  | 
|  | : "+r" (set) : "r" (lock), "r" (old) : "memory"); | 
|  |  | 
|  | return (set == old); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_inline ngx_atomic_int_t | 
|  | ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) | 
|  | { | 
|  | ngx_atomic_uint_t  old, res; | 
|  |  | 
|  | old = *value; | 
|  |  | 
|  | for ( ;; ) { | 
|  |  | 
|  | res = old + add; | 
|  |  | 
|  | __asm__ volatile ( | 
|  |  | 
|  | NGX_CASA " [%1] 0x80, %2, %0" | 
|  |  | 
|  | : "+r" (res) : "r" (value), "r" (old) : "memory"); | 
|  |  | 
|  | if (res == old) { | 
|  | return res; | 
|  | } | 
|  |  | 
|  | old = res; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #if (NGX_SMP) | 
|  | #define ngx_memory_barrier()                                                  \ | 
|  | __asm__ volatile (                                                \ | 
|  | "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad"        \ | 
|  | ::: "memory") | 
|  | #else | 
|  | #define ngx_memory_barrier()   __asm__ volatile ("" ::: "memory") | 
|  | #endif | 
|  |  | 
|  | #define ngx_cpu_pause() |