fasync driver demo

news/2024/11/19 19:34:06/

Linux系统中的fasync用于设备驱动程序与用户空间之间的异步通信。它允许设备驱动程序通知用户空间的进程,当设备状态发生变化时,通过发送SIGIO信号来告知进程。

具体来说,设备驱动程序可以调用fasync_helper()函数来注册一个或多个进程,当设备状态发生变化时,内核会自动发送SIGIO信号给这些进程。而用户空间进程可以通过调用fcntl()函数,并设置F_SETOWN标志来接收SIGIO信号。一旦接收到SIGIO信号,进程就可以执行相应的处理操作,如读取设备数据或进行其他操作。

通过使用fasync,设备驱动程序可以避免阻塞用户进程,可以实现非阻塞I/O操作,提高系统的响应性能。

下面实现的是打开设备文件并启用异步通知功能,然后进入一个无限循环中,等待接收SIGIO信号的触发。当设备发生变化时,设备驱动程序会发送SIGIO信号给这个用户空间程序,触发fasync_handler函数的执行,从而可以进行相应的处理操作。

#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<linux/rtc.h>
#include<linux/ioctl.h>
#include<stdio.h>
#include<stdlib.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>int fd;
void fasync_handler(int num)
{printf("fasync_handler entering\n");
}void main()
{int i=2;char data[256];int oflags=0;int retval;signal(SIGIO, fasync_handler);fd=open("/dev/fcn",O_RDWR);if(fd==-1){perror("error open\n");exit(-1);}printf("open /dev/fcn successfully\n");//使能了异步的通知到当前进程fcntl(fd, F_SETOWN, getpid());oflags=fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, oflags | FASYNC);while(1);close(fd);
}

demo.c ​​​​​​​

  1. 下面代码定义了一个名为simple_dev的结构体,用于表示设备的相关信息。在模块加载时,通过register_chrdev_region()函数请求一个主设备号。

  2. 创建并初始化一个simple_dev结构体,然后通过cdev_init()函数对其进行初始化。

  3. 调用cdev_add()函数将字符设备添加到系统中。定义了简单的设备操作函数,包括打开设备(simple_open)、关闭设备(simple_release)和异步通知(simple_fasync)。

  4. 初始化一个定时器simple_timer,当时间到达时,会调用simple_timer_handler函数。

  5. 在simple_open函数中,将定时器添加到内核定时器列表中,并启动定时器。

  6. 在simple_fasync函数中,通过fasync_helper函数将当前进程添加到异步通知队列fasync_queue中。

  7. 在simple_release函数中,调用simple_fasync函数取消异步通知。

  8. 模块卸载时,通过cdev_del()函数删除字符设备,释放相关资源。


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/delay.h>#include <asm/io.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/uaccess.h>#include "demo.h"MODULE_AUTHOR("fgj");
MODULE_LICENSE("Dual BSD/GPL");struct simple_dev *simple_devices;
static unsigned char simple_inc=0;
static struct timer_list simple_timer;
static struct fasync_struct *fasync_queue=NULL;static void simple_timer_handler( unsigned long data)
{printk("simple_timer_handler...\n");if (fasync_queue){//POLL_IN可读,POLL_OUT为可写kill_fasync(&fasync_queue, SIGIO, POLL_IN);printk("kill_fasync...\n");}return ;
}int simple_open(struct inode *inode, struct file *filp)
{struct simple_dev *dev;dev = container_of(inode->i_cdev, struct simple_dev, cdev);filp->private_data = dev;simple_timer.function = &simple_timer_handler;simple_timer.expires = jiffies + 2*HZ;add_timer (&simple_timer);printk("add_timer...\n");return 0;
}static int simple_fasync(int fd, struct file * filp, int mode) 
{int retval;printk("simple_fasync...\n");retval=fasync_helper(fd,filp,mode,&fasync_queue);if(retval<0)return retval;return 0;
}int simple_release(struct inode *inode, struct file *filp)
{simple_fasync(-1, filp, 0);return 0;
}struct file_operations simple_fops = {.owner =    THIS_MODULE,.open =     simple_open,.release=   simple_release,.fasync=    simple_fasync,};/*******************************************************MODULE ROUTINE
*******************************************************/
void simple_cleanup_module(void)
{dev_t devno = MKDEV(simple_MAJOR, simple_MINOR);if (simple_devices) {cdev_del(&simple_devices->cdev);kfree(simple_devices);}unregister_chrdev_region(devno,1);
}int simple_init_module(void)
{int result;dev_t dev = 0;dev = MKDEV(simple_MAJOR, simple_MINOR);result = register_chrdev_region(dev, 1, "DEMO");if (result < 0) {printk(KERN_WARNING "DEMO: can't get major %d\n", simple_MAJOR);return result;}simple_devices = kmalloc(sizeof(struct simple_dev), GFP_KERNEL);if (!simple_devices){result = -ENOMEM;goto fail;}memset(simple_devices, 0, sizeof(struct simple_dev));cdev_init(&simple_devices->cdev, &simple_fops);simple_devices->cdev.owner = THIS_MODULE;simple_devices->cdev.ops = &simple_fops;result = cdev_add (&simple_devices->cdev, dev, 1);if(result){printk(KERN_NOTICE "Error %d adding DEMO\n", result);goto fail;}init_timer(&simple_timer);return 0;fail:simple_cleanup_module();return result;
}module_init(simple_init_module);
module_exit(simple_cleanup_module);

demo.h

#ifndef _simple_H_
#define _simple_H_#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later *//********************************************************* Macros to help debugging********************************************************/
#undef PDEBUG             /* undef it, just in case */
#ifdef simple_DEBUG
#ifdef __KERNEL__
#    define PDEBUG(fmt, args...) printk( KERN_DEBUG "DEMO: " fmt, ## args)
#else//usr space
#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#endif
#else
#  define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif#undef PDEBUGG
#define PDEBUGG(fmt, args...) /* nothing: it's a placeholder *///设备号
#define simple_MAJOR 226
#define simple_MINOR 0
#define COMMAND_LEDON 1
#define COMMAND_LEDOFF 2//设备结构
struct simple_dev 
{struct cdev cdev;	  /* Char device structure		*/
};//函数申明
ssize_t simple_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos);
ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos);
loff_t  simple_llseek(struct file *filp, loff_t off, int whence);
int     simple_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg);#endif /* _simple_H_ */

上述代码的实现了一个简单的字符设备驱动程序,并使用定时器实现了异步通知功能,通过调用fasync_helper函数将进程添加到异步通知队列中,当定时器时间到达时,会发送SIGIO信号给进程,以实现类似中断的功能。 


http://www.ppmy.cn/news/981579.html

相关文章

自然语言处理从入门到应用——LangChain:模型(Models)-[文本嵌入模型Ⅱ]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 本文将介绍如何在LangChain中使用Embedding类。Embedding类是一种与嵌入交互的类。有很多嵌入提供商&#xff0c;如&#xff1a;OpenAI、Cohere、Hugging Face等&#xff0c;这个类旨在为所有这些提供一个标准接口。 …

JAVA面试总结-Redis篇章(五)——持久化

Java面试总结-Redis篇章&#xff08;五&#xff09;——持久化 1.RDBRDB全称Redis Database Backup file (Redis数据备份文件)&#xff0c;也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后&#xff0c;从磁盘读取快照文件&#x…

英语学习相关资源

学习建议 学习英语和口语需要付出一定的努力和时间。以下是一些学习英语和口语的建议&#xff1a; 学习基础词汇和语法&#xff1a;学习英语的第一步是掌握基础词汇和语法。可以通过阅读英语书籍、听英语音频和观看英语视频来学习词汇和语法。 练习听力和口语&#xff1a;英语…

代码随想录day28

46. 全排列 思路&#xff1a;这道题首先是一个排列问题&#xff0c;排列问题是讲究顺序的&#xff0c;例如[1,2]和[2,1]是两个不一样的排列&#xff0c;这里的1我们会有重复使用到&#xff0c;但是&#xff0c;在每一个排列中&#xff0c;每一个元素只能使用一次。所以需要一个…

练习时长两年半的双机热备

1.双机热备技术产生的背景 传统的组网方式如下左图所示&#xff0c;内部用户和外部用户的交互报文全部通过防火墙A。如果防火墙A出现故障&#xff0c;内部网络中所有以防火墙A作为默认网关的主机与外部网络之间的通讯将中断&#xff0c;通讯可靠性无法保证。防火墙作为安全设备…

uniapp微信小程序scroll-view滚动scrollLeft不准确

今天在实现微信小程序的一个横向导航的时候出现了一个问题&#xff0c;就是每次滑到滚动条最右边的时候 scrollLeft的值都不准确 原因&#xff1a;因为每次滚动监听事件都会被调用比较耗费资源系统会默认节流&#xff0c;可以在scroll-view 加一个 throttle“{{false}}” 关闭…

【iOS】KVOKVC原理

1 KVO 键值监听 1.1 KVO简介 KVO的全称是Key-Value Observing&#xff0c;俗称"键值监听"&#xff0c;可以用于监听摸个对象属性值得改变。 KVO一般通过以下三个步骤使用&#xff1a; // 1. 添加监听 [self.student1 addObserver:self forKeyPath:"age"…

UE4/5C++多线程插件制作(十四、MTPAbandonable)

目录 MTPAbandonable h实现 cpp实现 MTPMarco.h 首先是异步任务的宏定义部分: