Linux的fasync驱动异步通知详解

fasync简介  fasync是指应用于系统调用signal和sigaction函数的中断机制。 简单的说,signal函数就是让一个信号与一个函数对应,每当接收到这个信号就会调用相应的函数。 那么什么是异步通知?异步通知类似于中断的机制,当设备可写时,设备驱动函数发送一个信号给内核,告知内核有数据可读,在条件不满足之前,并不会造成阻塞。而不像之前学的阻塞型IO和poll,它们是调用函数进去检查,条件不满足时还会造成阻塞。 使用方式: 其实在应用层启用异步通知只三个步骤: 1)signal(SIGIO, 阅读详情

工作项目用有个需求是监测某个GPIO输入方波的频率!通俗的讲就是一个最最简单的测方波频率的示波器!不过只是测方波的频率!频率范围是0~200HZ,而且频率方波不是一直都是200HZ,大多数的时候可能一直是0或者一个更低频率的方波!同时要考虑到方波有可能一直维持在200HZ ,同时保持效率和性能的情况下,fasync驱动异步通知是个不错的选择,当初写demo的时候实测1K的方波完全没有问题!应用到项目中也是完全能满足需求!驱动很简单!业余时间把自己之前学到的知识总结一下!对自己也是个提高!

根据需求,驱动中实现比较简单!自己只实现open、close、fasync和read函数 ,这里只需要读取方波的频率即可!

驱动大概实现原理:方波每产生一个下降沿,产生一个中断,然后根据中断在通过异步通知应用程序,以此来测定输入方波的频率!

fansync机制的优势是能使驱动的读写和应用程序的读写分开,使得应用程序可以在驱动读写的时候去做别的事情!

下面是驱动的源码:

**-------File Info---------------------------------------------------------------------------------------
** File Name:               gpioInt.c
** Latest modified Data:    2015_11_16
** Latest Version:          v1.0
** Description:             NOME
**
**--------------------------------------------------------------------------------------------------------
** Create By:               K
** Create date:             20015-11-16
** Version:                 v1.0
** Descriptions:            混杂设备驱动程序 GPIO中断驱动 下降沿触发GPIO 内核会向用户空间发送一个键值
**						    用户态的应用程序通过读取键值来判断GPIO中断状况
**
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
#include<linux/init.h>
#include<linux/module.h>
#include<mach/gpio.h>                                                  
#include<asm/io.h>                                                 
#include"mach/../../mx28_pins.h"
#include <mach/pinctrl.h>
#include "mach/mx28.h"
#include<linux/fs.h>
#include <linux/io.h>
#include<asm/uaccess.h>                                     
#include<linux/miscdevice.h>                          
#include<linux/irq.h>                          
#include<linux/sched.h>                   
#include<linux/interrupt.h>              
#include<linux/timer.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io.h>

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

/*
*异步结构体指针 用于读
*/
static struct fasync_struct *b_async;

/*
*中断引脚描述结构体
*/
struct pin_desc_s{				
	unsigned int pin;
	unsigned int key_val;
	unsigned int irq;
};
static unsigned char key_val;

struct pin_desc_s pin_desc[5] = {
	{MXS_PIN_TO_GPIO(PINID_LCD_ENABLE),0x03,},    /* IO1 rain GPIO1_31     */  
	{MXS_PIN_TO_GPIO(PINID_LCD_HSYNC),0x05,},     /* IO2 windspeed GPIO1_29*/
	{MXS_PIN_TO_GPIO(PINID_LCD_DOTCK),0x0A,},     /* 机箱门             */
	{MXS_PIN_TO_GPIO(PINID_AUART3_RX),0x07,},     /* key1 GPIO3_12         */ 
	{MXS_PIN_TO_GPIO(PINID_AUART3_TX),0x09,},     /* key2 GPIO3_13         */ 
};


static DECLARE_MUTEX(b_lock);     
static DECLARE_WAIT_QUEUE_HEAD(b_waitq);


static irqreturn_t b_irq(int irq, void *dev_id)
{
	struct pin_desc_s * pindesc = (struct pin_desc_s *)dev_id;
	unsigned int pinval;
	
	pinval = gpio_get_value(pindesc->pin);

	if (pinval)
	{
		key_val = 1;
	}
	else
	{
		key_val = pindesc->key_val;
	}
        ev_press = 1;
        wake_up_interruptible(&b_waitq);		//唤醒等待队列里面的进程
		kill_fasync(&b_async, SIGIO, POLL_IN);	//异步通知
	//printk("interrupt occur..........\n");
	return IRQ_RETVAL(IRQ_HANDLED);
}

static int gpio_drv_open(struct inode *inode, struct file *file)
{
	int iRet[5]={0};
	int i = 0;

	if (file->f_flags & O_NONBLOCK)
	{
		if (down_trylock(&b_lock))
			return -EBUSY;
	}
	else
	{
		down(&b_lock);
	}
	
	
	for(i = 0; i < 5; i++)
	{
		gpio_direction_input((pin_desc[i]).pin);
		(pin_desc[i]).irq = gpio_to_irq((pin_desc[i]).pin); 
		if ((pin_desc[i]).irq) 
			disable_irq((pin_desc[i]).irq);
		set_irq_type((pin_desc[i]).irq, IRQF_TRIGGER_FALLING);	//下降沿中断
		iRet[i] = request_irq((pin_desc[i]).irq, buttons_irq, IRQF_SHARED, "gpio_int", &pin_desc[i]);
		if (iRet[i] != 0){
			printk("request irq failed!! ret: %d  irq:%d \n", iRet[i],(pin_desc[i]).irq);
		return -EBUSY;}
	
	}
	
	
	return 0;
}

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

	if (file->f_flags & O_NONBLOCK)
	{
		if (!ev_press)
			return -EAGAIN;
	}
	else
	{
		wait_event_interruptible(b_waitq, ev_press);
	}
	copy_to_user(buf, &key_val, 1);
	ev_press = 0;
	
	return 1;
}

int gpio_drv_close(struct inode *inode, struct file *file)
{
	int i = 0;
	
	for( i = 0; i < 5; i++)
	{
		free_irq((pin_desc[i]).irq, &pin_desc[i]);
	}

	up(&b_lock);
	return 0;
}

static int gpio_drv_fasync (int fd, struct file *filp, int on)
{
	printk("driver: gpio_drv_successful\n");
	return fasync_helper (fd, filp, on, &b_async);
}

static struct file_operations gpio_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= gpio_drv_open,
	.read		= gpio_drv_read,
	.release	= gpio_drv_close,
	.fasync	 	= gpio_drv_fasync,
};

static struct miscdevice b_miscdev = 
{
	.minor	        = MISC_DYNAMIC_MINOR,
   	.name	        = "magic-gpio",
    .fops	        = &gpio_drv_fops,
};

static int __init gpio_drv_init(void)
{
	int iRet=0;
	printk("gpio_miscdev module init!\n");
	iRet = misc_register(&b_miscdev);
	if (iRet) {
		printk("register failed!\n");
	} 
	return 0;
}

static void __exit gpio_drv_exit(void)
{
	printk("gpio_miscdev module exit!\n");
	misc_deregister(&b_miscdev);
}

module_init(gpio_drv_init);
module_exit(gpio_drv_exit);

MODULE_AUTHOR("HEHAI & RK");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("gpio interrupt module");

首先还是先从init函数来总结:该驱动是一混杂设备驱动模型来写的,这个主要是借鉴网上的好多资料都是一这种模式来写的,Linux里面misc混杂设备驱动的主设备号是为10的驱动设备,init模块首先是用 misc_register()函数注册一个一个混杂设备驱动,参数一个混杂设备驱动里面非常重要的一个数据结构 struct miscdevice,下面把原型贴出来:

struct miscdevice  {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const char *nodename;
    mode_t mode;
};
当然我上面的驱动代码只初始化了前面的关键三项:

static struct miscdevice b_miscdev = 
{
	.minor	        = MISC_DYNAMIC_MINOR,
   	.name	        = "magic-gpio",
        .fops	        = &gpio_drv_fops,
};

这里先说说 .minor这个成员:定义次设备号的,这里使用了一个MISC_DYNAMIC_MINOR宏! 这个宏的意思就是动态分配次设备号!而且这个次设备号不会超过64!实现的方法比较巧妙!这里贴出一篇相关的文章:

http://blog.youkuaiyun.com/yongan1006/article/details/6778285 这个可以研究一下,还比较有意思!

剩下的两个name 和 fops成员对驱动开发来说就最熟悉不过了!驱动的名字和驱动的接口函数这里就不说了!

注册混杂设备驱动后就是接口函数的表演了!

这里和内核硬件相关的就是struct pin_desc_s 结构了,硬件的初始化工作比较简单,放在open函数里面了!

struct pin_desc_s pin_desc[5] = {
	{MXS_PIN_TO_GPIO(PINID_LCD_ENABLE),0x03,},    /* IO1 rain GPIO1_31     */  
	{MXS_PIN_TO_GPIO(PINID_LCD_HSYNC),0x05,},     /* IO2 windspeed GPIO1_29*/
	{MXS_PIN_TO_GPIO(PINID_LCD_DOTCK),0x0A,},     /* 机箱门             */
	{MXS_PIN_TO_GPIO(PINID_AUART3_RX),0x07,},     /* key1 GPIO3_12         */ 
	{MXS_PIN_TO_GPIO(PINID_AUART3_TX),0x09,},     /* key2 GPIO3_13         */ 
};

这里把好几个gpio接口都放到这一个里面了!都是后边加进去的!上面的是直接根据文档在内核头文件中找到GPIO引脚对应的宏定义的!后边是给GPIO设置的键值!就是当应用程序收到一个signal后,根据读取到的键值来区分是哪一个GPIO发生了中断或是有信号传过来!看看open函数:

static int gpio_drv_open(struct inode *inode, struct file *file)
{
	int iRet[5]={0};
	int i = 0;

	if (file->f_flags & O_NONBLOCK)//非阻塞
	{
		if (down_trylock(&b_lock))
			return -EBUSY;
	}
	else
	{
		down(&b_lock);
	}
	
	
	for(i = 0; i < 5; i++)
	{
		gpio_direction_input((pin_desc[i]).pin);//设置对应的GPIO输入
		(pin_desc[i]).irq = gpio_to_irq((pin_desc[i]).pin);//把GPIO对应的pin值转换为相应的IRQ值并返回
		if ((pin_desc[i]).irq) 
			disable_irq((pin_desc[i]).irq);//先关闭中断并等待中断处理完
		set_irq_type((pin_desc[i]).irq, IRQF_TRIGGER_FALLING);	//设置下降沿中断
		iRet[i] = request_irq((pin_desc[i]).irq, b_irq, IRQF_SHARED, "gpio_int", &pin_desc[i]);
		if (iRet[i] != 0){
			printk("request irq failed!! ret: %d  irq:%d \n", iRet[i],(pin_desc[i]).irq);
		return -EBUSY;}
	
	}
	
	
	return 0;
}


这里可以详细了解一下关于GPIO的一些API函数: http://blog.sina.com.cn/s/blog_a6559d9201015vx9.html

request_irq函数:http://blog.youkuaiyun.com/wealoong/article/details/7566546
说说上面的request_irq函数了:

int request_irq(unsigned int irq, irq_handler_t handler,
                         unsigned long irqflags, const char *devname, void *dev_id)
irq是要申请的硬件中断号。
handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
irqflags是中断处理的属性,SA_SHARED表示多个设备共享中断,
devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。
request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

这里用到回调函数b_irq函数就是根据响应的GPIO中断返回设置好的相应的值,这样应用程序在得到这个值的时候就可以知道是哪个GPIO发送的中断!

b_irq函数:

static irqreturn_t b_irq(int irq, void *dev_id)
{
	struct pin_desc_s * pindesc = (struct pin_desc_s *)dev_id;
	unsigned int pinval;
	
	pinval = gpio_get_value(pindesc->pin);

	if (pinval)
	{
		key_val = 1;
	}
	else
	{
		key_val = pindesc->key_val;
	}
        ev_press = 1;
        wake_up_interruptible(&b_waitq);		//唤醒等待队列里面的进程
		kill_fasync(&b_async, SIGIO, POLL_IN);	//异步通知
	//printk("interrupt occur..........\n");
	return IRQ_RETVAL(IRQ_HANDLED);
}
其中上面的b_waitq是这样定义的:

static DECLARE_WAIT_QUEUE_HEAD(b_waitq);//生成一个等待队列的头 名字为b_waitq
关于等待队列可以看下这篇文章: http://www.cnblogs.com/xmphoenix/archive/2011/11/20/2256419.html

其实这里有一个很关键的地方就是kill_fasync异步通知应用程序。这里有很关键的一步,可以说是整个驱动程序的核心:kill_fasync 及 fasync_helper用于异步通知中,其中 kill_fasync(&b_async,SIGIO,POLL_IN)函数的功能是向应用程序发送可读信号,还有那个进程调用fasync_helper函数就向谁发!这个可以结合应用程序是如何拿到信号的对比着看,关于应用程序这里就不说了!网上的资料也比较多讲解的也很详细!例程代码还有理论分析都有!

fansync_helpr函数内部实现:

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
    struct fasync_struct *fa, **fp;
    struct fasync_struct *new = NULL;
    int result = 0;

    if (on) {
        new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
        if (!new)
            return -ENOMEM;
    }
    write_lock_irq(&fasync_lock);
    for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
        if (fa->fa_file == filp) {
            if(on) {
                fa->fa_fd = fd;   //区分向谁发
                kmem_cache_free(fasync_cache, new);
            } else {
                *fp = fa->fa_next;
                kmem_cache_free(fasync_cache, fa);
                result = 1;
            }
            goto out;
        }
    }

    if (on) {
        new->magic = FASYNC_MAGIC;
        new->fa_file = filp;
        new->fa_fd = fd;
        new->fa_next = *fapp;
        *fapp = new;
        result = 1;
    }
out:
    write_unlock_irq(&fasync_lock);
    return result;
}
kill_fasync函数里面的b_async参数:struct fasync_struct类型定义:

struct   fasync_struct   {
    int magic;
    int fa_fd;
    struct fasync_struct *fa_next;  
    struct file   *fa_file;
};
这个参数在下面中也被调用:实现的fasync成员函数
static int gpio_drv_fasync (int fd, struct file *filp, int on)
{
	printk("driver: gpio_drv_successful\n");
	return fasync_helper (fd, filp, on, &b_async);
}
这也是应用程序和内核之间传参的一个关键:

要实现传参,我们需要把一个结构体struct fasync_struct添加到内核的异步队列中,这个结构体用来存放对应设备文件的信息(如fd, filp)并交给内核来管理。一但收到信号,内核就会在这个所谓的异步队列头找到相应的文件(fd),并在filp->owner中找到对应的进程PID,并且调用对应的sig_handler了。

关于剩下的程序中用到的down() 、up() 还有 DECILARE_MUTEX(b_lock)这里简单的用到了信号量的两个简单的操作,主要是用于保护临界资源,保证中断不被丢失!

剩下的read和close都比较简单,驱动里面的函数基本都是对应的,close里面一把是释放所有申请的资源!这也是模块化驱动的一个好处!虽然这个驱动很简单!但是要仔细深究起来,里面所涉及的知识量也不小!上面也只是简单的分析总结一下!做个笔记算是对自己的一个提高,也别人在参考的时候能有一点点的帮助!

最近住的地方没网!感觉好长时间没写博客了!现在业余时间看linux驱动设备详解,哈哈,比一年多前看的效果好多了,至少书上的好多知识多多少少都接触过!而且看起来还比较有收获,就是看了就忘!看来总结还是相当重要的!好记性不如烂笔头!



Linux驱动异步通知机制:SIGIO与fasync深度解析 异步通知是Linux设备驱动中实现事件驱动模型的基础机制,本质是通过信号(如SIGIO)在内核与用户空间间建立低开销、高实时性的状态变化通知通道。其原理依托于文件描述符所有权(F_SETOWN)和异步标志(FASYNC)的协同控制,由内核fasync_struct链表管理注册进程,并通过kill_fasync触发信号分发。该机制显著降低轮询CPU开销,提升中断响应效率,广泛应用于GPIO按键、传感器就绪、工业I/O等嵌入式场景。相比异步IO(AIO),异步通知仅负责‘事件告知’,不参与数据搬运,二者常组合使 阅读详情

相关推荐

【Linux开发】linux设备驱动归纳总结(三):7.异步通知fasync

linux设备驱动归纳总结(三):7.异步通知fasync xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 异步通知fasync是应用于系统调用signal和sigaction函数,下面我会使用signal函数。简单的说,signal函数就是让一个信

ZhangPY的专栏 812

Linux异步IO之fasync简析

linux, fasync

JiMoKuangXiangQu的专栏 2054

linux内核异步通知用户空间fasync

linux内核异步通知用户空间fasync,使用内核提供的fasync_helper和kill_fasync两个函数

IO模型:多路复用及信号驱动(fasync)原理代码详解

select、poll、epoll都是I/O多路复用的机制,它们允许单个进程或线程同时监视多个文件描述符(如socket、管道、文件等),以等待I/O操作(如读、写、异常)的完成。下面分别解释这三种机制的原理:原理概述:工作流程:缺点:原理概述:工作流程:优点:缺点:原理概述:工作流程:优点:缺点:本文程序将使用select:使用函数:接上文代码加入多路复用功能: mychar.c:(部分新加入) 代码注释:调用:这一行调用了函数。是监视的文件描述符中的最大值加1(因为文件描述符是从0开始计数的),这

weixin_58809023的博客 1275

MATLAB/Simulink BLDC电机控制模型搭建:六步换相与速度环实战

无刷直流电机(BLDC)控制是电机驱动领域的核心技术,其六步换相原理通过霍尔信号控制逆变器开关,使定子磁场与转子磁场保持垂直以产生最大转矩。在MATLAB/Simulink中搭建BLDC控制系统,需从电机本体建模入手,结合PWM占空比调节和速度环PI控制器,实现速度闭环与波形观测。该技术广泛应用于电动工具、无人机电调和伺服驱动器等场景。本文详细解析BLDC六步换相逻辑、反电动势建模及Simulink分层设计方法,帮助读者掌握从零搭建完整控制模型的工程实践。

weixin_28273593的博客 207

NC65增加自定义参照并且参照数据要根据选择的财务组织过滤

1、首先定义一个参照类 package nc.pub.jzcm.ref; import nc.ui.bd.ref.AbstractRefModel; import nc.ui.bd.ref.IRefDocEdit; import nc.ui.bd.ref.IRefMaintenanceHandler; public class PMPrPayDefaultRefModel extends AbstractRefModel { public PMPrPayDefaultRefModel(){ ...

xyl的博客 3494

linux 异步机制

驱动里的kill_fasync、fasync_helper和应用层kill、signal函数区别和联系

yyymmmmyyy的博客 896

Simplicity Studio V5与EFR32BG22蓝牙开发环境实战指南

本文详细介绍了Simplicity Studio V5集成开发环境与EFR32BG22蓝牙芯片的开发实战指南。内容涵盖开发环境安装、SDK配置、项目创建、调试烧录、外设驱动集成及常见问题解决方案,帮助开发者快速上手物联网蓝牙应用开发,并充分利用EFR32BG22的低功耗与高集成度特性。

v5w6x的博客 319

Linux驱动 fasync异步通知方法

本文章来源于正点原子资料,记录下来,以后参考。 1.1 驱动中的信号处理 1 、fasync_struct 结构体 首先我们需要在驱动程序中定义一个 fasync_struct 结构体指针变量,fasync_struct 结构体内容如下: struct fasync_struct { spinlock_t fa_lock; int magic; int fa_fd; struct fasync_struct *fa_next; struct file *fa_file; struct rcu_

qq_31487199的博客 1423

[漏洞剖析]JeecgBoot queryFieldBySql注入与JDBC连接滥用:从内存马植入到RCE的完整攻击链

本文深度剖析了JeecgBoot框架中queryFieldBySql接口的SQL注入漏洞及其引发的完整攻击链。攻击者利用该漏洞,通过Freemarker SSTI植入隐蔽的内存马,并进一步滥用JDBC连接测试功能,借助H2数据库特性实现远程命令执行(RCE),揭示了低代码平台中功能滥用与安全配置疏忽带来的严重风险。

weixin_29232121的博客 115

拯救者R7000P(2021)装双系统Ubuntu20.04 解决联发科MT7921无线网卡在Ubuntu中不能联网

拯救者R7000P(2021)装双系统Ubuntu20.04/Ubuntu18.04 电脑配置:联想拯救者R7000P CPU:AMD R7-5800H GPU:RTX3060-6G 内存:16GB 固态:500G(原装)+500(加装) 1.做系统盘(本文以Ubuntu20.04为例) 1.下载Ubuntu20.04镜像 直接去Ubuntu官网或者一些国内的镜像去下载都可以,这里给出一个网址https://ubuntu.com/download/desktop,根据需要下载自己学要的Ubuntu版本,后缀

qq_41108639的博客 1万+

Linux中驱动程序通过fasync异步通知应用程序的实现

摘要:Linux异步I/O通知机制核心函数 fasync_helper和kill_fasync是Linux内核处理异步I/O通知的核心函数: fasync_helper负责注册/取消异步通知: 根据on参数决定启用/禁用通知 使用专用slab缓存分配内存 通过加锁保护全局链表操作 处理3种情况:更新现有条目、移除条目或添加新条目 返回操作结果(1=成功,0=无操作) kill_fasync负责发送信号: 验证条目魔术字 特殊处理SIGURG信号 通过send_sigio发送信号给注册进程 关键数据结构: f

weixin_51019352的博客 1537

MRST开源油藏模拟:从入门到精通的全流程指南

本文全面介绍了MRST开源油藏模拟工具的使用方法,从环境搭建到核心功能实战,再到性能优化和工业级应用。MRST作为一款基于MATLAB的开源工具,为油藏工程师提供了强大的数值模拟能力,特别适合教学和科研场景。文章还分享了二次开发技巧和常见问题解决方案,帮助读者快速掌握油藏模拟技术。

beer8的博客 326

Linux的fasync驱动异步通知详解【转】

本文转载自:http://blog.csdn.net/coding__madman/article/details/51851338 版权声明:本文为博主原创文章,未经博主允许不得转载。 工作项目用有个需求是监测某个GPIO输入方波的频率!通俗的讲就是一个最最简单的测方波频率的示波器!不过只是测方波的频率!频率范围是0~200HZ,而且频率方波不是一直都是200HZ,大多数的时候可能一直是...

zzb2760715357的博客 238

Gmsh+OCC对应版本库编译

输入 GMSH_DLL_EXPORT值C:\LIB\OCCT-7_8_0-i;9、如果只是生成库文件编译gmesh工程即可生成文件在C:\LIB\Gmsh\gmsh-4.13.1-Windows64-B\Debug 下gmsh.dll、gmsh.lib、gmsh.h、gmshc.h文件;3、CMAK编译Gmsh对应OCC版本的,CMAK选择源文件路径C:\LIB\Gmsh\gmsh-4.13.1-source,生成构建文件路径C:\LIB\Gmsh\gmsh-4.13.1-Windows64-B。

u013401364的博客 411

使用node-red网关读取modbus设备点表,并上传到市政低碳平台来统计数据

最近做了一个物联网项目,具体是这样的,利用node-red网关盒子,来采集Modbus设备的点表,然后将数据转换,封装,最终上传到市政的低碳平台。上一步封装了点表的数据,调用低碳平台还需要账号密码,建筑id,这些都是固定信息,所以我们单独提出来。上一步获取到了原始的点表数据,下一步就是将这些点表数据与在低碳平台创建的采集的对应起来,并且设置好分类。读取modbus的节点,会有两个输出,我是使用的第一个输出。msg.meters 是一个数组,里面的每一个元素都是一个点表,比如厨房用水,园区照明,

知无涯 946

5.Linux按键驱动-fasync异步通知

当应用程序收到SIGIO信号的时候, sig_func函数就会被调用,调用read函数读取按键的值。2.2APP把自己的pid告诉驱动程序。2.1绑定信号和信号处理函数。

weixin_40933496的博客 431

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

使用Linux驱动程序的fasync(文件异步通知机制)向用户空间发送SIGIO信号的学习记录

fcntl是 Linux 系统中的一个强大的文件控制函数,用于操作文件描述符(fd)。通过fcntl,可以设置文件描述符(fd)的属性、锁定文件或获取文件状态。函数原型参数说明fd:需要操作的文件描述符。cmd:控制命令,决定fcntl作什么操作。arg:可选参数,根据cmd的不同而不同,有时可以省略。参数cmd的常用命令及功能1. 设置文件描述符的属主(属于哪个进程)命令F_SETOWN作用。

昊虹AI笔记 922

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

linux设备驱动归纳总结(三):7.异步通知fasync【转】

本文转载自:http://blog.chinaunix.net/uid-25014876-id-62725.html linux设备驱动归纳总结(三):7.异步通知fasync xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 异步通知fasync是应用于系统调用signa...

zzb2760715357的博客 86

linux设备驱动归纳总结(三):7.异步通知fasync

转自: http://blog.chinaunix.net/uid-25014876-id-62725.html linux设备驱动归纳总结(三):7.异步通知fasync xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 异步通知fasync是应用于系统

lijiatong1005的专栏 746

【Linux】Linux驱动开发 IO模型:异步通知IO(signal、fasync)

在进程中注册一个信号处理函数,如果硬件的数据准备好的时候,会产生中断,在中断处理函数中给这个进程发送信号即可。如果内核没有发出信号应用程序,不需要阻塞,运行自己特有的代码即可。本来也要在中断处理函数中发送,此处同样的也是在write函数中发信号。2、通过fcntl调用到底层的fasync函数。3、将当前进程号告诉内核。1、注册信号处理函数。

W__winter的博客 864

【转载】Linux驱动技术 _异步通知技术 fasync

驱动异步通知应用, fasync

jltsun的专栏 166
上一篇: 面试编程题---其中隐藏着若干0,其余非0整数,使A把0移至后面,非0整数移至数组前面并保持有序
下一篇: Linux C 库函数判断一个文件是否为空
coding__madman
博客等级 码龄11年 188粉丝 76原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值