暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一起撸linux内核20-字符设备构建消息队列(01)

囧囧妹 2022-03-10
174

点击上方蓝字【囧囧妹】一起学习,一起成长!

一、开篇

接上一节一起撸linux内核19-io多路复用之总结。我们前面说了字符设备、链表、同步和锁、IO多路复用,然后回到最初的目的,我们想构建一个消息队列用于用户态各个进程、线程间的通信。从这节开始,我之前也没有做过,所以可以一起来做。

二、构思


我们的构思大概是这样的,后面也可能会大幅度来调整,我们创建一个全局的设备类,该设备类下创建256个字符设备,每个字符设备我们绑定一个channel,channel下面可以放n个消息元素。

我们通过open来打开一个channel,read、write分别进行消息的读写,close关闭这个channel,poll用来让进程或者线程来监听消息的到达。至于ioctl我们是想调整channel内的消息优先级。

大致的一个思路就是这样子,可能在后面实现的过程中会有调整。


三、代码部分
我现在先把字符设备驱动的框架搭建起来,只定义了字符设备相关的数据,关于消息的数据还没有定义。
代码放到https://gitee.com/sunnyshare/linux-examplecode.git,因为gitee需要注册,github我这里网络不行,所以我打了个包放到了百度云盘,有需要的可以点击上方囧囧妹进行关注回复“msg”来获取。
这里只说几个函数吧。
    /** @brief msg_init
    * 模块初始化函数
    * @param
    * @param
    * @return 0-成功;其它错误码
    * @discri
    * @note
    */
    static int __init msg_init(void){
    u32 ret = 0;

    //申请一个全局chan
    pcalloc(get_globalchan(chan), sizeof(chan_st), chan_st);
    //申请一个字符设备
    ret = alloc_chrdev_region(&get_globalchan(chan)->devno, 0, CHANNEL_MAX, CHANNEL_NAME);
    if(ret != 0){ pfree(get_globalchan(chan)); get_globalchan(chan) = nil; return ret; } //释放pchan


    do{
    //初始化
    cdev_init(&(get_globalchan(chan)->cdev), &chan_fops);

    //添加到内核
    ret = cdev_add(&(get_globalchan(chan)->cdev), get_globalchan(chan)->devno, CHANNEL_MAX);
    if(ret < 0){ cdev_del(&(get_globalchan(chan)->cdev)); break; }


    get_globalchan(chan)->dev_class = class_create(THIS_MODULE, CHANNEL_NAME);
    if(IS_ERR(get_globalchan(chan)->dev_class)){
    kernel_print(KERN_ERR "Unable create sysfs class for demo\n");
    ret = PTR_ERR(get_globalchan(chan)->dev_class);
    break;
    }
    //将所有字符设备创建出来
    chan_create();
    return 0;
    }while(0);


    unregister_chrdev_region(get_globalchan(chan)->devno, CHANNEL_MAX);
    pfree(get_globalchan(chan));
    get_globalchan(chan) = nil;


    return -1;
    }
    模块注册函数就是我们按着之前字符设备的步骤来进行申请和注册。这里我们还通过class_create来创建了一个设备类,主要用于我们在驱动内部就在用户态创建好我们需要的256个字符设备,无需再通过指令mknod dev/chan_0 c 238 0 来创建。
    创建设备的函数如下:
      /** @brief chan_create
      * 创建字符设备
      * @param
      * @param
      * @return 0-成功;其它错误码
      * @discri
      * @note
      */
      static int chan_create(void){
      u32 i = 0;


      //分配所有通道
      get_globalchan(chan)->chan_count = CHANNEL_MAX;
      pcalloc(get_globalchan(chan)->chan_item, \
      get_globalchan(chan)->chan_count * sizeof(chan_item_st), \
      chan_item_st);


      for_zero_travel(i, CHANNEL_MAX){
      //创建设备节点
      get_globalchan(chan)->chan_item[i].devno = MKDEV(MAJOR(get_globalchan(chan)->devno), i);
      get_globalchan(chan)->chan_item[i].minor = i;
      device_create(get_globalchan(chan)->dev_class, nil, \
      get_globalchan(chan)->chan_item[i].devno, \
      nil, "%s_%d", CHANNEL_NAME, i);
      }


      return 0;
      }
      目前主要完成的就是这两个函数,其它就是模块卸载,一些释放操作等,具体可以看源码。

      四、编译运行
      make后直接insmod查看/dev/下是否有256个chan_x文件。

      卸载rmmod msg后查看/dev/下的chan_x文件是否还存在。


      今天先到这,明早继续。

      觉得不错,点击“分享”,“赞”,“在看”传播给更多热爱嵌入式的小伙伴吧!
      文章转载自囧囧妹,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论