linux中断&poll&selcet按键处理机制

2023-05-16

在上一篇linux按键中断处理中,我们采用按键中断处理获取按键,在read函数中阻塞读取,当按键发生时,read自动解除阻塞,实现应用层读取到相应的按键值。在上一节中如果没有按键到来,应用层会一直阻塞等待在read 函数中。本博客页尝试使用按键中断加poll和selcet机制的方式这个处理。实现在应用层,阻塞指定的时间,如果没有信息返回,就主动退出阻塞等待。

先贴一段代码:

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>


/* forthdrvtest 
  */
int main(int argc, char **argv)
{
	int fd;
	unsigned char key_val;
	int ret;

	struct pollfd fds[1];
	
	fd = open("/dev/buttons", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	}

	fds[0].fd     = fd;
	fds[0].events = POLLIN;
	while (1)
	{
		ret = poll(fds, 1, 5000);
		if (ret == 0)
		{
			printf("time out\n");
		}
		else
		{
			read(fd, &key_val, 1);
			printf("key_val = 0x%x\n", key_val);
		}
	}

	return 0;
}

----------------------------------我是漂亮的分割线-----------------------------------------------------------------------------------------
 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>


static struct class *forthdrv_class;
static struct class_device	*forthdrv_class_dev;

volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;

volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;


static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
static volatile int ev_press = 0;


struct pin_desc{
	unsigned int pin;
	unsigned int key_val;
};


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;

struct pin_desc pins_desc[4] = {
	{S3C2410_GPF0, 0x01},
	{S3C2410_GPF2, 0x02},
	{S3C2410_GPG3, 0x03},
	{S3C2410_GPG11, 0x04},
};


/*
  * 确定按键值
  */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	struct pin_desc * pindesc = (struct pin_desc *)dev_id;
	unsigned int pinval;
	
	pinval = s3c2410_gpio_getpin(pindesc->pin);

	if (pinval)
	{
		/* 松开 */
		key_val = 0x80 | pindesc->key_val;
	}
	else
	{
		/* 按下 */
		key_val = pindesc->key_val;
	}

    ev_press = 1;                  /* 表示中断发生了 */
    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

	
	return IRQ_RETVAL(IRQ_HANDLED);
}

static int forth_drv_open(struct inode *inode, struct file *file)
{
	/* 配置GPF0,2为输入引脚 */
	/* 配置GPG3,11为输入引脚 */
	request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
	request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
	request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
	request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);	

	return 0;
}

ssize_t forth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	if (size != 1)
		return -EINVAL;

	/* 如果没有按键动作, 休眠 */
	wait_event_interruptible(button_waitq, ev_press);

	/* 如果有按键动作, 返回键值 */
	copy_to_user(buf, &key_val, 1);
	ev_press = 0;
	
	return 1;
}


int forth_drv_close(struct inode *inode, struct file *file)
{
	free_irq(IRQ_EINT0, &pins_desc[0]);
	free_irq(IRQ_EINT2, &pins_desc[1]);
	free_irq(IRQ_EINT11, &pins_desc[2]);
	free_irq(IRQ_EINT19, &pins_desc[3]);
	return 0;
}

static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
	poll_wait(file, &button_waitq, wait); // 不会立即休眠

	if (ev_press)
		mask |= POLLIN | POLLRDNORM;

	return mask;
}



static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open    =  forth_drv_open,     
	.read	 =	forth_drv_read,	   
	.release =  forth_drv_close,
	.poll    =  forth_drv_poll,
};


int major;
static int forth_drv_init(void)
{
	major = register_chrdev(0, "forth_drv", &sencod_drv_fops);

	forthdrv_class = class_create(THIS_MODULE, "forth_drv");

	forthdrv_class_dev = class_device_create(forthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
	gpfdat = gpfcon + 1;

	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
	gpgdat = gpgcon + 1;

	return 0;
}

static void forth_drv_exit(void)
{
	unregister_chrdev(major, "forth_drv");
	class_device_unregister(forthdrv_class_dev);
	class_destroy(forthdrv_class);
	iounmap(gpfcon);
	iounmap(gpgcon);
	return 0;
}


module_init(forth_drv_init);

module_exit(forth_drv_exit);

MODULE_LICENSE("GPL");

比较分析上一个博文,这俩个博文都使用了了

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
说明,我们在做阻塞等待时,会需要一个等待队列。在上一节中,我们在驱动read函数中,做了等待。然而在此处read并没有等待。那么为了完成我们阻塞等待,我们引进了poll机制。应用层使用poll函数调用内核的sys_poll函数,然后将当前进程塞入到等待队列中,再去调用驱动的poll函数,检测poll函数是否返回非0。如果返回值非0,不进入阻塞,直接返回应用层。倘若,返回值为0则进入阻塞状态。我们可以看到驱动中static volatile int ev_press = 0;将中断跟poll串联起来了。因为在驱动中sys_poll中并不是立即休眠,先执行一遍poll函数。我们在poll函数必须加上当根据ev_press 的当前数值做出不同的返回值。在应用层的poll函数,不在此具体列举,可以通过man poll自己查看。

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux中断&poll&selcet按键处理机制 的相关文章

  • 打印堆栈指针的值

    如何在 Linux Debian 和 Ubuntu 中用 C 打印堆栈指针的当前值 我尝试谷歌但没有找到结果 一个技巧是简单地将本地地址作为指针打印出来 但它不可移植 甚至无法保证有效 void print stack pointer vo
  • 由于参数中有空格,Bash 脚本因未知选项而失败

    我正在尝试运行 aws create lambda 函数 事情的经过如下 eval aws lambda create function function name FUNCTION NAME runtime RUNTIME role RO
  • POSIX:FreeBSD 与 Linux 中的管道系统调用

    在 Linux 2 6 35 22 generic 中 man pipe指出 pipeline 创建一个管道 一个可用于进程间通信的单向数据通道 在 FreeBSD 6 3 RELEASE p5 中 man pipe指出 pipeline
  • 将尾部输出重定向到程序中

    我想使用 tail 作为标准输入向程序发送文本文件中的最新行 首先 我向程序回显一些每次都相同的输入 然后从输入文件发送尾部输入 该输入文件应首先通过 sed 处理 以下是我期望工作的命令行 但是当程序运行时 它只接收回显输入 而不接收尾部
  • Linux 缓冲区溢出环境变量

    我一直在审查不同类型的缓冲区溢出 并遇到了一个我不记得为什么会发生的问题 下面的代码是我尝试执行缓冲区溢出的程序 include
  • 获取当前时间(以小时和分钟为单位)

    我正在尝试从系统收集信息 并且需要获取当前时间 以小时和分钟为单位 目前我有 date awk print 4 输出如下 16 18 54 怎样才能把秒数去掉呢 提供格式字符串 date H M Running man date将给出所有格
  • Ubuntu 上的 Docker 无法连接到本地主机,但可以连接到其 IP

    我运行的是 Ubuntu 18 04 uname r 5 3 0 46 generic 我已经安装了docker docker version Docker version 19 03 8 build afacb8b7f0 我有一个简单的
  • 用于列出用户和组的 Python 脚本

    我正在尝试编写一个脚本 在自己的行上输出每个用户及其组 如下所示 user1 group1 user2 group1 user3 group2 user10 group6 etc 我正在为此用 python 编写一个脚本 但想知道如何做到这
  • 将 -1 作为文件描述符传递给 mmap

    我对 FC17 Linux 中的 ls 命令进行了 strace 以下是输出 execve usr bin ls ls 48 vars 0 brk 0 0x27c1000 mmap NULL 4096 PROT READ PROT WRIT
  • 在ubuntu 18.04上安装python 2.7

    有没有办法在 Ubuntu 18 04 上安装 Python 2 7 我尝试了这个命令 但它不起作用 sudo apt install python minimal 有没有办法手动安装 我尝试使用 python 2 7 作为不支持 pyth
  • 在 Ubuntu 上运行独立的 ASP.NET Core 应用程序

    我已经发布了一个 ASP NET Core 应用程序作为针对 Ubuntu 的独立应用程序 发布似乎工作正常 我已将这些文件复制到一台漂亮的 Ubuntu 机器上 现在 我如何运行我的应用程序 我的理解是 因为它是一个独立的 NET Cor
  • Node exec 无权执行脚本

    直到最近 它都运行良好 但是当我今天尝试使用它时 它无法正常运行 它返回以下错误 错误 命令失败 bin sh c home pi RPi Computer Power RPi Server routes scripts hash js 1
  • 在 Unix 中,我可以在目录中运行“make”而无需先 cd 到该目录吗?

    在 Unix 中 我可以运行make在没有的目录中cd首先进入该目录 make C path to dir
  • Web 本地应用程序 Apache:运行 shell 脚本

    我开发了一个 shell 脚本 我想用它创建一个 UI 我决定使用带有本地服务器的 Web 界面 因为我对 HTML PHP 的了解很少 比 QT 或 Java 的了解更多 我只是希望我的 html 可以在我的计算机上运行 shell 脚本
  • bash 或 sh 中的“=”和“==”运算符有什么区别

    我意识到 和 运算符都可以在 if 语句中使用 例如 var some string if var some string then doing something fi if var some string then doing some
  • MYSQL插入GB大小的巨大SQL文件

    我正在尝试创建 Wikipedia DB 副本 大约 50GB 但在处理最大的 SQL 文件时遇到问题 我使用 linux split 实用程序将 GB 大小的文件拆分为 300 MB 的块 例如 split d l 50 enwiki 2
  • 模拟用户输入以使用不同参数多次调用脚本

    我必须使用提供的脚本 该脚本在脚本运行时接受用户输入而不是参数 我无法解决这个问题 脚本的一个例子是 bin bash echo param one read one doSomething echo param two read two
  • C中的内存使用问题

    请帮忙 操作系统 Linux 其中 sleep 1000 中 此时 top 显示Linux任务 给我写了7 7 MEM使用 valgrind 未发现内存泄漏 我明白 写得正确 所有 malloc 结果都是 NULL 但是为什么这次 睡眠 我
  • 将一个文件写入.c中的另一个文件

    我有一个读取文件然后将其内容复制到另一个文件的代码 我需要使其仅复制每 20 个符号 然后跳过 10 个符号 然后再次跳过 20 个符号 依此类推 我必须使用 lseek 函数 但我不知道如何将所有这些放入循环中来执行此操作 main ar
  • 除了 iptables 之外还有数据包管理实用程序吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 Linux 实用程序 它可以根据一组规则更改网络数据包的有效负载 理想情况下 我会使用

随机推荐

  • 【新手】关于ros包安装时,提示找不到相应的ros包(unable to locate package ros- **** )

    我是在学习这个大佬的教程 xff1a 从零开始的ROS学习之仿真 43 SLAM https blog csdn net u011612364 article details 122147741 xff08 引用 xff09 时发现我自己出
  • c++实现守护进程

    概述 Linux Daemon xff08 守护进程 xff09 是运行在后台的一种特殊进程 它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件 约束 守护进程一般在系统启动时开始运行 xff0c 除非强行终止 xff0c 否
  • linux C++ 环境下的ActiveMQ学习

    ActiveMQ 1 概述 ActiveMQ 是Apache出品 xff0c 最流行的 功能强大的即时通讯和集成模式的开源服务器 ActiveMQ 是一个完全支持JMS1 1和J2EE 1 4规范的 JMS Provider实现 提供客户端
  • Django与mysql建立长连接

    问题 xff1a 每次请求操作mysql数据库都会从新创建一个connect实例 xff0c 大大降低了数据处理的效率 还是django不够熟悉 解决办法 xff1a 自Django1 6版本后 xff0c 官方提供支持长连接 xff0c
  • Python ActiveMQ 消费者实现

    encoding utf 8 import stomp import sys import thread Create your tests here topic name 61 39 topic your topic name 39 br
  • Django 服务启动2次问题

    首先 xff0c 我们的操作如下 xff1a 一 命令行的启动服务 xff1a python manage py runserver 0 0 0 0 8000 二 服务启动行为 try os environ setdefault 34 DJ
  • Django settings.py配置总结

    1 版本 xff1a 1 8 9 2 解决数据库时间和当前系统时间不一致问题 设置USE TZ 61 False 3 时区配置 xff1a TIME ZONE 61 39 Asia Shanghai 39 4 静态文件js css等的引用路
  • Extern关键字在vscode中不生效的解决办法

    今天回顾extern关键字的时候遇到一个问题 a c里的代码 b c里的代码 这么简单的几个代码 vscode竟然给我报错 为什么 抱着这个问题去逛了下csdn 终于让我找到了问题所在 原来vscode默认只能对单文件编译 即使俩文件在同一
  • 头文件、源文件 及extern的使用

    头文件与源文件的作用 1 编译器的工作过程 简单的说其实要理解C文件与头文件 xff08 即 h xff09 有什么不同之处 xff0c 首先需要弄明白编译器的工作过程 xff0c 一般说来编译器会做以下几个过程 xff1a 1 预处理阶段
  • 从零开始的三维激光雷达SLAM教程第二讲(搭建Gazebo仿真环境,并添加动态障碍物)

    文章目录 引言第二节 xff1a 搭建仿真环境下载velodyne激光模拟功能包安装turtlebot3模拟器安装三维激光雷达到turtlebot3上构建Gazebo地图添加动态障碍物操作机器人建图最终效果 引言 毕业设计打算做三维激光SL
  • 一个简单的基础通信协议的设计与实现

    一个简单的基础通信协议的设计与实现 一种常见的通信协议格式搭建串口收发环境配置STM32CubeMX添加USART部分代码 通信协议的实现 不同设备之间的通信 xff0c 都需要设计自己的通信协议 为了保证设备与设备之间的数据的稳定传输 x
  • 串口调试助手之间通信和接受、发送数据

    最近在用串口调试助手的时候在网上找了好多资料和教程都没有一个完整的 xff0c 就来写个完整的串口调试助手资料给刚入门或者刚接触的小白 xff0c 希望有所帮助 xff01 1 准备好串口调试助手 和 虚拟串口驱动 软件VirtualSer
  • win10下vs2019编译使用boost库v1_75_0

    boost介绍 Boost库是为C 43 43 语言标准库提供扩展的一些C 43 43 程序库的总称 boost是一个准标准库 xff0c 相当于STL的延续和扩充 xff0c 它的设计理念和STL比较接近 xff0c 都是利用泛型让复用达
  • vscode格式化C++代码方法

    参考 xff1a https blog csdn net wydxry article details 125191171 格式操作 解决方法 xff1a 按下组合键ctrl 43 shift 43 p 在弹出的搜索窗口中输入format
  • OpenCV基本介绍和安装

    OpenCV是一个通用 开源 功能强大的图像处理和计算机视觉库 官方网站 xff1a Home OpenCV 1999年 加里 布拉德斯基在Intel公司创建了计算机视觉库 xff08 Computer Vision Library xff
  • java jni ubuntu 环境搭建时遇到的坑

    1 xff1a 版本不一致遇到的坑 javah的版本需要同javac的版本一致 如果版本的问题搞不定 xff0c 直接用andorid source build之后的环境即可 2 xff1a javah使用遇到的坑 jni中字段描述符可以使
  • jni中native通过adb输出

    本文主要实践了如何在jni中打印log xff0c 贴源码 xff1a Android mk主要是巴拉的android源码中的app LOCAL PATH 61 call my dir include CLEAR VARS TARGET P
  • 关于服务器端用C语言实现TCP的数据接收

    关于这个 xff0c 真的是踩过很多坑 xff0c 罗列了一下要注意的点 xff1a 代码前面一定要添加库 xff0c 不然会出很多错 pragma comment lib 34 Ws2 32 lib 34 这段代码在vs2017中怎么也编
  • linux中断&poll&selcet按键处理机制

    在上一篇linux按键中断处理中 xff0c 我们采用按键中断处理获取按键 xff0c 在read函数中阻塞读取 xff0c 当按键发生时 xff0c read自动解除阻塞 xff0c 实现应用层读取到相应的按键值 在上一节中如果没有按键到
  • linux中断&poll&selcet按键处理机制

    在上一篇linux按键中断处理中 xff0c 我们采用按键中断处理获取按键 xff0c 在read函数中阻塞读取 xff0c 当按键发生时 xff0c read自动解除阻塞 xff0c 实现应用层读取到相应的按键值 在上一节中如果没有按键到