4

I have a particular problem. Poll keeps returning when I know there is nothing to read.

So the setup it as follows, I have 2 File Descriptors which form part of a fd set that poll watches. One is for a Pin high to low change (GPIO). The other is for a proxy input. The problem occurs with the Proxy Input.

The order of processing is: start main functions; it will then poll; write data to proxy; poll will break; accept the data; send the data over SPI; receiving slave device, signals that it wants to send ack, by Dropping GPIO low; poll() senses this drop and reacts; Infinite POLLINs :(

IF I have no timeout on the Poll function, the program works perfectly. The moment I include a timeout on the Poll. The Poll returns continuously. Not sure what I am doing wrong here.

while(1)
{
    memset((void*)fdset, 0, sizeof(fdset));

    fdset[0].fd = gpio_fd;
    fdset[0].events = POLLPRI; // POLLPRI - There is urgent data to read 

    fdset[1].fd = proxy_rx;
    fdset[1].events = POLLIN; // POLLIN   - There is data to read

    rc = poll(fdset, nfds, 1000);//POLL_TIMEOUT);
            
    if (rc < 0)     // Error
    {
        printf("\npoll() failed/Interrupted!\n");
    }
    else if (rc == 0)       // Timeout occurred
    {
        printf(" poll() timeout\n");
    }
    else
    {
        if (fdset[1].revents & POLLIN)
        {
            printf("fdset[1].revents & POLLIN\n");
            if ((resultR =read(fdset[1].fd,command_buf,10))<0)
            {                                   
                printf("Failed to read Data\n");
            }
            if (fdset[0].revents & POLLPRI)
            //if( (gpio_fd != -1) && (FD_ISSET(gpio_fd, &err)))
            {
                lseek(fdset[0].fd, 0, SEEK_SET); // Read from the start of the file
                len = read(fdset[0].fd, reader, 64);
            }
        }
    }
}

So that is the gist of my code.

I have also used GDB and while debugging, I found that the GPIO descriptor was set with revents = 0x10, which means that an error occurred and that POLLPRI also occurred.

In this question, something similar was addressed. But I do read all the time whenever I get POLLIN. It is a bit amazing, that this problem only occurs when I include the timeout, if I replace the poll timeout with -1, it works perfectly.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
user2298298
  • 41
  • 1
  • 3
  • 1
    Although I don't think it's the cause of this particular problem, be aware that the `sysfs` interface to GPIO only detects edges when there is a thread blocked on in `poll()` or `select()` - it doesn't buffer them until the next call. Unless you are absolutely sure (by protocol design and implementation) that you'll always be blocked when the ACK appears, there's potential for a race condition and getting into a state where you never receive another one. My solution to this is a similar scenario to yours was a kernel mode driver. – marko Apr 21 '13 at 11:12
  • 1
    Well its been seven years since I first posted this. Wow. We did refactor this piece of code make it simpler. The main route cause of this eventually turned out to be a driver issue from the device connected, where they were unable to clear the flags. As was pointed out by Marko above there is no buffer and therefore introduces edge cases where things can be missed too (encountered this problem much later too) – user2298298 Apr 08 '21 at 10:10

2 Answers2

0

When poll fails (returning -1) you should do something with errno, perhaps thru perror; and your nfds (the second argument to poll) is not set, but it should be the constant 2.

Probably the GCC compiler would have given a warning, at least with all warnings enabled (-Wall), about nfds not being set.

(I'm guessing that nfds being uninitialized might be some "random" large value.... So the kernel might be polling other "random" file descriptors, those in your fdset after index 2...)

BTW, you could strace your program. And using the fdset name is a bit confusing (it could refer to select(2)).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • poll() doesnt fail, however I did use the perror idea and print out the error that was popping up (I have been receiving :Device or resource busy for the GPIO File descriptor). nfds is initially set to 2 in main, didnt include that part, sorry. Also, I see it happens as soon as I allow the other device to alter the GPIO. Still quite perplexing – user2298298 Apr 22 '13 at 13:03
-1

Assuming I fixed your formatting properly in your question, it looks like you have a missing } after the POLLIN block and the next if() that checks the POLLPRI. It would possibly work better this way:

    if (fdset[1].revents & POLLIN)
    {
        printf("fdset[1].revents & POLLIN\n");
        if ((resultR =read(fdset[1].fd,command_buf,10))<0)
        {                                   
            printf("Failed to read Data\n");
        }
    }
    if (fdset[0].revents & POLLPRI)
    //if( (gpio_fd != -1) && (FD_ISSET(gpio_fd, &err)))
    {
        lseek(fdset[0].fd, 0, SEEK_SET); // Read from the start of the file
        len = read(fdset[0].fd, reader, 64);
    }

Although you can do whatever you want with indentation in C/C++/Java/JavaScript, not doing it right can bite you really hard. Hopefully, I'm wrong and your original code was correct.

Another one I often see: People not using the { ... } at all and end up writing code like:

if(expr) do_a; do_b;

and of course, do_b; will be executed all the time, whether expr is true or false... and although you could fix the above with a comma like so:

if(expr) do_a, do_b;

the only safe way to do it right is to use the brackets:

if(expr)
{
    do_a;
    do_b;
}

Always make sure your indentation is perfect and write small functions so you can see that it is indeed perfect.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156