nginx多进程锁的实现

CPU cache:

http://cenalulu.github.io/linux/all-about-cpu-cache/

other:

http://www.cnblogs.com/zhengsyao/p/mcs_lock_scalable_spinlock.html

http://simohayha.iteye.com/blog/658012

http://www.searchtb.com/2011/06/spinlock%E5%89%96%E6%9E%90%E4%B8%8E%E6%94%B9%E8%BF%9B.html

 

Nginx workers 要获取新的请求,需要互斥的得到监听端口的socket句柄。nginx通过自己实现的锁来实现进程间互斥.

1, 原子操作

原子操作就是可以在执行这几个操作的时候不会被其他指令打断,可以实现排他的内存访问,实际是在内存总线层次的临界区操作。

Nginx 使用gcc的原子操作:

ngx_atomic.h:

#elif (NGX_HAVE_GCC_ATOMIC)

/* GCC 4.1 builtin atomic operations */

 

#define NGX_HAVE_ATOMIC_OPS 1  //表示支持原子操作

typedef long                        ngx_atomic_int_t;

typedef unsigned long               ngx_atomic_uint_t;

 

#if (NGX_PTR_SIZE == 8)

#define NGX_ATOMIC_T_LEN           (sizeof("-9223372036854775808") - 1)

#else

#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") -1)

#endif

 

typedef volatile ngx_atomic_uint_t  ngx_atomic_t; //volatile类型,表示该变量随时会被修改,每次都需要从其存储地址读取

 

#define ngx_atomic_cmp_set(lock, old, set)                                    \ // 原子的比较和交换,如果*lock==old,就将set写入*lock

   __sync_bool_compare_and_swap(lock, old, set)                            // 相等并写入的情况下返回true/操作之前的值

 

#define ngx_atomic_fetch_add(value, add)                                      \   // *value+=add并返回更新前的值

    __sync_fetch_and_add(value,add)

 

#define ngx_memory_barrier()        __sync_synchronize()                     // 发出一个full barrier

 

memory barrier有几种类型:

    acquire barrier : 不允许将barrier之后的内存读取指令移到barrier之前(linuxkernel中的wmb())。

    release barrier : 不允许将barrier之前的内存读取指令移到barrier之后(linux kernel中的rmb())。

    full barrier    : 以上两种barrier的合集(linux kernel中的mb())。

 

Nginx自己实现原子操作:

read-modify-write(RMW)原子操作

例如Intel平台支持在指令前面加上lock前缀锁定总线,实现原子的比较-交换操作(CAS,通过cmpxchg指令,原子地执行判断条件并交换值的操作),原子递增和原子递减(inc和dec指令)操作。还支持一个交换操作,xchg指令,不需要lock前缀,可以原子地交换两个寄存器或一个寄存器和一个内存位置的值。在Intel平台上通过这些基本的原子操作支持几乎所有的原子操作。

ngx_gcc_atomic_amd64.h:

static ngx_inline ngx_atomic_uint_t

ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_told, ngx_atomic_uint_t set)

{

 u_char  res;

  __asm__ volatile (

 

         lock

    "    cmpxchgq %3, %1;   "  

    "    sete     %0;       "        

 

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

    return res;

}

//"=a" : =是output operand字段特有的约束,表示该操作数是只写的(write-only);

a表示先将命令执行结果输出至%eax,然后再由寄存器%eax更新位于内存中的out_var;

//不想通过寄存器中转,而是直接操作内存时,可以用"m"来约束

// "r"约束指明gcc可以先将%eax值存入任一可用的寄存器,然后由该寄存器负责更新内存变量。

//The "cc" means that flags were changed.

 

2,锁的实现

在用户空间进程间锁实现的原理,就是有一个让所有进程共享的东西,比如mmap的内存或者文件,然后通过这个东西来控制进程的互斥。

就是共享一个变量,然后通过设置这个变量来控制进程的行为。

初始化:ngx_event_module_init

....

    /* cl should be equal to or greater thancache line size */

   //mmap分配共享内存,cache line可以简单的理解为CPU Cache中的最小缓存单位。

    cl = 128;

    size = cl            /* ngx_accept_mutex */

           + cl          /* ngx_connection_counter */

           + cl;         /* ngx_temp_number */

    shm.size = size;

    shm.name.len =sizeof("nginx_shared_zone");

    shm.name.data = (u_char *)"nginx_shared_zone";

    shm.log = cycle-log;

    if (ngx_shm_alloc(shm) != NGX_OK) {

        return NGX_ERROR;

    }

    shared = shm.addr;

    ngx_accept_mutex_ptr = (ngx_atomic_t *)shared;

    ngx_accept_mutex.spin = (ngx_uint_t) -1;

    //把分配的共享内存地址赋值给ngx_accept_mutex-lock;

    if (ngx_shmtx_create(ngx_accept_mutex,(ngx_shmtx_sh_t *) shared,

                        cycle-lock_file.data)

        != NGX_OK)

    {

        return NGX_ERROR;

    }

......

typedef struct {

    u_char     *addr;  //mmap分配的共享内存地址

    size_t      size;

    ngx_str_t   name;

    ngx_log_t  *log;

    ngx_uint_t  exists;   /* unsigned  exists:1; */

} ngx_shm_t;

ngx_shm_t            shm;

 

ngx_shmtx.h

typedef struct {

#if (NGX_HAVE_ATOMIC_OPS)

    ngx_atomic_t  *lock;

#if (NGX_HAVE_POSIX_SEM)

    ngx_atomic_t  *wait;

    ngx_uint_t     semaphore;

    sem_t          sem;

#endif

#else

    ngx_fd_t       fd;

    u_char        *name;

#endif

    ngx_uint_t     spin;

} ngx_shmtx_t;

ngx_shmtx_t           ngx_accept_mutex;

 

非阻塞获取锁:ngx_shmtx_trylock(ngx_accept_mutex)

//尝试获取锁,如果锁已经被其他进程占用,返回false,否则给lock赋值表示该已进程获取锁。

ngx_uint_t 

ngx_shmtx_trylock(ngx_shmtx_t*mtx)

{

    return (*mtx-lock == 0 ngx_atomic_cmp_set(mtx-lock, 0, ngx_pid));

}

 

阻塞获取锁:

void

ngx_shmtx_lock(ngx_shmtx_t *mtx)

{

    ngx_uint_t         i, n;

 

    ngx_log_debug0(NGX_LOG_DEBUG_CORE,ngx_cycle-log, 0, "shmtx lock");

 

    for ( ;; ) {

        //直接获取锁

        if (*mtx-lock == 0 ngx_atomic_cmp_set(mtx-lock, 0, ngx_pid)) {

            return;

        }

        //多核情况下,进入spin-wait loop

        if (ngx_ncpu 1) {

 

            for (n = 1; n mtx-spin; n= 1) {

                   //busy waiting

                for (i = 0; i n; i++) {

                    ngx_cpu_pause();

                }

                   //try again

                if (*mtx-lock == 0

                    ngx_atomic_cmp_set(mtx-lock, 0, ngx_pid))

                {

                    return;

                }

            }

        }

 

#if (NGX_HAVE_POSIX_SEM)

 

        if (mtx-semaphore) {

            (void)ngx_atomic_fetch_add(mtx-wait, 1);

 

            if (*mtx-lock == 0 ngx_atomic_cmp_set(mtx-lock, 0, ngx_pid)) {

                (void)ngx_atomic_fetch_add(mtx-wait, -1);

                return;

            }

 

            ngx_log_debug1(NGX_LOG_DEBUG_CORE,ngx_cycle-log, 0,

                           "shmtx wait %uA",*mtx-wait);

 

            while (sem_wait(mtx-sem)== -1) {

                ngx_err_t  err;

 

                err = ngx_errno;

 

                if (err != NGX_EINTR) {

                   ngx_log_error(NGX_LOG_ALERT, ngx_cycle-log, err,

                                 "sem_wait() failed while waiting on shmtx");

                    break;

                }

            }

 

            ngx_log_debug0(NGX_LOG_DEBUG_CORE,ngx_cycle-log, 0,

                           "shmtx awoke");

 

            continue;

        }

 

#endif

        //强迫当前运行的进程放弃占有处理器

        ngx_sched_yield();

    }

}

 


最新回复(0)
/jishuyZqqGilGG44T8A7CovfhL_2FNT3ufJlYGV3lpuouOZ8EI_3D4794603
8 简首页