I want to use the GPIO pins to wait for a button-press without using a CPU spin loop. My preferred way of using the GPIO pins is via the sysfs interface at /sys/class/gpio, but it seems to me that there is an inherent race condition in doing so. Namely, if I understand the sysfs interface to GPIO correctly, it seems one must go through the following sequence:

  1. Read the value file to see whether the desired condition holds true.
  2. If it does not (the usual case for the first iteration), poll the value file for POLLPRI to sleep until it changes state, and repeat from step 1.

However, in this procedure, there is a window of opportunity between steps 1 and 2 such that the button is not yet pressed when the value is read, but then pushed right before entering doing the poll call, in which case this particular button press would effectively be missed.

I mean, I realize that a low-frequency event like button presses doesn't really have a high probability of triggering this race condition, but there are certainly more high-frequency events that could, and even regardless of that, it just seems ugly. Is there a way to avoid this problem?

  • Not to try to talk you out of your preference for sysfs, but it's been deprecated and may not be around much longer. – Seamus Sep 15 '18 at 20:15
  • @Seamus: I'm fine with being talked out of sysfs access, I just don't quite know what the alternative would be, except direct register access, which seems a bit ugly in comparison to using user-space interfaces. – Dolda2000 Sep 15 '18 at 20:38
  • Follow the first link in my comment above - there are at least two good libraries, and that link discusses them. pigpio is one of those libraries, and I see @joan has already answered, so you're in good hands. – Seamus Sep 15 '18 at 20:43

You should probably think about migrating to the new gpiochip interface for any new software. One improvement is that it gives you the likely time of GPIO level changes.

I have done pretty much what you describe with sysfs without noticing a problem. I suspect that once you have set the GPIO as an input and given an edge the system is primed to respond to level changes. That may be why I consume any prior interrupt in this code.

I suggest having a look in wiringPi or (my) pigpio which both have sysfs interrupt code.

/* 2014-07-06

   gcc -o wfi wfi.c

   ./wfi [gpio]

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <poll.h>

#define GPIO 4

int main(int argc, char *argv[])
   char str[256];
   struct timeval tv;
   struct pollfd pfd;
   int fd, gpio;
   char buf[8];

      Prior calls assumed.
      sudo sh -c "echo 4      >/sys/class/gpio/export"
      sudo sh -c "echo in     >/sys/class/gpio/gpio4/direction"
      sudo sh -c "echo rising >/sys/class/gpio/gpio4/edge"

   if (argc > 1) gpio = atoi(argv[1]);
   else          gpio = GPIO;

   sprintf(str, "/sys/class/gpio/gpio%d/value", gpio);

   if ((fd = open(str, O_RDONLY)) < 0)
      fprintf(stderr, "Failed, gpio %d not exported.\n", gpio);

   pfd.fd = fd;

   pfd.events = POLLPRI;

   lseek(fd, 0, SEEK_SET);    /* consume any prior interrupt */
   read(fd, buf, sizeof buf);

   poll(&pfd, 1, -1);         /* wait for interrupt */

   lseek(fd, 0, SEEK_SET);    /* consume interrupt */
   read(fd, buf, sizeof buf);


I didn't set up the edge and direction within the above code because I wanted the program to work without running with root permissions.

  • "The new gpiochip interface", you say? Does this refer to the /dev/gpiochip* files? Are they preferable to the sysfs interface? I've been trying to find documentation about it, but have been unsuccessful. – Dolda2000 Sep 15 '18 at 20:41
  • Have a search for a user space interface called libgpiod. E.g. cnx-software.com/2017/11/03/… – joan Sep 15 '18 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.