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-16 18:15
设计资源 培训 开发板 精华推荐
- 4 通道 I2C 多路复用器提供地址扩展、总线缓冲和故障管理
- 用于恒流源的 NCV431A 可编程精密基准的典型应用
- RS485DL RS485保护电路
- LT6656BIS6-4.096、4.096V 扩展电源范围电压基准的典型应用
- 物联网加热台_兼容大尺寸加热板版本
- 使用 LTC3637IDHC 4V 至 76V 输入至 1.8V 超级电容充电器的典型应用
- A8586KLJTR-T-1 宽输入电压、可调频率、3.5A 降压稳压器的典型应用电路
- syzygy-epc901:SYZYGY 与 EPC901 CCD + 50MSps ADC
- 元件封装测试板_SMD
- LT3091EDE 在极低输出电压下低压降操作的典型应用
- Allegro MicroSystems 在 2024 年德国慕尼黑电子展上推出先进的磁性和电感式位置感测解决方案
- 左手车钥匙,右手活体检测雷达,UWB上车势在必行!
- 狂飙十年,国产CIS挤上牌桌
- 神盾短刀电池+雷神EM-i超级电混,吉利新能源甩出了两张“王炸”
- 浅谈功能安全之故障(fault),错误(error),失效(failure)
- 智能汽车2.0周期,这几大核心产业链迎来重大机会!
- 美日研发新型电池,宁德时代面临挑战?中国新能源电池产业如何应对?
- Rambus推出业界首款HBM 4控制器IP:背后有哪些技术细节?
- 村田推出高精度汽车用6轴惯性传感器
- 福特获得预充电报警专利 有助于节约成本和应对紧急情况