OK6410A 开发板 (八) 102 linux-5.11 OK6410A glibc提供的mmap的四种用途之一
共享匿名映射两种方式
当使用参数 fd = -1 且 flags = MAP_ANONYMOUS | MAP_SHARED 时,创建的mmap 映射是共享匿名映射.
共享匿名映射让相关进程共享一块内存区域,通常用于父子进程之间的通信.
创建共享匿名映射有如下两种方式,这两种方法最终都调用shmem 模块来创建共享匿名映射
1. fd = -1,且 使用这个文件句柄来创建mmap(lags = MAP_ANONYMOUS | MAP_SHARED) .
在这种情况下,do_mmap_pgoff()->mmap_region() 函数
最终会调用shmem_zero_setup 来打开一个 "/dev/zero"
2. fd = 打开 "/dev/zero"返回的 fd ,且 使用这个文件句柄来创建mmap(flags = MAP_ANONYMOUS | MAP_SHARED)
注意 : 以下三个实例 都调用了 shmem_zero_setup
实例1 : 走了 mmap_region-> mm/mmap.c(1844)shmem_zero_setup
实例2 : 走了 mmap_region-> mm/mmap.c(1844)shmem_zero_setup
// 实例2 虽然打开了文件,但是还是走的共享匿名映射
// 共享匿名映射实例 mmap_dev-zero-fd.c 中 匿名和 fd(大于等于0)同时置,是有问题的
实例3 : 走了 mmap_region-> mm/mmap.c(1807)call_mmap(即mmap_zero)->shmem_zero_setup // 走了 共享文件映射
mmap 做共享文件映射的时候可以用 磁盘文件,也可以用 内存文件。
mmap 做共享匿名映射的时候 ,本质上用的是 /dev/zero(其文件是内存文件/dev/zero)
至于说这些/dev/下的内存文件 底下藏着什么东西,要看驱动(因为/dev下都是驱动)的实现
tmpfs或其他(udev或devtmpfs) 一般挂载到 /dev下 . shmemfs 一般挂载到 /dev/shm 下
在 /dev 下的 文件 一般都有自己(独有)的 file_operations
在 /dev/shm 下的 所有文件共享同一个 file_operations
[5] = { "zero", 0666, &zero_fops, 0 },
/dev/zero 下的 是
static const struct file_operations zero_fops
.mmap = mmap_zero,
.get_unmapped_area = get_unmapped_area_zero,
[DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
/dev/mem 下的是
static const struct file_operations __maybe_unused mem_fops
.mmap = mmap_mem,
.get_unmapped_area = get_unmapped_area_mem,
/dev/shm/xxx
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
shmem_init
register_filesystem(&shmem_fs_type);
.name = "tmpfs",
为什么在 /dev/shm 下 创建,是因为
/dev/shm 下 为 shmemfs(tmpfs) 挂载到的目录
也就是说 在 shmemfs 下创建文件.
而对 该文件的 的mmap 是 的底层是 分为两种
//1.
static const struct file_operations shmem_file_operations = {
.mmap = shmem_mmap,
.get_unmapped_area = shmem_get_unmapped_area,
//2.
#define shmem_file_operations ramfs_file_operations
const struct file_operations ramfs_file_operations = {
.mmap = generic_file_mmap,
.get_unmapped_area = ramfs_mmu_get_unmapped_area,
posix 和 systemv 的 共享内存 都是 基于 shmem 文件系统的 file_operations 的 mmap 做的
共享匿名映射实例 mmap_negtivefd.c
// gcc mmap_negtivefd.c -o mmap_negtivefd -lpthread
// mmap_negtivefd.c
#include #include #include #include #include #include #include struct file_content { sem_t st; void *pv; }file_content; #define NINT 16 int main (int argc, char *argv[]) { int fd; fd = -1; struct file_content *pfc; pfc =mmap (NULL, sizeof (file_content) + sizeof (int) * NINT, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANON, fd, 0); if (pfc == MAP_FAILED) { printf ("map failed!n"); exit(3); } //信号量初始化为1,用于互斥 sem_init (&(pfc->st), 1, 1); //pv指向结构体下一个字节的地址 pfc->pv = (void *) ((char *) pfc + sizeof (struct file_content)); printf ("结构体地址:tt%xn结构体下一位置地址:tt%xn", (int)pfc, (int)pfc->pv); // 不加上这句的话,可能输出会卡在那里! setbuf(stdout,NULL); //子进程 if (fork () == 0) { static int count_child = 0; int i; while (1) { sem_wait (&(pfc->st)); printf ("Child processn"); int *p = pfc->pv; for (i = 0; i < NINT; i++) { p[i] = 2 * i; } for (i = 0; i < NINT; i++) { printf ("%d ", p[i]); } printf ("n"); sem_post (&(pfc->st)); sleep(2); count_child ++; if (count_child == 2) break; } } // 父进程 else { static int count_father = 0; int i; while (1) { sem_wait (&(pfc->st)); printf ("Father processn"); int *p = pfc->pv; /* for (i = 0; i < NINT; i++) { p[i] = 3 * i; } */ for (i = 0; i < NINT; i++) { printf ("%d ", p[i]); } printf ("n"); sem_post (&(pfc->st)); sleep(2); count_father ++; if (count_father == 2) break; } } if (munmap (pfc, sizeof (file_content) + sizeof (int) * NINT) == -1) { printf ("ummap!n"); exit (2); } return 0; } 共享匿名映射实例 mmap_dev-zero-fd.c // gcc mmap_dev-zero-fd.c -o mmap_dev-zero-fd -lpthread // mmap_dev-zero-fd.c #include #include #include #include #include #include #include struct file_content { sem_t st; void *pv; }file_content; #define NINT 16 int main (int argc, char *argv[]) { int fd; #define FILE_PATH "/dev/zero" fd = open(FILE_PATH,O_RDWR); if(fd < 0) { printf("open zero fail n"); exit(2); } struct file_content *pfc; pfc =mmap (NULL, sizeof (file_content) + sizeof (int) * NINT, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANON, fd, 0); close(fd); if (pfc == MAP_FAILED) { printf ("map failed!n"); exit(3); } //信号量初始化为1,用于互斥 sem_init (&(pfc->st), 1, 1); //pv指向结构体下一个字节的地址 pfc->pv = (void *) ((char *) pfc + sizeof (struct file_content)); printf ("结构体地址:tt%xn结构体下一位置地址:tt%xn", (int)pfc, (int)pfc->pv); // 不加上这句的话,可能输出会卡在那里! setbuf(stdout,NULL); //子进程 if (fork () == 0) { static int count_child = 0; int i; while (1) { sem_wait (&(pfc->st)); printf ("Child processn"); int *p = pfc->pv; for (i = 0; i < NINT; i++) { p[i] = 2 * i; } for (i = 0; i < NINT; i++) { printf ("%d ", p[i]); } printf ("n"); sem_post (&(pfc->st)); sleep(2); count_child ++; if (count_child == 2) break; } } // 父进程 else { static int count_father = 0; int i; while (1) { sem_wait (&(pfc->st)); printf ("Father processn"); int *p = pfc->pv; /* for (i = 0; i < NINT; i++) { p[i] = 3 * i; } */ for (i = 0; i < NINT; i++) { printf ("%d ", p[i]); } printf ("n"); sem_post (&(pfc->st)); sleep(2); count_father ++; if (count_father == 2) break; } } if (munmap (pfc, sizeof (file_content) + sizeof (int) * NINT) == -1) { printf ("ummap!n"); exit (2); } return 0; } 其他 共享文件映射实例 mmap_dev-zero-fd2.c 这个 在文本上 比 "共享匿名映射实例 mmap_dev-zero-fd.c" 少了一个 "|MAP_ANON" , 其他都一样 这个 在效果上 和 "共享匿名映射实例 mmap_dev-zero-fd.c" 完全一样 这个 和 "共享匿名映射实例 mmap_dev-zero-fd.c" 在本质上有什么不同 ??? TODO 这个 和 "共享匿名映射实例 mmap_dev-zero-fd.c" 都调用了 shmem_zero_setup // gcc mmap_dev-zero-fd2.c -o mmap_dev-zero-fd2 -lpthread // mmap_dev-zero-fd.c #include #include #include #include #include #include #include struct file_content { sem_t st; void *pv; }file_content; #define NINT 16 int main (int argc, char *argv[]) { int fd; #define FILE_PATH "/dev/zero" fd = open(FILE_PATH,O_RDWR); if(fd < 0) { printf("open zero fail n"); exit(2); } struct file_content *pfc; pfc =mmap (NULL, sizeof (file_content) + sizeof (int) * NINT, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (pfc == MAP_FAILED) { printf ("map failed!n"); exit(3); } //信号量初始化为1,用于互斥 sem_init (&(pfc->st), 1, 1); //pv指向结构体下一个字节的地址 pfc->pv = (void *) ((char *) pfc + sizeof (struct file_content)); printf ("结构体地址:tt%xn结构体下一位置地址:tt%xn", (int)pfc, (int)pfc->pv); // 不加上这句的话,可能输出会卡在那里! setbuf(stdout,NULL);
上一篇:OK6410A 开发板 (八) 104 linux-5.11 OK6410A mmap四种用途参数及扩展
下一篇:OK6410A 开发板 (八) 101 linux-5.11 OK6410A printf 在 glibc 和 linux 中的流程
推荐阅读最新更新时间:2024-11-08 07:18
设计资源 培训 开发板 精华推荐
- LT3091EFE 并联器件使用 IMONN 消除镇流器电阻压降的典型应用
- TCR5SB31U、200mA、3.1V输出电压CMOS低压降稳压器的典型应用
- LTC1266、全 N 沟道单电源 5V 至 3.3V/10A 稳压器
- 使用 Infineon Technologies AG 的 ICB1FL02G 的参考设计
- 基于ESP32S2以及MaixBit的智能网络台灯
- DC1591A,用于 LTC6409 10GHz、1nV/rt (Hz) 差分放大器/ADC 驱动器的演示板
- OM13313: TDA5051A PLM演示板套件
- 超小型刷式直流电机电流调节 TI 参考设计
- LT6656ACDC-3.3、3.3V 低功率 ADC 电压基准的典型应用
- 使用 ON Semiconductor 的 NCP1086 的参考设计
- Waymo打造最大弱势道路使用者交通事故数据集 可帮助指导自动驾驶系统研发
- 车载显示,大步向前
- 新专利:未来福特汽车或将配备亮度管理系统
- 科学家研发基于AI的身份验证工具 可保护车辆免受网络攻击威胁
- Microchip推出广泛的IGBT 7 功率器件组合,专为可持续发展、电动出行和数据中心应用而设计
- 面向未来驾驶体验 博世推出新型微电子技术
- 英飞凌与马瑞利合作 利用AURIX™ TC4x MCU系列推动区域控制单元创新
- 5C超充,该怎么卷?
- 《2025年度中国汽车十大技术趋势》正式揭晓!你最看好哪个?
- Microchip推出新型VelocityDRIVE™软件平台和车规级多千兆位以太网交换芯片,支持软件定义汽车