Nginx源码阅读(进程间通信)

来源:互联网 发布:动画创意广告软件 编辑:程序博客网 时间:2024/05/16 05:13

共享内存

/* src/os/unix/ngx_shmem.h */typedef struct {    u_char      *addr; // 共享内存的地址    size_t       size; // 共享内存的长度    ngx_str_t    name; // 共享内存的名称    ngx_log_t   *log;    ngx_uint_t   exists;   /* unsigned  exists:1;  */} ngx_shm_t;ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);void ngx_shm_free(ngx_shm_t *shm);
/* src/os/unix/ngx_shmem.c */#if (NGX_HAVE_MAP_ANON)ngx_int_tngx_shm_alloc(ngx_shm_t *shm){    // mmap和munmap的定义:http://www.man7.org/linux/man-pages/man2/mmap.2.html    shm->addr = (u_char *) mmap(NULL, shm->size,                                PROT_READ|PROT_WRITE,                                MAP_ANON|MAP_SHARED, -1, 0);    if (shm->addr == MAP_FAILED) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);        return NGX_ERROR;    }    return NGX_OK;}voidngx_shm_free(ngx_shm_t *shm){    if (munmap((void *) shm->addr, shm->size) == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "munmap(%p, %uz) failed", shm->addr, shm->size);    }}#elif (NGX_HAVE_MAP_DEVZERO)ngx_int_tngx_shm_alloc(ngx_shm_t *shm){    ngx_fd_t  fd;    fd = open("/dev/zero", O_RDWR);    if (fd == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "open(\"/dev/zero\") failed");        return NGX_ERROR;    }    shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE,                                MAP_SHARED, fd, 0);    if (shm->addr == MAP_FAILED) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size);    }    if (close(fd) == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "close(\"/dev/zero\") failed");    }    return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK;}voidngx_shm_free(ngx_shm_t *shm){    if (munmap((void *) shm->addr, shm->size) == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "munmap(%p, %uz) failed", shm->addr, shm->size);    }}#elif (NGX_HAVE_SYSVSHM)#include <sys/ipc.h>#include <sys/shm.h>ngx_int_tngx_shm_alloc(ngx_shm_t *shm){    int  id;    /* shmget的定义:http://www.man7.org/linux/man-pages/man2/shmget.2.html       shmat和shmdt的定义:http://www.man7.org/linux/man-pages/man2/shmop.2.html       shmctl的定义:http://www.man7.org/linux/man-pages/man2/shmctl.2.html */    id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));    if (id == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "shmget(%uz) failed", shm->size);        return NGX_ERROR;    }    ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id);    shm->addr = shmat(id, NULL, 0);    if (shm->addr == (void *) -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");    }    if (shmctl(id, IPC_RMID, NULL) == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "shmctl(IPC_RMID) failed");    }    return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;}voidngx_shm_free(ngx_shm_t *shm){    if (shmdt(shm->addr) == -1) {        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,                      "shmdt(%p) failed", shm->addr);    }}#endif

原子操作

不支持原子库下的原子操作

/* src/os/unix/ngx_atomic.h */#define NGX_HAVE_ATOMIC_OPS  0typedef int32_t                     ngx_atomic_int_t;typedef uint32_t                    ngx_atomic_uint_t;typedef volatile ngx_atomic_uint_t  ngx_atomic_t;#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)static ngx_inline ngx_atomic_uint_tngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,    ngx_atomic_uint_t set){    if (*lock == old) {        *lock = set;        return 1;    }    return 0;}static ngx_inline ngx_atomic_int_tngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add){    ngx_atomic_int_t  old;    old = *value;    *value += add;    return old;}#define ngx_memory_barrier()#define ngx_cpu_pause()

x86架构下的原子操作

/* src/os/unix/ngx_atomic.h */typedef int32_t                     ngx_atomic_int_t;typedef uint32_t                    ngx_atomic_uint_t;typedef volatile ngx_atomic_uint_t  ngx_atomic_t;#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)#if ( __SUNPRO_C )#define NGX_HAVE_ATOMIC_OPS  1ngx_atomic_uint_tngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,    ngx_atomic_uint_t set);ngx_atomic_int_tngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add);/* * Sun Studio 12 exits with segmentation fault on '__asm ("pause")', * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_x86.il */voidngx_cpu_pause(void);/* the code in src/os/unix/ngx_sunpro_x86.il */#define ngx_memory_barrier()        __asm (".volatile"); __asm (".nonvolatile")#else /* ( __GNUC__ || __INTEL_COMPILER ) */#define NGX_HAVE_ATOMIC_OPS  1#include "ngx_gcc_atomic_x86.h"#endif
/* src/os/unix/ngx_gcc_atomic_x86.h */#if (NGX_SMP)#define NGX_SMP_LOCK  "lock;"#else#define NGX_SMP_LOCK#endif/* * "cmpxchgl  r, [m]": * *     if (eax == [m]) { *         zf = 1; *         [m] = r; *     } else { *         zf = 0; *         eax = [m]; *     } * * * The "r" means the general register. * The "=a" and "a" are the %eax register. * Although we can return result in any register, we use "a" because it is * used in cmpxchgl anyway.  The result is actually in %al but not in %eax, * however, as the code is inlined gcc can test %al as well as %eax, * and icc adds "movzbl %al, %eax" by itself. * * The "cc" means that flags were changed. */static ngx_inline ngx_atomic_uint_tngx_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;}/* * "xaddl  r, [m]": * *     temp = [m]; *     [m] += r; *     r = temp; * * * The "+r" means the general register. * The "cc" means that flags were changed. */#if !(( __GNUC__ == 2 && __GNUC_MINOR__ <= 7 ) || ( __INTEL_COMPILER >= 800 ))/* * icc 8.1 and 9.0 compile broken code with -march=pentium4 option: * ngx_atomic_fetch_add() always return the input "add" value, * so we use the gcc 2.7 version. * * icc 8.1 and 9.0 with -march=pentiumpro option or icc 7.1 compile * correct code. */static ngx_inline ngx_atomic_int_tngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add){    __asm__ volatile (         NGX_SMP_LOCK    "    xaddl  %0, %1;   "    : "+r" (add) : "m" (*value) : "cc", "memory");    return add;}#else/* * gcc 2.7 does not support "+r", so we have to use the fixed * %eax ("=a" and "a") and this adds two superfluous instructions in the end * of code, something like this: "mov %eax, %edx / mov %edx, %eax". */static ngx_inline ngx_atomic_int_tngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add){    ngx_atomic_uint_t  old;    __asm__ volatile (         NGX_SMP_LOCK    "    xaddl  %2, %1;   "    : "=a" (old) : "m" (*value), "a" (add) : "cc", "memory");    return old;}#endif/* * on x86 the write operations go in a program order, so we need only * to disable the gcc reorder optimizations */#define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory")/* old "as" does not support "pause" opcode */#define ngx_cpu_pause()         __asm__ (".byte 0xf3, 0x90")

自旋锁

/* src/core/ngx_spinlock.c */voidngx_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为0表示锁是被释放的,lock不为0表示锁是被某个进程持有的        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;                }            }        }        /* #if (NGX_HAVE_SCHED_YIELD)           // sched_yield的定义:http://www.man7.org/linux/man-pages/man2/sched_yield.2.html           #define ngx_sched_yield()  sched_yield()           #else           #define ngx_sched_yield()  usleep(1)           #endif */        ngx_sched_yield(); // 暂时让出处理器    }#else#if (NGX_THREADS)#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !#endif#endif}
0 0
原创粉丝点击