I'm implementing a misc device driver for linux.
This driver implements file_operations::poll and
I want to make it so that poll(2) would return POLLHUP if the descriptor is closed.
Supposed driver client code(userland code) follows.
void ThreadA(int fd){
// initialization codes...
pfd[0].fd = fd;
pfd[0].event = POLLIN;
int r = poll(pfd, 1, -1);
if(r > 0 && pfd[0].revent & POLLHUP){
// Detect fd is closed
return; // Exit thread
}
}
void ThreadB(int fd){
// waiting some events. ex.signals
// I expect close(fd) will cause poll(2) return and ThreadA will exit.
close(fd);
return;
}
But I could not implement this behavior to in my driver code.
Calling poll(2) never returns even if descriptor is closed. so threadA never exits.
Trivial test driver code follows.
static wait_queue_head_t q;
static int CLOSED = 0;
int my_open(struct inode *a, struct file *b){
printk(KERN_DEBUG "my_open");
return 0;
}
int my_release(struct inode *a, struct file *b){
printk(KERN_DEBUG "my_release");
CLOSED = 1;
wake_up_interruptible(&q);
// I expect this call will wake up q and recall my_poll.
// but doesn't
return 0;
}
unsigned int my_poll(struct file *a, struct poll_table_struct *b){
printk(KERN_DEBUG "my_poll");
poll_wait(file, &q, a);
if(CLOSED != 0)
return POLLHUP;
return 0;
}
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = &my_open,
.release = &my_release,
.poll = &my_poll
};
static struct miscdevice mydevice =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "TESTDEV",
.fops = &my_fops
};
static int __init myinit(void){
init_waitqueue_head(&q);
misc_register(&mydevice);
return 0;
}
static void __exit myexit(void){
misc_deregister(&mydevice);
}
module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");
I think calling wake_up_interruptible() doesn't effect in my_release().
so that my_poll() will never be recalled and poll(2) will never return.
How should I implement my_poll() in a correct manner?
My test environment: kernel is linux-3.10.20