• 首页
  • 中国
  • OK6410A 开发板 (八) 102 linux-5.11 OK6410A glibc提供的mmap的四种用途之一

OK6410A 开发板 (八) 102 linux-5.11 OK6410A glibc提供的mmap的四种用途之一

2023-11-01 36浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。

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);

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