#include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/sched.h> #include <linux/poll.h> #include <asm/uaccess.h> #define DEVICE_NAME "select_poll" #define MAX_BUFFER_SIZE 20 static char buffer[MAX_BUFFER_SIZE]; static int buffer_char_count = 0; static wait_queue_head_t my_queue; struct semaphore sem; static ssize_t demo_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; if(buffer_char_count > 0){ if(down_interruptible(&sem)) return -ERESTARTSYS; if(copy_to_user(buf, buffer, buffer_char_count)) return -EINVAL; //唤醒等待队列头指向的量表中的所有等待队列 wake_up_interruptible(&my_queue); ret = buffer_char_count; buffer_char_count = 0; up(&sem); return ret; } else return 0; return ret; } static ssize_t demo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; if(down_interruptible(&sem)) return -ERESTARTSYS; //休眠当前进程,知道condition满足 wait_event_interruptible(my_queue, buffer_char_count == 0); //check condition. if(count > MAX_BUFFER_SIZE) return -EINVAL; if(copy_from_user(buffer, buf, count)) return -EINVAL; ret = count; buffer_char_count = count; //Release semaphore. up(&sem); return ret; } unsigned int demo_poll(struct file *filp, struct poll_table_struct *wait) { unsigned int mask = 0; if(down_interruptible(&sem)) return -ERESTARTSYS; //将对应的等待队列头添加到轮询表中,pollwait函数不会阻塞,只是把当前进程添加到wait参数指向的轮询表中 poll_wait(filp, &my_queue, wait); if(buffer_char_count > 0) mask |= POLLIN | POLLRDNORM; if(buffer_char_count == 0) mask |= POLLOUT | POLLWRNORM; up(&sem); return mask; } struct file_operations dev_fops = { .owner = THIS_MODULE, .read = demo_read, .write = demo_write, .poll = demo_poll, }; struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init demo_init(void) { int ret = misc_register(&misc); init_waitqueue_head(&my_queue); sema_init(&sem, 1); printk("select poll init success.\n"); return ret; } static void __exit demo_exit(void) { misc_deregister(&misc); printk("select poll exit sucess.\n"); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL");
测试程序
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #define BUFFER_LEN 20 int main(void) { int fd, num; fd_set rfds, wfds; char buf[BUFFER_LEN]; memset(buf, 0, BUFFER_LEN); fd = open("/dev/select_poll", O_RDWR | O_NONBLOCK); if (fd != -1) { while(1){ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(fd, &rfds); FD_SET(fd, &wfds); select(fd + 1, &rfds, &wfds, NULL, NULL); if(FD_ISSET(fd, &rfds)){ printf("Data can be read!\n"); read(fd, buf, BUFFER_LEN); memset(buf, 0, BUFFER_LEN); } if(FD_ISSET(fd, &wfds)){ printf("Data can be written!\n"); } sleep(1); } } else{ printf("Device open failed!\n"); } return 0; }
测试方法:
echo xxxxxxxx > /dev/select_poll
poll的设计
最新推荐文章于 2022-02-19 11:45:22 发布