8. 文件io模型—异步通信 kill
来源:互联网 发布:盒子软件破解版 编辑:程序博客网 时间:2024/06/14 22:26
客户端
- 要点三( 设置信号SIGIO的处理)
- 设置信号处理方法(当中断型号来之后自动跳到catch_signal( ) 函数执行
signal(SIGIO, catch_signal); - 设置信号的属主进程
fcntl(fd, F_SETOWN, getpid()); - 将读写模式设置成异步模式
unsigned int flag = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flag | FASYNC);
- 设置信号处理方法(当中断型号来之后自动跳到catch_signal( ) 函数执行
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/ioctl.h>#include <linux/input.h>#include <poll.h>#include <signal.h>struct key_event{ int code ; // 按键的键值, 比如KEY_DOWN, KEY_POWER int value; // 按键的状态,按下为1, 抬起为0};static int fd;void catch_signal(int signo){ int ret; struct key_event event; if(signo == SIGIO) { printf("we got a SIGIO\n"); ret = read(fd, &event, sizeof(struct key_event)); if(ret < 0) { perror("read"); exit(1); } if(event.code == KEY_POWER) { if(event.value) { printf("__APP__ key power pressed\n"); }else { printf("__APP__ key power up\n"); } } if(event.code == KEY_ENTER) { if(event.value) { printf("__APP__ key enter pressed\n"); }else { printf("__APP__ key enter up\n"); } } } printf("-----------------signal handled end\n");}int main(int argc, char *argv[]){ // int fd; int ret; char kbbuf[128]; fd = open("/dev/key1", O_RDWR); if(fd < 0) { perror("open"); exit(1); } // 需要设置信号SIGIO的处理 // 1,设置信号处理方法 signal(SIGIO, catch_signal); // 2,设置信号的属主进程 fcntl(fd, F_SETOWN, getpid()); //3, 将读写模式设置成异步模式 unsigned int flag = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flag | FASYNC); //做其他的事情 while(1){ sleep(1); printf("I am very bored\n"); } close(fd); return 0;}
—————————————————
驱动端
- 要点3条
1. 需要一个struct fasync_struct 指针,不需要自己分配 struct fasync_struct *key_fasync //描述了信号是给谁, 信息的载体(包括了SIGIO发送给哪个进程的信息) 2. 思想: 2.1 初始化struct fasync_struct指针, 以后就可以知道信号发送给谁 帮你去构建struct fasync_struct 2.3 将前两个参数给到struct fasync_struct ,其中filp中的f_owner就记录了用户空间设置的属主进程的pid 实例: int key_irq_fcntl(int fd, struct file *file, int no) { //1.调用一个fasync_helper, 构建struct fasync_struct,描述信号的信息(信号是给谁的) return fasync_helper(fd, filp, on, &key_dev->key_fasync); } 3. 在(中断的最后)发送信号( SIGIO) kill_fasync(struct fasync_struct * * fp,int sig,int band); 实例: kill_fasync(&key_dev->key_fasync, SIGIO, POLLIN);
#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/gpio.h>#include <linux/interrupt.h>#include <linux/input.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/poll.h>#include <asm/uaccess.h>#include <asm/io.h>// 设计一个表示按键数据的对象struct key_event{ int code ; // 按键的键值, 比如KEY_DOWN, KEY_POWER int value; // 按键的状态,按下为1, 抬起为0};// 面向对象---将任何都看成对象, struct 就是对象//设计一个对象类型,描述当前的设备信息,同时是一个全局的设备对象struct s5pv210_key{ int dev_major; //用老的注册设备号的方式 struct class *cls; struct device *dev; int irqno; //表示设备的中断号码 int testdata; struct key_event event;//存放按键的数据 wait_queue_head_t wq_head; int have_data; //表示标志位,表示是否有数据 struct fasync_struct *key_fasync; //指向一个被分配之后的struct fasync_struct空间 struct tasklet_struct mytasklet;};//设计一个对象,描述是按键的信息/*1, 中断号 2, gpio号码 3, 名字 4, 按键的类型*/struct key_info{ char *name; int irqno; int gpionum; int code; int flags; //触发方式};//设置所有按键的信息struct key_info allkeys[] = { [0] = { .name = "key1_eint0", .irqno = IRQ_EINT(0), .gpionum = S5PV210_GPH0(0), .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, .code = KEY_UP, }, [1] = { .name = "key2_eint1", .irqno = IRQ_EINT(1), .gpionum = S5PV210_GPH0(1), .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, .code = KEY_DOWN, }, [2] = { .name = "key3_eint2", .irqno = IRQ_EINT(2), .gpionum = S5PV210_GPH0(2), .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, .code = KEY_LEFT, }, [6] = { .name = "key7_eint22", .irqno = IRQ_EINT16_31, .gpionum = S5PV210_GPH2(6), .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, .code = KEY_HOME, }, [7] = { .name = "key8_eint23", .irqno = IRQ_EINT16_31, .gpionum = S5PV210_GPH2(7), .flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, .code = KEY_POWER, },};//设置对象struct s5pv210_key *key_dev;int key_drv_open(struct inode *inode, struct file *filp){ //一般也是做初始化动作 printk("-------^_^ %s-----------\n", __FUNCTION__); memset(&key_dev->event,0, sizeof(struct key_event)); key_dev->have_data = 0; return 0;}// write(fd, buf, size);ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos){ return 0;}int key_drv_close(struct inode *inode, struct file *filp){ printk("-------^_^ %s-----------\n", __FUNCTION__); fasync_helper(-1, filp, 0, &key_dev->key_fasync);//释放key_dev->key_fasync return 0;}long key_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long args){ return 0;}ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos){ printk("-------^_^ %s------have= %d-----\n", __FUNCTION__, key_dev->have_data); int ret; //区分阻塞还是非阻塞 if((filp->f_flags & O_NONBLOCK ) && !key_dev->have_data) return -EAGAIN; // 没有数据就休眠--have_data如果0表示没有数据,就需要等 wait_event_interruptible(key_dev->wq_head, key_dev->have_data); ret = copy_to_user(buf, &key_dev->event, count); if(ret > 0) { printk("copy_to_user error\n"); return -EFAULT; } // 清空后,接着去收其他的数据 memset(&key_dev->event,0, sizeof(struct key_event)); key_dev->have_data = 0; // 重新设置成没有数据 return count;}unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts){ printk("-------^_^ %s-----------\n", __FUNCTION__); unsigned int mask = 0; // 将当前的等待队列注册到vfs中 poll_wait(filp, &key_dev->wq_head, pts); //如果有数据的时候,返回一个POLLIN if(key_dev->have_data) mask |= POLLIN; return mask;}int key_drv_fasync (int fd, struct file *filp, int on){ //调用一个fasync_helper, 构建struct fasync_struct,描述信号的信息(信号是给谁的) return fasync_helper(fd, filp, on, &key_dev->key_fasync);}const struct file_operations key_fops = { .open = key_drv_open, .write = key_drv_write, .read = key_drv_read, .release = key_drv_close, .unlocked_ioctl = key_drv_ioctl, .poll = key_drv_poll, .fasync = key_drv_fasync,};void tasklet_half_irq_handle(unsigned long data){ printk("-------^_^ %s-----------\n", __FUNCTION__); wake_up_interruptible(&key_dev->wq_head);//会唤醒 key_dev->have_data = 1; //表示有数据 ///发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数 kill_fasync(&key_dev->key_fasync, SIGIO, POLLIN);}irqreturn_t key_irq_handler(int irqno, void *dev_id){ printk("-------^_^ %s-----------\n", __FUNCTION__); //区分不同的中断 struct key_info *p = (struct key_info *)dev_id; //区分是按下还是抬起 int value; value = gpio_get_value(p->gpionum); if(value){ //抬起 printk("%s up \n", p->name); key_dev->event.code = p->code; key_dev->event.value = 0; }else{ //按下 printk("%s pressed \n", p->name); key_dev->event.code = p->code; key_dev->event.value = 1; } //启动下半部 tasklet_schedule(&key_dev->mytasklet); return IRQ_HANDLED;}static int __init key_drv_init(void){ int ret; //申请资源 // 实例化该对象 // GFP_KERNEL如果当前没有内存可分配,该函数会一直等 key_dev = kzalloc(sizeof(struct s5pv210_key), GFP_KERNEL); if(key_dev == NULL) { printk(KERN_ERR "kzalloc error\n"); return -ENOMEM; } // 1, 申请设备号 key_dev->dev_major = register_chrdev(0, "s5pv210_key_drv", &key_fops); if(key_dev->dev_major < 0) { printk(KERN_ERR "kzalloc error\n"); ret = -ENODEV; goto err_0; } // 2, 自动创建文件 // /sys/class/key_cls 文件夹 key_dev->cls = class_create(THIS_MODULE, "key_cls"); if(IS_ERR(key_dev->cls)) { printk(KERN_ERR "class_create error\n"); ret = PTR_ERR(key_dev->cls); goto err_1; } // /sys/class/key_cls/key/ // /dev/key1 key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,1),NULL, "key1"); if(IS_ERR(key_dev->dev)) { printk(KERN_ERR "device_create error\n"); ret = PTR_ERR(key_dev->dev); goto err_2; } // 4, 硬件的初始化---中断 // //key_dev->irqno = IRQ_EINT(1); int i; int irqno; int flags; char *name; for(i=0; i<ARRAY_SIZE(allkeys); i++) { irqno = allkeys[i].irqno; if(irqno == IRQ_EINT16_31) irqno = gpio_to_irq(allkeys[i].gpionum); flags = allkeys[i].flags; name = allkeys[i].name; ret = request_irq(irqno, key_irq_handler, flags,name, &allkeys[i]); if(ret != 0) { printk(KERN_ERR "request_irq error : i=%d\n", i); ret = -EBUSY; goto err_4; } } //初始化等待队列头 init_waitqueue_head(&key_dev->wq_head); // 初始化tasklet,为下半部做准备 tasklet_init(&key_dev->mytasklet,tasklet_half_irq_handle, 34); return 0;err_4: i--; for(; i>0; i--) { irqno = gpio_to_irq(allkeys[i].gpionum); free_irq(irqno, &allkeys[i]); }err_3: device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));err_2: class_destroy(key_dev->cls);err_1: unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");err_0: kfree(key_dev); return ret;}static void __exit key_drv_exit(void){ //释放资源 int i; int irqno; for(i=0; i<ARRAY_SIZE(allkeys); i++) { irqno = gpio_to_irq(allkeys[i].gpionum); free_irq(irqno, &allkeys[i]); } device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1)); class_destroy(key_dev->cls); unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv"); kfree(key_dev);}module_init(key_drv_init);module_exit(key_drv_exit);MODULE_LICENSE("GPL");
0 0
- 8. 文件io模型—异步通信 kill
- 深入浅出异步IO模型
- 理解异步IO模型
- 重叠IO模型-异步IO
- 重叠IO模型 - 异步IO
- 重叠IO模型 - 异步IO
- 重叠IO模型 - 异步IO
- 通信模型socket.io
- linux网络编程异步IO模型之—select模型 .
- Winsock异步IO----select模型
- Linux异步信号IO模型
- Java 异步IO(1) 文件异步IO
- 关于异步文件IO
- 关于异步文件IO
- 文件操作 异步IO
- Windows Socket常见异步IO模型——代码攻略
- 同步文件IO和异步文件IO
- 同步文件IO和异步文件IO
- indexOf charAt split substring substr字符串和Math常用方法总结
- pythom程序如何控制命令行标签
- 指示器随机变量,算法导论5.2
- java基础之LinkedList练习--模拟堆栈
- 第十四周项目二两个成员的类模板二
- 8. 文件io模型—异步通信 kill
- WPF 4 媒体播放器(MediaElement)
- Android viewpager实现无限循环轮播
- 求一个二维数组中每列的最小值
- 解决vc运行CMD秒退小问题
- 第14周项目三—数组类模板
- leetcode 41 First Missing Positive
- ReactiveCocoa进阶
- 分布式数据库2