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);
百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台