-
Notifications
You must be signed in to change notification settings - Fork 2.1k
native/async_read: use poll() instead of select() #12428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
No longer exists :( |
I posted the question why a GPIO fd won't generate a signal to the process but there was no answer, I guess it got automatically deleted. I had this Code#include <fcntl.h>
#include <linux/gpio.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define PIN_IN (20)
#define PIN_OUT (26)
static int fd_in; /* to be read in the signal handler */
/* configure input pin */
static int setup_pin_int(int fd, int pin, int mode, int flank) {
struct gpioevent_request req = {
.lineoffset = pin,
.handleflags = mode,
.eventflags = flank
};
int res = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
if (res < 0) {
return res;
}
return req.fd;
}
/* configure output pin */
static int setup_pin_out(int fd, int pin, int mode) {
struct gpiohandle_request req = {
.lineoffsets[0] = pin,
.flags = mode,
.lines = 1
};
int res = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (res < 0) {
return res;
}
return req.fd;
}
static void pin_set(int fd, uint8_t val) {
ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &val);
}
static void sigurg_handler(void) {
struct gpioevent_data event;
read(fd_in, &event, sizeof(event));
if (event.id == GPIOEVENT_EVENT_RISING_EDGE) {
puts("rising");
}
if (event.id == GPIOEVENT_EVENT_FALLING_EDGE) {
puts("falling");
}
}
static void signal_handler(int signal) {
printf("got signal: %x\n", signal);
if (signal == SIGURG) {
sigurg_handler();
}
}
static void register_signal(int signal, void (*handler)(int)) {
struct sigaction sa = {
.sa_handler = handler
};
sigaction(signal, &sa, NULL);
}
/* calling poll() on the fd works as expected */
static void _do_poll(int fd) {
struct pollfd pfd = {
.fd = fd,
.events = POLLIN | POLLPRI
};
if (poll(&pfd, 1, 1000) > 0) {
sigurg_handler();
}
}
int main(void) {
int pins[2];
int fd = open("/dev/gpiochip0", O_RDWR);
pins[0] = setup_pin_int(fd, PIN_IN, GPIOHANDLE_REQUEST_INPUT, GPIOEVENT_REQUEST_BOTH_EDGES);
pins[1] = setup_pin_out(fd, PIN_OUT, GPIOHANDLE_REQUEST_OUTPUT);
fd_in = pins[0];
/* register signal handler */
register_signal(SIGIO, signal_handler);
register_signal(SIGURG, signal_handler);
/* make the fd generate signals */
fcntl(fd_in, F_SETOWN, getpid());
fcntl(fd_in, F_SETSIG, SIGURG);
fcntl(fd_in, F_SETFL, O_NONBLOCK | O_ASYNC);
/* toggle the output pin each second */
int state;
while (1) {
state = !state;
sleep(1);
printf("set %d\n", state);
pin_set(pins[1], state);
/* poll() is working on the fd */
// _do_poll(fd_in);
}
close(fd);
return 0;
} running on the Raspi with a jumper bridging GPIO20 and GPIO26. You will find that no signals are generated even though AFAIU those should be enabled by So the conclusion would be that this is an omission by the Linux kernel, a conclusion that @bergzand had already reached before and thus implemented this solution where |
I tested on Linux and |
I don't really have a working OSX setup. But does |
I was send here from #12451 since I seem to be one of the few Mac users here.
I had this problem before and it was fixed a few month ago.
So I don't think testing this is possible right now. |
So this only happens on linking, but there are no issues on compilation? This might hint, that |
We could try to run it on FreeBSD as a gauge. I think that was Ludwig's free replacement for OSX back when he introduced |
Thanks for testing @janschlicht by the way! ❤️ |
I finally got a setup working where I was able to compile, by luck I have |
Let's wait with this until feature freeze. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are not in feature freeze anymore and since native is broken OSX because of 64bit, it's not possible to say that this PR is breaking something there. There's a consensus with @fjmolinas to merge this one (as it works on Linux anyway) and to see if it had an impact on OSX when we have 64 bit support for native.
Let's move forward, ACK!
@benpicco, also please rebase to trigger the new GH actions checks! |
select() can not listen to POLLPRI events which are used by the Kernel's GPIO API. In preparation for that, rewrite async_read() to use poll() instead of select().
fcntl(fd, F_SETOWN, getpid()); doesn't seem to work on Linux to get generate a signal when an event on the GPIO fd occurs. So fall back to the same method as on OS X and call poll() in a child process.
|
Something broke |
#ifdef __MACH__ | ||
kill(_sigio_child_pids[i], SIGKILL); | ||
#endif | ||
real_close(_fds[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the culprit.
We need to add this again with the new code - #14638
Contribution description
async_read relies on
select()
to wait for file descriptors to become active.The problem with this is, that
select()
does not work forPOLLPRI
events that are generated when watching GPIO fds.In preparation for native GPIO support, this converts async_read from
select()
topoll()
.Unfortunately, no
SIGURG
signal is being generated after callingfcntl(fd, F_SETOWN, getpid())
, so the same fallback as on OS X is used for those: A child thread is spawned that blocks onpoll()
and manually generates the signal for the parent whenpoll()
returns.Testing procedure
Make sure
netdev_tap
still works by running thegnrc_networking
example.Also check if it still works on OS X.
Issues/PRs references
needed for #12451
taken from #7530
GPIO and SIGURG on StackOverflow