fasync例程分析
代码取自《深入Linux设备驱动程序内核机制》7.7 7.8
app 代码如下:
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <signal.h> 7 8 #define DEVFILE "/dev/fa_dev" 9 static unsigned long eflag = 1; 10 11 static void sigio_handler(int sigio) 12 { 13 printf("Get the SIGIO signal,we exit the application!\n"); 14 eflag = 0; 15 } 16 17 static int block_sigio(void) 18 { 19 sigset_t set,old; 20 int ret; 21 22 sigemptyset(&set); 23 sigaddset(&set,SIGIO); 24 sigprocmask(SIG_BLOCK,&set,&old); 25 ret = sigismember(&old,SIGIO); 26 27 return ret; 28 } 29 30 static void unblock_sigio(int blocked) 31 { 32 sigset_t set; 33 if(!blocked) 34 { 35 sigemptyset(&set); 36 sigaddset(&set,SIGIO); 37 sigprocmask(SIG_UNBLOCK,&set,NULL); 38 } 39 } 40 41 int main(void) 42 { 43 int fd; 44 struct sigaction sigact,oldact; 45 46 int oflag; 47 int blocked; 48 49 blocked = block_sigio(); 50 51 sigemptyset(&sigact.sa_mask); 52 sigaddset(&sigact.sa_mask,SIGIO); 53 sigact.sa_flags = 0; 54 sigact.sa_handler = sigio_handler; 55 56 if(sigaction(SIGIO,&sigact,&oldact)<0) 57 { 58 printf("sigaction failded !\n"); 59 unblock_sigio(blocked); 60 return -1; 61 } 62 63 unblock_sigio(blocked); 64 65 fd = open(DEVFILE,O_RDWR); 66 if(fd>=0) 67 { 68 fcntl(fd,F_SETOWN,getpid()); 69 oflag = fcntl(fd,F_GETFL); 70 fcntl(fd,F_SETFL,oflag|FASYNC); 71 printf("Do everything you want until we get a signal...\n"); 72 while(eflag); 73 close(fd); 74 } 75 76 return 0; 77 }
上面代码中block_sigio()个人认为逻辑上有问题:
根据:http://learn.akae.cn/media/ch33s03.html所述:
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);如果oset
和set
都是非空指针,则先将原来的信号屏蔽字备份到oset
里,然后根据set
和how
参数更改信号屏蔽字。
个人认为改成如下逻辑更合理:
static int block_sigio(void) { sigset_t set,current; int ret; sigemptyset(&set); sigaddset(&set,SIGIO); //首先阻塞SIGIO信号 sigprocmask(SIG_BLOCK,&set,NULL); //再次调用sigprocmask,取得当前信号集current sigprocmask(SIG_BLOCK,NULL,¤t); //判断SIGIO是否在当前信号集中,存在返回1,否则返回0 ret = sigismember(¤t,SIGIO); return ret; }
我不理解原例子中的代码,为什么通过设置了SIGIO信号之前的信号集来做判断条件。
同时unblock_sigio()改为:
static void unblock_sigio(int blocked) { sigset_t set; if(blocked)//修改一下 { sigemptyset(&set); sigaddset(&set,SIGIO); sigprocmask(SIG_UNBLOCK,&set,NULL); } }
附上驱动代码:
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/cdev.h> 5 #include <linux/device.h> 6 #include <asm/signal.h> 7 #include <asm/siginfo.h> 8 9 static struct cdev *pcdev; 10 static dev_t ndev; 11 static struct class *fa_cls; 12 static struct device *fadev; 13 14 static unsigned long flag = 0; 15 static struct fasync_struct *sigio_list; 16 17 18 static ssize_t read_flag(struct device *dev,struct device_attribute *attr,char *buf) 19 { 20 size_t count = 0; 21 count += sprintf(&buf[count],"%lu\n",flag); 22 23 return count; 24 } 25 26 static ssize_t write_flag(struct device *dev,struct device_attributer *attr, 27 const char *buf,size_t count) 28 { 29 flag = buf[0] - '0'; 30 31 kill_fasync(&sigio_list,SIGIO,POLL_IN); 32 return count; 33 } 34 35 static struct device_attribute flag_attr = 36 __ATTR(flag_file,S_IRUGO|S_IWUSR,read_flag,write_flag); 37 38 static int fa_open(struct inode *inode,struct file *flp) 39 { 40 return 0; 41 } 42 43 static int fa_async(int fd,struct file *filp,int onflag) 44 { 45 return fasync_helper(fd,filp,onflag,&sigio_list); 46 } 47 48 static struct file_operations ops={ 49 .owner = THIS_MODULE, 50 .open = fa_open, 51 .fasync = fa_async, 52 }; 53 54 static int fa_init(void) 55 { 56 int ret = 0; 57 58 ret = alloc_chrdev_region(&ndev,0,1,"fa_dev"); 59 if(ret < 0) 60 return ret; 61 62 pcdev = cdev_alloc(); 63 cdev_init(pcdev,&ops); 64 pcdev->owner = THIS_MODULE; 65 cdev_add(pcdev,ndev,1); 66 67 fa_cls = class_create(THIS_MODULE,"fa_dev"); 68 if(IS_ERR(fa_cls)) 69 return PTR_ERR(fa_cls); 70 71 fadev = device_create(fa_cls,NULL,ndev,NULL,"fa_dev"); 72 if(IS_ERR(fadev)) 73 return PTR_ERR(fadev); 74 75 ret = device_create_file(fadev,&flag_attr); 76 77 return ret; 78 } 79 80 static void fa_exit(void) 81 { 82 device_remove_file(fadev,&flag_attr); 83 device_destroy(fa_cls,ndev); 84 class_destroy(fa_cls); 85 cdev_del(pcdev); 86 unregister_chrdev_region(ndev,1); 87 } 88 89 module_init(fa_init); 90 module_exit(fa_exit); 91 MODULE_LICENSE("GPL");
Makefile如下:
export ARCH=x86 export CROSS_COMPILE= obj-m := fasync_demo.o KERNELDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.o *.ko *.mod.*