nginx进程间的通信机制源码分析(一)----共享内存

</pre><span style="font-size:18px"></span><p></p><p>      <span style="white-space:pre"></span>共享内存是linux下提供的最基本的进程间通信方法,它通过mmap或者shmget系统调用在内存中创建了一块连续的线性地址空间,而通过munmap和shmdt系统调用可以释放这块内存.使用共享内存的好处是当多个进程使用同一块共享内存时,在任何一个进程修改了共享内存中的内容后,其他进程通过访问这段共享内存都能够得到修改后的内容.为了支持跨平台,nginx提供了三种共享内存的实现,分别为不映射文件使用mmap分配共享内存,以/dev/zero文件使用mmap映射共享内存,用shmget调用来分配共享内存       </p><p>头文件源码解析:</p><pre name="code" class="cpp">
typedef struct {
    u_char      *addr;      //指向共享内存的起始地址
    size_t       size;      //共享内存的长度
    ngx_str_t    name;      //这块共享内存的名称
    ngx_log_t   *log;       //记录日志的ngx_log_t对象
    ngx_uint_t   exists;   /* unsigned  exists:1;  *///表示共享内存是否已经分配过的标志为,为1时表示已经存在
} ngx_shm_t;


ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);          //分配共享内存
void ngx_shm_free(ngx_shm_t *shm);                //释放已经存在的共享内存</span>
           实现文件源码解析:

#include <ngx_config.h>
#include <ngx_core.h>


//mmap函数详细知识可看apue中文第三版p423
#if (NGX_HAVE_MAP_ANON)     //不映射文件用mmap分配共享内存          
//若mmap函数参数中的flags参数加入MAP_ANON,表示不使用文件映射方式,fd参数和offset参数没有意义,此时mmap方法和ngx_shm_alloc的功能几乎一样
ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)              
{
    //开辟一块shm->size大小的内存,首地址存放在shm-addr中,同时可读写
    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;
}


void
ngx_shm_free(ngx_shm_t *shm)                         //释放共享内存
{
    //使用ngx_shm_t中的shm->addr和shm->size参数释放共享内存
    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)  //以/dev/zero文件使用mmap映射共享内存

ngx_int_t
ngx_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,大小为shm->size,可读写
    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;
}


void
ngx_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)    //用shmget调用来分配共享内存

#include <sys/ipc.h>
#include <sys/shm.h>


ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
    int  id;
    //创建一个新的共享存储段,返回共享存储id
    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);
    //进程调用shmat将此段共享内存链接到它的地址空间,成功返回共享存储段的指针
    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;
}


void
ngx_shm_free(ngx_shm_t *shm)                //释放内存
{
    //这并不从系统中删除其标识符及其相关数据结构,直到某个进程调用shmctl删除它
    if (shmdt(shm->addr) == -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmdt(%p) failed", shm->addr);
    }
}



发布了25 篇原创文章 · 获赞 1 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章