Nginx 소스 코드 완전 분석 nginx 자전거 자물쇠 ngxspinlock

6320 단어
Nginx 는 다 중 프로 세 스 모드 입 니 다. 하나의 master 와 여러 workers 는 보통 다 중 핵 CPU 에서 작 동 하기 때문에 자 물 쇠 를 사용 해 야 합 니 다.Nginx 의 자 회전 자물쇠 의 정 의 는 ngx 에 있 습 니 다.spinlock. c 에 서 는 다음 과 같 습 니 다.
void
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
{

#if (NGX_HAVE_ATOMIC_OPS)

    ngx_uint_t  i, n;

    for ( ;; ) {

        // lock    ,     
        // ngx_atomic_cmp_set       ,         
        if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
            return;
        }

        //   
        if (ngx_ncpu > 1) {

            //        ,      
            for (n = 1; n < spin; n <<= 1) {

                for (i = 0; i < n; i++) {
                    ngx_cpu_pause();
                }

                if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
                    return;
                }
            }
        }

        ngx_sched_yield();
    }

#else

#if (NGX_THREADS)

#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !

#endif

#endif

}

그 중에서 lock 이라는 성형 변수 로 자 물 쇠 를 표시 하 는데 필자 의 기계 (Darwin 12.0) 에서 다음 과 같이 정의 된다.
typedef volatile ngx_atomic_uint_t  ngx_atomic_t;

다시 위 spinlock 의 소스 코드 분석 으로 돌아 가면 ngxncpu (CPU 의 핵심 수 를 나타 내 는 것) 가 1 개 이상, 즉 다 핵 CPU 를 초과 하면 대기 / 재 시도 해 야 합 니 다.예 를 들 어 spin 이 80 이면 처음으로 ngx 1 개 를 기다린다.cpu_pause () 작업 을 한 다음 잠 금 이 사용 가능 한 지 다시 확인 합 니 다.다음 라운드 마다 각각 2 개, 4 개, 8 개, 16 개, 32 개, 64 개 ngxcpu_pause () 조작 후 다시 시도 합 니 다.이 중간 과정 에서 자물쇠 가 풀 려 사용 할 수 있 는 상황 이 발생 하면 순환 이 중단 되 고 spinlock 함수 가 값 을 되 돌려 줍 니 다.재 시도 에 성공 하지 못 하면 ngx 를 실행 합 니 다.sched_yield, 그리고 위의 조작 을 반복 합 니 다.
그리고 그 중의 ngxatomic_cmp_set 함수 도 탐구 가치 가 있 습 니 다.Darwin 12.0 에 서 는 다음 과 같은 매크로 정의 가 있 습 니 다.
#define ngx_atomic_cmp_set(lock, old, new) \
OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock)

제 친구 의 Linux 환경 (구체 적 으로 잊 어 버 렸 지만 x86) 은 다음 과 같 습 니 다.그 중의 내 연 어 셈 블 리 는 본 블 로그 내의 GCC 내 연 어 셈 블 리 의 두 편의 박문 을 참고 할 수 있다.그 중 SMP 는 버스 자물쇠 다.
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)
{
    u_char  res;

    __asm__ volatile (

         NGX_SMP_LOCK
    " cmpxchgl %3, %1; "
    " sete %0; "

    : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");

    return res;
}

이 출력 은 res 로 eax 레지스터 에 저 장 됩 니 다.* lock (내장), old (eax 중), set (r 는 유 니 버 설 레지스터 를 표시 합 니 다.이렇게% 0 은 res,% 1 은 * lock,% 2 는 old,% 3 은 set 입 니 다.
* lock 과 old 가 같 으 면 이 또는 (cmpxchgl) 가 0 이면 ZF 는 1 이 고 sete 는 res (% 0) 의 값 을 1 로 설정 하고 되 돌려 줍 니 다.* lock 과 old 가 같 지 않 으 면 이화 치가 0 이 아니 기 때문에 ZF 가 0 이 아니면 sete 는 동작 을 수행 하지 않 습 니 다. 즉, res 값 이 0 이 고 ngx 를 호출 합 니 다.atomic_cmp_set 실패.
cmpxchgl 은 ZF (Zero Flag) 표지 위치 에 영향 을 줄 수 있 습 니 다.

좋은 웹페이지 즐겨찾기