nginx源码分析1———进程间的通信机制三(mmap)
2015-07-27 22:22
741 查看
相关介绍
mmap函数把一个文件或者一个Posix共享内存区对象映射到调用进程的地址空间。使用该函数,可以达到三个目的。1.使用普通文件以提供内存映射I/O。
2.使用特殊文件以提供匿名内存映射。
3.使用shm_open以提供无亲缘关系进程间的Posix共享内存区(本章不介绍,有兴趣可以了解)
相关系统调用
#include<sys/mman.h> //若成功则返回被映射区的起始地址,若出错则为MAP_FAILED void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
addr:可以制定描述符fd应被映射到进程内空间的起始地址。它通常被指定为一个空指针,这样告诉内核自己去选择起始地址。无论哪种情况下,该函数的返回值都是描述符fd所映射到内存区的起始地址。
len:映射到调用进程地址空间中的字节数,它从被映射文件开头起第offset个字节开始算。offset通常设置为0。
prot:内存映射区的保护由port参数指定。
prot | 说明 |
---|---|
PROT_READ | 数据可读 |
PROT_WRITE | 数据可写 |
PROT_EXEC | 数据可执行 |
PROT_NONE | 数据不可访问 |
1,如果指定了MAP_PRIVATE,那么调用进程对被映射数据所作的修改只对该进程可见,而不改变其底层支撑对象(或者一个文件对象,或者一个共享内存区对象)。
2,如果指定了MAP_SHARED,那么调用进程对映射数据所做的修改对于共享该对象的所有进程可见,而且确实改变了其底层支撑对象。
Flags | 说明 |
---|---|
MAP_SHARED | 变动是共享的 |
MAP_PRIVATE | 变动是自私的 |
MAP_ANON | 这个映射不基于任何文件 |
MAP_FIXED | 准确地解释addr参数 |
4 , mmap返回后,fd参数可以关闭,该操作对于由mmap建立的映射关系没有影响。
#include <sys/mman.h> int munmap(void *addr, size_t len);
其中addr参数是由mmap返回的地址,len是映射区的大小。再次访问这些地址将导致向调用进程产生一个SIGSEGV信号(当然这里假设以后的mmap调用并不重用这部分地址空间)。
相关结构
ngx_shmem.htypedef 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_HAVE_MAP_ANON宏开启的条件下,将采用MAP_ANON的方式去mmap和munmap。这是4.4BSD提供的匿名内存映射,它彻底避免了文件的创建和打开。#if (NGX_HAVE_MAP_ANON) //使用mmap进行alloc ngx_int_t ngx_shm_alloc(ngx_shm_t *shm) { //指定共享区的数据可读也可以写,并且是shared共享模式的。 shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, //对于MAP_ANON,将不基于//任何文件,所以文件fd为-1,offset为0,而且内容将被初始化为0. MAP_ANON|MAP_SHARED, -1, 0); //出错将返回MAP_FAILED。 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; } //使用munmap进行free void ngx_shm_free(ngx_shm_t *shm) { //里面的addr是mmap里面返回的addr,size也是mmap里面分配的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)
细心的读者在最后可以看到#elif宏,也就是在NGX_HAVE_MAP_ANON没有开启的时候,将采取映射/dev/zero的方式去共享内存
#elif (NGX_HAVE_MAP_DEVZERO) ngx_int_t ngx_shm_alloc(ngx_shm_t *shm) { ngx_fd_t fd; //open一个文件,将其作为映射,这是一个特殊文件 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; } //调用mmap和上面的例子一样,不过多填进去fd和少1个MAP_ANON,因为该种方式采用特殊文件,不是匿名方式了。 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); } //关掉fd文件描述符,前面已经提到,这并没什么卵用,可以直接关掉。 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; }
上述是SVR4提供/dev/zero设备文件,我们open它之后的描述符可以再mmap中使用,从设备读取返回的字节全为0,写往该设备的任何字节则被丢弃。而ngx_shm_free和匿名方式一样,我就不在赘述。而共享内存还使用了第三种方式去共享,那是在这两种都没有的情况下,我们将留到下一章赘述。
相关文章推荐
- Nginx worker工作流程
- nginx的fastcgi配置
- tornado + nginx + supervisord 环境部署
- centOS下的nginx1.8.0多站点配置(同一IP,不同端口)
- Nginx配置文件说明
- 让 Vim 支持 nginx 语法(syntax) 格式化配置文件
- thinkphp nginx 上配置 并解决get获取到数据现象
- Nginx/LVS/HAProxy负载均衡软件的优缺点详解
- nginx第一章--执行main函数前的描述
- nginx 域名(虚拟)部署nodejs项目
- 实战Nginx与PHP(FastCGI)的安装、配置与优化
- 基于Storm的Nginx log实时监控系统
- LVS Nginx HAProxy 优缺点
- 解决nginx下connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstream, client: 127.0.0.1, server: 错误信息
- CDN下nginx获取用户真实IP地址
- Nginx中发送udp请求
- Nginx虚拟主机配置 + 虚拟主机支持PHP
- nginx设计解读--模块化设计及程序初始化
- Apache与Nginx的优缺点比较
- Nginx学习之:上传碰到“413”错误