This helper macro provides a convenient implementation of the
beforepoll_fn interface for *nfds_io. Use it everywhere.
This produces one bugfix: log_from_fd_beforepoll would fail to set
*nfds_io if it was finished,
This also arranges for many beforepoll callbacks to actually fail
properly with ERANGE if there is not enough space. Previously they
would blithely write the next fd entry or two. In practice the
provided fd array never runs out in the current code, so in these
cases we are just fixing latent bugs.
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
{
struct fdlog *st=sst;
if (!st->finished) {
{
struct fdlog *st=sst;
if (!st->finished) {
+ BEFOREPOLL_WANT_FDS(1);
fds[0].fd=st->fd;
fds[0].events=POLLIN;
fds[0].fd=st->fd;
fds[0].events=POLLIN;
+ } else {
+ BEFOREPOLL_WANT_FDS(0);
static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
int *timeout_io)
{
static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
int *timeout_io)
{
- if (*nfds_io<1) {
- *nfds_io=1;
- return ERANGE;
- }
- *nfds_io=1;
+ BEFOREPOLL_WANT_FDS(1);
fds[0].fd=spr;
fds[0].events=POLLIN;
return 0;
fds[0].fd=spr;
fds[0].events=POLLIN;
return 0;
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/time.h>
int *timeout_io);
typedef void afterpoll_fn(void *st, struct pollfd *fds, int nfds);
int *timeout_io);
typedef void afterpoll_fn(void *st, struct pollfd *fds, int nfds);
+/* void BEFOREPOLL_WANT_FDS(int want);
+ * Expects: int *nfds_io;
+ * Can perform non-local exit.
+ * Checks whether there is space for want fds. If so, sets *nfds_io.
+ * If not, sets *nfds_io and returns. */
+#define BEFOREPOLL_WANT_FDS(want) do{ \
+ if (*nfds_io<(want)) { *nfds_io=(want); return ERANGE; } \
+ *nfds_io=(want); \
+ }while(0)
+
/* Register interest in the main loop of the program. Before a call
to poll() your supplied beforepoll function will be called. After
the call to poll() the supplied afterpoll function will be called.
/* Register interest in the main loop of the program. Before a call
to poll() your supplied beforepoll function will be called. After
the call to poll() the supplied afterpoll function will be called.
- *nfds_io=0; /* We don't use any file descriptors */
+ BEFOREPOLL_WANT_FDS(0); /* We don't use any file descriptors */
st->now=*now;
/* Work out when our next timeout is. The earlier of 'timeout' or
st->now=*now;
/* Work out when our next timeout is. The earlier of 'timeout' or
struct userv *st=sst;
if (st->rxfd!=-1) {
struct userv *st=sst;
if (st->rxfd!=-1) {
+ BEFOREPOLL_WANT_FDS(2);
fds[0].fd=st->txfd;
fds[0].events=0; /* Might want to pick up POLLOUT sometime */
fds[1].fd=st->rxfd;
fds[1].events=POLLIN;
} else {
fds[0].fd=st->txfd;
fds[0].events=0; /* Might want to pick up POLLOUT sometime */
fds[1].fd=st->rxfd;
fds[1].events=POLLIN;
} else {
+ BEFOREPOLL_WANT_FDS(0);
int *timeout_io)
{
struct tun *st=sst;
int *timeout_io)
{
struct tun *st=sst;
+ BEFOREPOLL_WANT_FDS(1);
fds[0].fd=st->fd;
fds[0].events=POLLIN;
return 0;
fds[0].fd=st->fd;
fds[0].events=POLLIN;
return 0;
{
int i;
struct udp *st=state;
{
int i;
struct udp *st=state;
- if (*nfds_io<st->n_socks) {
- *nfds_io=st->n_socks;
- return ERANGE;
- }
- *nfds_io=st->n_socks;
+ BEFOREPOLL_WANT_FDS(st->n_socks);
for (i=0; i<st->n_socks; i++) {
fds[i].fd=st->socks[i].fd;
fds[i].events=POLLIN;
for (i=0; i<st->n_socks; i++) {
fds[i].fd=st->socks[i].fd;
fds[i].events=POLLIN;