首页 > 代码库 > linux内核 信号
linux内核 信号
简单的写一个小程序了解一些信号的机理
尽管阻塞和非阻塞操作和 select 方法的结合对于查询设备在大部分时间是足
够的, 一些情况还不能被我们迄今所见到的技术来有效地解决.
让我们想象一个进程, 在低优先级上执行一个长计算循环, 但是需要尽可能快
的处理输入数据. 如果这个进程在响应新的来自某些数据获取外设的报告, 它
应当立刻知道当新数据可用时. 这个应用程序可能被编写来调用 poll 有规律
地检查数据, 但是, 对许多情况, 有更好的方法. 通过使能异步通知, 这个应
用程序可能接受一个信号无论何时数据可用并且不需要让自己去查询.
用户程序必须执行 2 个步骤来使能来自输入文件的异步通知. 首先, 它们指定
一个进程作为文件的拥有者. 当一个进程使用 fcntl 系统调用发出 F_SETOWN
命令, 这个拥有者进程的 ID 被保存在 filp->f_owner 给以后使用. 这一步对
内核知道通知谁是必要的. 为了真正使能异步通知, 用户程序必须设置 FASYNC
标志在设备中, 通过 F_SETFL fcntl 命令.
在这 2 个调用已被执行后, 输入文件可请求递交一个 SIGIO 信号, 无论何时
新数据到达. 信号被发送给存储于 filp->f_owner 中的进程(或者进程组, 如
果值为负值).
例如, 下面的用户程序中的代码行使能了异步的通知到当前进程, 给 stdin 输
入文件:
signal(SIGIO, &input_handler); /* dummy sample; sigaction() is better */
fcntl(STDIN_FILENO, F_SETOWN, getpid());
oflags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
这个在源码中名为 asynctest 的程序是一个简单的程序, 读取 stdin. 它可用
来测试 scullpipe 的异步能力. 这个程序和 cat 类似但是不结束于文件尾;
它只响应输入, 而不是没有输入.
注意, 但是, 不是所有的设备都支持异步通知, 并且你可选择不提供它. 应用
程序常常假定异步能力只对 socket 和 tty 可用.
输入通知有一个剩下的问题. 当一个进程收到一个 SIGIO, 它不知道哪个输入
文件有新数据提供. 如果多于一个文件被使能异步地通知挂起输入的进程, 应
用程序必须仍然靠 poll 或者 select 来找出发生了什么.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <asm-generic/ioctl.h> #include <asm/uaccess.h> #include <linux/wait.h> #include <linux/sched.h> #include <asm/atomic.h> #include <linux/semaphore.h> #define MAGIC ‘B‘ #define GET_BTN_VAL _IOR(MAGIC, 1, unsigned long) typedef struct { unsigned int gpio; unsigned int btn; unsigned int irq; char* name; }irq_typedef; static irq_typedef irqsource[] = { {EXYNOS4_GPX3(2),1,0,"btn1"}, {EXYNOS4_GPX3(3),2,0,"btn2"}, {EXYNOS4_GPX3(4),3,0,"btn3"}, {EXYNOS4_GPX3(5),4,0,"btn4"} }; DEFINE_SEMAPHORE(btn_sem); DECLARE_WAIT_QUEUE_HEAD(btn_wait_que); static int condition; static unsigned long btn_num; static irqreturn_t gpio_irq_handler(int irq, void *dev) { irq_typedef* curdev = (irq_typedef *)dev; printk("%s\n",curdev->name); printk("btn(drv):%d\n",curdev->btn); btn_num = curdev->btn; condition=1; wake_up(&btn_wait_que); return 0; } static int btn_open(struct inode *inod, struct file *fil) { if(!down_interruptible(&btn_sem)) { up(&btn_sem); return -EINTR; } return 0; } static int btn_release(struct inode *inod, struct file *fil) { up(&btn_sem); return 0; } static long btn_ioctl(struct file *fil, unsigned int cmd, unsigned long arg) { unsigned long ret; void __user *argp = (void __user *)arg; wait_event_interruptible(btn_wait_que, condition); condition = 0; switch(cmd) { case GET_BTN_VAL: ret = copy_to_user((void __user *) argp, (void *)&btn_num,4); // put_user(btn_num, (unsigned int __user *) argp); break; default:return -EINVAL; } return ret; } static struct file_operations btn_irq_fops = { .owner = THIS_MODULE, .open = btn_open, .release = btn_release, .unlocked_ioctl = btn_ioctl, }; static struct miscdevice btn_irq_misc = { .minor = 255, .name = "btn", .fops = &btn_irq_fops, }; static __init int btn_irq_init(void) { int i,ret; misc_register(&btn_irq_misc); for(i=0;i<4;i++) { irqsource[i].irq = gpio_to_irq(irqsource[i].gpio); ret = request_irq(irqsource[i].irq,gpio_irq_handler,IRQF_TRIGGER_FALLING,irqsource[i].name, &irqsource[i]); } return ret; } static __exit void btn_irq_exit(void) { int i; for(i=0;i<4;i++) free_irq(irqsource[i].irq, &irqsource[i]); misc_deregister(&btn_irq_misc); } module_init(btn_irq_init); module_exit(btn_irq_exit); MODULE_LICENSE("GPL");
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/ioctl.h> #define MAGIC ‘B‘ #define GET_BTN_VAL _IOR(MAGIC, 1, unsigned long) int main(int argc,char *argv[]) { int btn_fd,btn_val=0; if(argc!=2) { printf("Usage:<%s> </dev/?node>\n",argv[0]); return -1; } btn_fd = open(argv[1],O_RDONLY); if(btn_fd<0) return -1; while(1) { // ioctl(btn_fd,GET_BTN_VAL,btn_val); ioctl(btn_fd,GET_BTN_VAL,&btn_val); // sleep(1); printf("btn_val(irq):%d\n",btn_val); } }
obj-m += btnirq.o SOURCE =btntest.o CROSS_COMPLIE = arm-linux- CC = $(CROSS_COMPLIE)gcc KERNDIR = /file/samsung/linux-3.5 #CURDIR = $(shell pwd) CURDIR = `pwd` .PHONY: module clean all: module $(SOURCE:.o=) module: $(MAKE) -C $(KERNDIR) M=$(CURDIR) modules $(SOURCE:.o=):$(SOURCE) $(CC) -o $@ $^ %.o:%.c $(CC) -c $< clean: $(MAKE) -C $(KERNDIR) M=$(CURDIR) clean rm $(SOURCE:.o=)
linux内核 信号