当前位置: 首页 > news >正文

Linux驱动学习之内核poll阻塞

在linux系统编程课程中学习过多路IO复用,简单来说就三个函数select,poll,epoll。

对于select

        此函数是跨平台的,可以在windows,Linux中使用。

对于poll与epoll

        只能在linux平台下使用,

        epoll底层实现是一个红黑树,效率高,检测的文件更多。

这三个函数可以实现并发。

前面的章节中讲了,等待队列用于内核与上层的数据同步,现在我们来实现内核poll与上层的数据同步。

通过前面我们知道,内核驱动中,如果read函数中没有阻塞,上层read就没有阻塞,可是在linux系统编程课中,明明学习的read函数是阻塞的,这里可以大胆的猜测,系统编程实在别人写好的驱动上运行的,他内核驱动内部实现了read的阻塞。

本章学习内核poll机制,学完对理解linux系统编程多路io复用有很大帮助。

  • 内核poll的实现

在文件操作结构体中有一个poll函数,我们实现这个函数,并在这个函数中实现阻塞,那么上层调用这个函数就会调用上册函数阻塞。

那么poll阻塞是怎么实现的呢。

  • poll阻塞的实现
  1. 在poll函数里调用 poll_wait()函数。
  2. 在合适的情况下返回合适的值。

当然内核poll阻塞是靠等待队列实现的,所以,要在需要地方唤醒。

  • API函数
 void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{

参数1:poll函数的第一个参数,

参数2:等待队列地址

参数3:poll函数第二个参数

  • 整体实现

在其他地方调用,并设置cond=1;当然也得在别的地方把cond变为0,不然就只在开头阻塞一次

  • 读取按键整体代码
#include "linux/cdev.h"
#include "linux/device.h"
#include "linux/device/class.h"
#include "linux/poll.h"
#include "linux/export.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/module.h"
#include "linux/of_device.h"
#include "linux/of_gpio.h"
#include "linux/platform_device.h"
#include "linux/poll.h"
#include "linux/printk.h"
#include "linux/timer.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/wait.h"
#include "linux/zconf.h"
uint32_t pin;
dev_t dev_num;
struct cdev *cdev;
struct class *cls;
struct device * dev;
uint8_t cond;
struct timer_list timer;DECLARE_WAIT_QUEUE_HEAD(queue);
uint8_t val;
irqreturn_t fun(int i, void * a)
{val=gpio_get_value(pin);printk("%d\r\n",val);mod_timer(&timer, jiffies+msecs_to_jiffies(10));return 0;
}
static ssize_t read(struct file *f, char __user *b, size_t s, loff_t *offt)
{cond=0;// wait_event_interruptible(queue,cond);int a=copy_to_user(b,&val,1);if(a){}return 0;
}
static int open(struct inode *i, struct file *f)
{int ret=devm_request_irq(dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);printk("%d\r\n",ret);return ret;
}
static int close(struct inode *i, struct file *f)
{devm_free_irq(dev,gpio_to_irq(pin),NULL);return 0;
}
__poll_t poll (struct file *f, struct poll_table_struct *p)
{poll_wait(f, &queue, p);if(cond==1){return EPOLLIN;}return 0;
}
struct file_operations fops={.owner=THIS_MODULE,.read=read,.open=open,.release=close,.poll=poll,
};
void func(struct timer_list *tl)
{wake_up_interruptible(&queue);cond=1;
}
int probe(struct platform_device *d)
{timer_setup(&timer, func, 0);dev=&d->dev;pin=of_get_named_gpio(d->dev.of_node,"key_pin",0);printk("%d\r\n",pin);printk("%d\r\n", platform_get_irq(d,0));printk("irq_num=%d", gpio_to_irq(pin));gpio_request(pin,"key");gpio_direction_input(pin);// devm_request_irq(&d->dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);alloc_chrdev_region(&dev_num, 0, 1,"key");cdev=cdev_alloc();cdev->ops=&fops;cdev_add(cdev,dev_num,1);cls=class_create(THIS_MODULE, "key");device_create(cls, NULL,dev_num,NULL,"key");return 0;
}
int remove(struct platform_device *d)
{return 0;
}
static struct of_device_id match={.compatible="key",
};static struct platform_driver driver={.probe=probe,.remove=remove,.driver={.name="key",.of_match_table=&match,},
};
static int __init start(void)
{platform_driver_register(&driver);printk(KERN_INFO "Hello, world!\n");return 0;
}
static void __exit stop(void)
{platform_driver_unregister(&driver);printk(KERN_INFO "Goodbye, world!\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL");

 补充,上面列子只在poll中实现阻塞,当然也可以自己增加逻辑让在read和epoll中都阻塞,就能实现在系统编程中,多路io复用让夜歌poll监控所有文件描述符,当不用多路io复用,read照样阻塞。


http://www.mrgr.cn/news/14716.html

相关文章:

  • 【C++ Primer Plus习题】6.5
  • 【项目日记】高并发内存池项目---整体框架设计
  • 鸿蒙ArkTS语言学习(五):扩展(函数)@Extend@Styles@Builder
  • 你的软件系统安全吗
  • class 2: vue.js 3 模板语法和内置指令
  • 在C语言中使用POSIX线程库(pthread)实现多线程编程
  • Amazon Bedrock 实践:零基础创建贪吃蛇游戏
  • 计算机毕业设计选题推荐-Cosplay论坛系统-Java/Python项目实战
  • gNB UE发送Timing AdvanceCommand
  • 闲置物品|基于SprinBoot+vue的校园闲置物品交易平台(源码+数据库+文档)
  • OpenCV绘图函数(7)从一个椭圆定义中提取出多边形的顶点坐标函数ellipse2Poly()的使用
  • golang私有仓库遇到的问题记录
  • 搜维尔科技:使用MANUS VR手套控制特斯拉机器人叠衣服操作
  • 人工智能 | 实现定制化 AutoGPT 实战
  • Vue.js 起步
  • 数据结构——栈
  • 保证MQ的高可用性:RabbitMQ为例
  • JAVA中如何使用反射获取数组元素类型
  • 谷粒商城实战笔记-277~278-商城业务-订单服务-构造订单和订单明细
  • 基于FPGA的SD NAND Flash数据读写实现