cpu/native: async_read: rewrite select() call to poll()

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().
This commit is contained in:
Koen Zandberg 2017-08-20 10:49:49 +02:00 committed by Benjamin Valentin
parent e8a8d12d96
commit a274ea45fc
4 changed files with 48 additions and 43 deletions

View File

@ -22,41 +22,25 @@
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include "async_read.h"
#include "native_internal.h"
static int _next_index;
static int _fds[ASYNC_READ_NUMOF];
static void *_args[ASYNC_READ_NUMOF];
static native_async_read_callback_t _native_async_read_callbacks[ASYNC_READ_NUMOF];
static struct pollfd _fds[ASYNC_READ_NUMOF];
static async_read_t pollers[ASYNC_READ_NUMOF];
#ifdef __MACH__
static pid_t _sigio_child_pids[ASYNC_READ_NUMOF];
static void _sigio_child(int fd);
#endif
static void _async_io_isr(void) {
fd_set rfds;
FD_ZERO(&rfds);
int max_fd = 0;
struct timeval timeout = { .tv_usec = 0 };
for (int i = 0; i < _next_index; i++) {
FD_SET(_fds[i], &rfds);
if (max_fd < _fds[i]) {
max_fd = _fds[i];
}
}
if (real_select(max_fd + 1, &rfds, NULL, NULL, &timeout) > 0) {
if (real_poll(_fds, _next_index, 0) > 0) {
for (int i = 0; i < _next_index; i++) {
if (FD_ISSET(_fds[i], &rfds)) {
_native_async_read_callbacks[i](_fds[i], _args[i]);
/* handle if one of the events has happened */
if (_fds[i].revents & _fds[i].events) {
pollers[i].cb(_fds[i].fd, pollers[i].arg);
}
}
}
@ -70,22 +54,29 @@ void native_async_read_cleanup(void) {
unregister_interrupt(SIGIO);
for (int i = 0; i < _next_index; i++) {
#ifdef __MACH__
kill(_sigio_child_pids[i], SIGKILL);
#endif
real_close(_fds[i]);
if (pollers[i].child_pid) {
kill(pollers[i].child_pid, SIGKILL);
}
}
}
void native_async_read_continue(int fd) {
(void) fd;
#ifdef __MACH__
for (int i = 0; i < _next_index; i++) {
if (_fds[i] == fd) {
kill(_sigio_child_pids[i], SIGCONT);
if (_fds[i].fd == fd && pollers[i].child_pid) {
kill(pollers[i].child_pid, SIGCONT);
}
}
#endif
}
static void _add_handler(int fd, void *arg, native_async_read_callback_t handler) {
_fds[_next_index].fd = fd;
_fds[_next_index].events = POLLIN | POLLPRI;
async_read_t *poll = &pollers[_next_index];
poll->child_pid = 0;
poll->cb = handler;
poll->arg = arg;
poll->fd = &_fds[_next_index];
}
void native_async_read_add_handler(int fd, void *arg, native_async_read_callback_t handler) {
@ -93,13 +84,11 @@ void native_async_read_add_handler(int fd, void *arg, native_async_read_callback
err(EXIT_FAILURE, "native_async_read_add_handler(): too many callbacks");
}
_fds[_next_index] = fd;
_args[_next_index] = arg;
_native_async_read_callbacks[_next_index] = handler;
_add_handler(fd, arg, handler);
#ifdef __MACH__
/* tuntap signalled IO is not working in OSX,
* * check http://sourceforge.net/p/tuntaposx/bugs/17/ */
* * check http://sourceforge.net/p/tuntaposx/bugs/18/ */
#ifdef __MACH__
_sigio_child(_next_index);
#else
/* configure fds to send signals on io */
@ -118,14 +107,15 @@ void native_async_read_add_handler(int fd, void *arg, native_async_read_callback
#ifdef __MACH__
static void _sigio_child(int index)
{
int fd = _fds[index];
struct pollfd fds = _fds[index];
async_read_t *poll = &pollers[_next_index];
pid_t parent = _native_pid;
pid_t child;
if ((child = real_fork()) == -1) {
err(EXIT_FAILURE, "sigio_child: fork");
}
if (child > 0) {
_sigio_child_pids[index] = child;
poll->child_pid = child;
/* return in parent process */
return;
@ -139,11 +129,8 @@ static void _sigio_child(int index)
/* watch tap interface and signal parent process if data is
* available */
fd_set rfds;
while (1) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (real_select(fd + 1, &rfds, NULL, NULL, NULL) == 1) {
if (real_poll(&fds, 1, -1) == 1) {
kill(parent, SIGIO);
}
else {

View File

@ -18,6 +18,9 @@
#ifndef ASYNC_READ_H
#define ASYNC_READ_H
#include <stdlib.h>
#include <poll.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -34,6 +37,16 @@ extern "C" {
*/
typedef void (*native_async_read_callback_t)(int fd, void *arg);
/**
* @brief Interrupt callback information structure
*/
typedef struct {
pid_t child_pid; /**< PID of the interrupt listener */
native_async_read_callback_t cb; /**< Interrupt callback funtion */
void *arg; /**< Argument ptr for the callback */
struct pollfd *fd; /**< sysfs gpio fd */
} async_read_t;
/**
* @brief initialize asynchronus read system
*

View File

@ -21,6 +21,7 @@
#include <signal.h>
#include <stdio.h>
#include <poll.h>
/* enable signal handler register access on different platforms
* check here for more:
* http://sourceforge.net/p/predef/wiki/OperatingSystems/
@ -117,6 +118,7 @@ extern int (*real_pause)(void);
extern int (*real_pipe)(int[2]);
/* The ... is a hack to save includes: */
extern int (*real_select)(int nfds, ...);
extern int (*real_poll)(struct pollfd *nfds, ...);
extern int (*real_setitimer)(int which, const struct itimerval
*__restrict value, struct itimerval *__restrict ovalue);
extern int (*real_setsid)(void);

View File

@ -25,6 +25,7 @@
#include <err.h>
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
@ -83,6 +84,7 @@ int (*real_open)(const char *path, int oflag, ...);
int (*real_pause)(void);
int (*real_pipe)(int[2]);
int (*real_select)(int nfds, ...);
int (*real_poll)(struct pollfd *fds, ...);
int (*real_setitimer)(int which, const struct itimerval
*restrict value, struct itimerval *restrict ovalue);
int (*real_setsid)(void);
@ -462,6 +464,7 @@ void _native_init_syscalls(void)
*(void **)(&real_fork) = dlsym(RTLD_NEXT, "fork");
*(void **)(&real_dup2) = dlsym(RTLD_NEXT, "dup2");
*(void **)(&real_select) = dlsym(RTLD_NEXT, "select");
*(void **)(&real_poll) = dlsym(RTLD_NEXT, "poll");
*(void **)(&real_setitimer) = dlsym(RTLD_NEXT, "setitimer");
*(void **)(&real_setsid) = dlsym(RTLD_NEXT, "setsid");
*(void **)(&real_setsockopt) = dlsym(RTLD_NEXT, "setsockopt");