0

The usual way to respond to an edge-triggered GPIO interrupt, using the old sysfs GPIO interface, is like this:

repeat forever
    poll() on POLLPRI event on GPIO fd
    lseek() back to 0 on GPIO fd
    read() current state from GPIO fd

If I put the code that actually handles the interrupt after the read(), is it guaranteed that any new interrupt that happens before poll() is called again will cause that next poll() to return immediately? In other words, what step re-arms the interrupt? The return from poll(), the call to lseek(), the call to read(), or the next call to poll()? If it's the last of these, I don't see any way to guarantee that an interrupt can't get lost.

Also, is it necessary to do the read()? I don't care about the state, just the edge event. And if I don't need read(), does lseek() do anything useful? This is hard to test in real life, because it would require generating interrupts in rapid succession on the existing hardware. None of the docs seem to explain this.

0andriy
  • 4,183
  • 1
  • 24
  • 37
Paul DeRocco
  • 403
  • 3
  • 15
  • 1
    First of all, do not use sysfs interface. Second, what kernel version you are talking about? We can check the code and see what happens there. – 0andriy Jun 01 '21 at 19:01
  • This https://elixir.bootlin.com/linux/latest/source/fs/kernfs/file.c#L943 and this https://elixir.bootlin.com/linux/latest/source/fs/kernfs/file.c#L801 will answer to the `lseek()` question. – 0andriy Jun 01 '21 at 19:17
  • This shows what happens when new interrupt (event) is coming https://elixir.bootlin.com/linux/latest/source/fs/kernfs/file.c#L913. AFAIU when you read the value, you will read the actual state (which may be different to what triggered the poll). Which means that read of event makes a little sense. – 0andriy Jun 01 '21 at 19:21
  • I'm stuck with 4.0.0, which is why I'm using sysfs. I don't know my way around the kernel at all, so I couldn't figure out anything from those bits of code, least of all when the interrupt is re-armed. Although there is a comment in the code implying that it really is necessary to do an lseek and a read. I read something somewhere on the advantages of /dev/gpiochip which said "The polling process to catch events (interrupts from GPIO lines) is reliable" which leads me to fear that there may be some intrinsic problem with /sys/class/gpio that makes an occasional missed interrupt unavoidable. – Paul DeRocco Jun 07 '21 at 04:06
  • v4.0?! (There was no v4.0.0) It's very strange. But okay, it's not the main issue we are discussing here. – 0andriy Jun 07 '21 at 12:50
  • IRQs are armed at the state of requesting them (i.e. they are **always** armed until you explicitly disable them, see `free_irq()` call somewhere near to the `request_any_context_irq()` in _gpiolib-sysfs.c_). Then it's hardware driven event model. – 0andriy Jun 07 '21 at 12:53
  • `lseek()` and `read()` are necessary in case you need that data, otherwise I think you may ignore that. – 0andriy Jun 07 '21 at 12:55
  • 4.0.0 is actually the Buildroot version, so the kernel is 4.0. – Paul DeRocco Jun 08 '21 at 22:25
  • The question is really this: If one interrupt completes a poll() call, will another interrupt that happens before the lseek() cause the next poll() to complete immediately? How about between lseek() and read()? How about between read() and the next poll()? If an interrupt isn't recognized until after poll() is called again, then there's no reliable way to prevent a lost interrupt. The reason I ask here is that lost interrupts are the sort of thing that only happens rarely, so it's a hard thing to test. – Paul DeRocco Jun 08 '21 at 22:44
  • Interrupt can happen **any** time, because it's a **hardware interrupt**. – 0andriy Jun 09 '21 at 10:36

1 Answers1

1

I've been using sysfs recently, and this snippet helped me:

int main() {
    struct pollfd myPollfd;
    myPollfd.fd = open("/sys/class/gpio/GPIO_IN_WHEEL1/value", O_RDONLY); //store filedescriptor in struct, open(path, read-write-permission)
    myPollfd.events = POLLPRI;
    while (1) {
        poll(&myPollfd, 1, -1); //poll(struct pollfd, max fd, timeout), timeout=-1 --> never
        if(myPollfd.revents & POLLPRI) {
            len = read(myPollfd.fd, buf, BUF_SIZE);  //mandatory to make system register interrupt as served
            printf("interrupt!\n",);
        }
        lseek(myPollfd.fd, 0, 0); //return cursor to beginning of file or next read() will return EOF
    }
    close(myPollfd.fd);
    return 0;
}

According to the sysfs manual, it's the read operation that makrs the interrupt to register as served, so in order to react to the next interrupt one must call read() on the endpoint, even if the content of the endpoint itself is meaningless.
Unfortunately i can't find the said documentation at the moment, but if i understood your question correctly, what you need to know is that all interrupts that happen between the first and the first call to read() are going to be lost.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Jack
  • 123
  • 5