2

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

bbpencil
  • 41
  • 1
  • 3

1 Answers1

2

The manual page for close warns:

It is probably unwise to close file descriptors while they may be in use by
system calls in other threads in the same process. Since a file descriptor
may be reused, there are some obscure race conditions that may cause unintended
side effects.

I suspect that something in the higher levels of the kernel is cancelling your poll operation when you execute close, before the release() function actually gets called. I'd think about solving your problem a different way.

Peter
  • 14,559
  • 35
  • 55
  • Thanks your answer. I found that close(2) erases given descriptor from fd table soon. so given descriptor is no loger valid when close(2) returned and behavior of poll(2) that never returns may be correct. your assumption may be correct. I try to implement this problem by different way. – bbpencil Dec 18 '13 at 15:31