#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