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

发布者:HarmonySpirit最新更新时间:2022-08-15 来源: csdn关键字:OK6410A  开发板  mmap 手机看文章 扫描二维码
随时随地手机看文章

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

[1] [2]
关键字:OK6410A  开发板  mmap 引用地址:OK6410A 开发板 (八) 102 linux-5.11 OK6410A glibc提供的mmap的四种用途之一

上一篇:OK6410A 开发板 (八) 104 linux-5.11 OK6410A mmap四种用途参数及扩展
下一篇:OK6410A 开发板 (八) 101 linux-5.11 OK6410A printf 在 glibc 和 linux 中的流程

推荐阅读最新更新时间:2024-11-08 07:18

MEGA16游戏开发板驱动
#include iom16v.h #include macros.h #define uchar unsigned char #define uint unsigned int #pragma interrupt_handler power_off:2 #define EN_ PORTB&=~BIT(2) #define EN PORTB|=BIT(2) #define LE PORTB|=BIT(3) //高电平选通573 #define LE_ PORTB&=~BIT(3) //低电平锁存573 #define LEDEN PORTB|=BIT(4) //高电平选通led10 #define LEDEN_ PORTB&=~
[单片机]
OK6410A 开发板 (三) 7 u-boot-2021.01 boot 解析 u-boot 与linux配置部分
U-boot配置 make O=output ok6410a_mini_defconfig // 在配置的时候 不需要指定 ARCH(因为defconfig有写) 与 CROSS_COMPILE(因为现在并不需要,build的时候才需要) // 如果写了CROSS_COMPILE,会去检查CROSS_COMPILE , 然后build的时候还是需要写 // 第一次用arm-gcc 的时刻, 编译时 的 CC lib/asm-offsets.s make : Entering directory '/home/suws/ok6410/system-new/u-boot/output' HOSTCC scri
[单片机]
《如何制作STM32开发板》之通信接口部分
上一篇文章,我们规划了一下STM32开发板串口(UART),这一篇文章介绍剩下的通信接口。我们在第一课画STM32F103VET6单片机原理图的时候,我们就看到,它除了UART,还有SPI、CAN、I2C等通信接口。 一个单片机,为什么会有这么多的通信接口?一种接口不够用么!这是一部分小伙伴的疑问。 基于单片机的电子产品,从简单的到复杂的,基本上没有只用单片机就可以完成了。这一点,大家在看到很多电子产品的电路板之后就发现了,上面有若干个芯片。带有单片机的电路板上,其他的芯片都被称作单片机的外围芯片。 根据不同的应用,有不同的外围芯片。这些外围芯片有很多种,例如加速度传感器芯片、数字收音机芯片、存储芯片、无线通信芯片、放大器芯片、温
[单片机]
《如何制作STM32<font color='red'>开发板</font>》之通信接口部分
FPGA开发板远程检测系统的实现
1系统概述 目前FPGA开发板的板载资源检测都是采用将示例下载到开发板上检测的方法,检测不同的资源需要一般使用不同的示例。这样的检测方法缺少对检测结果信息的收集。对于实验室批量管理FPGA开发板的情况,难以应对。 本系统基于Nexys 3 Spartan-6 FPGA开发板,不仅可对该开发板的板载资源进行检测,并且可以对检测结果数据进行收集,将收集的数据进行保存以方便诊断开发板的状态。 其原理是由上位机通过串口发送测试数据到开发板上的串口模块,FPGA从串口模块得到相应的测试命令,然后根据命令,对开发板上对应的资源进行检测,并将检测结果反馈到上位机进行保存。 本系统的结构示意图如下所示。 图1系统结构示意图
[测试测量]
FPGA<font color='red'>开发板</font>远程检测系统的实现
S3C2440开发板文件传输
看着教程里的各种软件,真是晕的不行,好好整理。 一、空白开发板第一步---写bootloader 类似于给电脑装系统,不装系统就是一块集成电路板,鸟用没有。bootloader就等价于bios,常用的bootloader有U-BOOT、supervivi(改进的vivi,加了一个usb下载功能而已)。工具是真的多,各种开发板制作商家都可能开发出自己的一套下载工具,五花八门,想想刚开始接触的时候,试工具都试了几天,想想也是心累,区分一下各种名词: 1、JTAG 开发板在没有写任何系统时,里面啥驱动都没有,芯片是啥都不会认的,usb、串口接了也不会有反应。还好有JTAG协议,原本是用来做芯片测试的,这里拿来写引导程序。 2、JLINK
[单片机]
玩转mini2440开发板之【编译u-boot提示没有规则可以创建“XX.o”需要的目标】
今天继续玩一玩mini2440开发板的u-boot的编译和下载。 首先,交代一下背景,我下载的是tekkamanninja大神于2010.03移植过来的mini2440定制版的u-boot(可以直接去https://github.com/tekkamanninja/u-boot-tekkamanninja/tree/v2010.03_mini2440_tekkamanninja下载,也可以用git clone命令从https://github.com/tekkamanninja/u-boot-tekkamanninja.git处获取)。当然,具体的详细步骤,也可直接参考我另一篇博客的记录:玩转mini2440开发板之【tek
[单片机]
ATmega16开发板教程(3)——74HC595驱动数码管显示
4、数码管显示 数码管驱动电路采用2片74HC595芯片进行IO扩展,仅仅只需3Pin即可驱动需要16位引脚的数码管。74HC595是一个8位串行输入、并行输出的位移缓存器。 只有对74HC595的工作原理和时序要了解清楚,才能更好的理解和编程。 工作原理: Ø1、74HC595是串行输入,即将一个字节Byte的数据通过8次以高低电平的形式送到数据引脚DS,且高字节先入,低字节后入,类似于堆栈; Ø2、那么数据什么时候进入呢?需要SCK(SH_CP)时钟上升沿来讲8位bit数据移入到移位寄存器中; 直接编程讲解: 如图,首先假设wei变量=01101001,然后取出最高位,那么&0x80,得到0,那么执行e
[单片机]
ATmega16<font color='red'>开发板</font>教程(3)——74HC595驱动数码管显示
搭建 S3C6410开发板的测试环境
S3C6410 是由三星公司推出的低功耗、高性价比的 SC ( reduced instruction set computer,精简指令集计算机〉处理器,它基于 ARMII 内核( ARMl76JZF-S),可广泛应用于移动电话和通用处理等领域。 (1)安装串口调试工具minicom 1.检测当前系统是否支持USB转串口 # Ismod I grep usbserial 2.安装 minicom # apt-get install minicom 3.配置minicom # minicom -s 4.测试minicom # minicom (2)使用E b o o t擦除N a n d F l a s h 1.用串口线或USB
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved