From: Roy Marples Date: Sun, 10 Feb 2008 23:01:44 +0000 (+0000) Subject: Replace select with poll and nanosleep. X-Git-Tag: v3.2.3~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b014ee76e17164890317b5a3d9ba070533560f41;p=thirdparty%2Fdhcpcd.git Replace select with poll and nanosleep. --- diff --git a/arp.c b/arp.c index 6d4f5bc8..794850c7 100644 --- a/arp.c +++ b/arp.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #ifdef __linux__ @@ -39,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -53,9 +53,9 @@ /* These are really for IPV4LL */ #define NPROBES 3 -#define PROBE_INTERVAL 200000 +#define PROBE_INTERVAL 200 #define NCLAIMS 2 -#define CLAIM_INTERVAL 200000 +#define CLAIM_INTERVAL 200 /* Linux does not seem to define these handy macros */ #ifndef ar_sha @@ -116,6 +116,10 @@ int arp_claim (interface_t *iface, struct in_addr address) int nprobes = 0; int nclaims = 0; struct in_addr null_address; + struct pollfd fds[] = { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; if (! iface) return (-1); @@ -134,29 +138,25 @@ int arp_claim (interface_t *iface, struct in_addr address) if (! open_socket (iface, ETHERTYPE_ARP)) return (-1); + fds[0].fd = signal_fd (); + fds[1].fd = iface->fd; + memset (&null_address, 0, sizeof (null_address)); buffer = xmalloc (iface->buffer_length); reply = xmalloc (iface->buffer_length); for (;;) { - struct timeval tv; size_t bufpos = 0; size_t buflen = iface->buffer_length; - fd_set rset; int bytes; int s = 0; - int maxfd; struct timeval stopat; struct timeval now; - /* Only select if we have a timeout */ + /* Only poll if we have a timeout */ if (timeout > 0) { - tv.tv_sec = 0; - tv.tv_usec = timeout; - - maxfd = signal_fd_set (&rset, iface->fd); - s = select (maxfd + 1, &rset, NULL, NULL, &tv); + s = poll (fds, 2, timeout); if (s == -1) { if (errno == EINTR) { if (signal_exists (NULL) == -1) { @@ -166,7 +166,7 @@ int arp_claim (interface_t *iface, struct in_addr address) break; } - logger (LOG_ERR, "select: `%s'", + logger (LOG_ERR, "poll: `%s'", strerror (errno)); break; } @@ -220,7 +220,7 @@ int arp_claim (interface_t *iface, struct in_addr address) continue; } - if (! FD_ISSET (iface->fd, &rset)) + if (! fds[1].revents & POLLIN) continue; memset (buffer, 0, buflen); diff --git a/client.c b/client.c index 2975ac85..8630186d 100644 --- a/client.c +++ b/client.c @@ -31,13 +31,13 @@ #include #include -#include #include #ifdef __linux__ # include #endif #include #include +#include #include #include #include @@ -78,9 +78,10 @@ # endif #endif -/* We need this for our maximum timeout as FreeBSD's select cannot handle - * any higher than this. Is there a better way of working this out? */ -#define SELECT_MAX 100000000 +/* Some platforms don't define INFTIM */ +#ifndef INFTIM +# define INFTIM -1 +#endif /* This is out mini timeout. * Basically we resend the last request every TIMEOUT_MINI seconds. */ @@ -104,6 +105,10 @@ #define SOCKET_CLOSED 0 #define SOCKET_OPEN 1 +/* Indexes for pollfds */ +#define POLLFD_SIGNAL 0 +#define POLLFD_IFACE 1 + typedef struct _state { int *pidfd; bool forked; @@ -460,47 +465,41 @@ static void drop_config (state_t *state, const options_t *options) memset (state->dhcp, 0, sizeof (*state->dhcp)); } -static int wait_for_packet (fd_set *rset, state_t *state, +static int wait_for_packet (struct pollfd *fds, state_t *state, const options_t *options) { dhcp_t *dhcp = state->dhcp; interface_t *iface = state->interface; + int timeout = 0; int retval = 0; - struct timeval tv; - int maxfd; if (! (state->timeout > 0 || (options->timeout == 0 && (state->state != STATE_INIT || state->xid)))) { - /* We need to zero our rset, otherwise we will block trying - * to read a signal. */ - FD_ZERO (rset); + /* We need to zero our signal fd, otherwise we will block + * trying to read a signal. */ + fds[POLLFD_SIGNAL].revents = 0; return (0); } + fds[POLLFD_IFACE].fd = iface->fd; + if ((options->timeout == 0 && state->xid) || (dhcp->leasetime == (unsigned) -1 && state->state == STATE_BOUND)) { - int retry = 0; - - logger (LOG_DEBUG, "waiting on select for infinity"); + logger (LOG_DEBUG, "waiting for infinity"); while (retval == 0) { - maxfd = signal_fd_set (rset, iface->fd); if (iface->fd == -1) - retval = select (maxfd + 1, rset, - NULL, NULL, NULL); + retval = poll (fds, 1, INFTIM); else { /* Slow down our requests */ - if (retry < TIMEOUT_MINI_INF) - retry += TIMEOUT_MINI; - else if (retry > TIMEOUT_MINI_INF) - retry = TIMEOUT_MINI_INF; - - tv.tv_sec = retry; - tv.tv_usec = 0; - retval = select (maxfd + 1, rset, - NULL, NULL, &tv); + if (timeout < TIMEOUT_MINI_INF) + timeout += TIMEOUT_MINI; + else if (timeout > TIMEOUT_MINI_INF) + timeout = TIMEOUT_MINI_INF; + + retval = poll (fds, 2, timeout * 1000); if (retval == 0) _send_message (state, state->last_type, options); @@ -516,22 +515,20 @@ static int wait_for_packet (fd_set *rset, state_t *state, if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) _send_message (state, state->last_type, options); - logger (LOG_DEBUG, "waiting on select for %ld seconds", + logger (LOG_DEBUG, "waiting for %ld seconds", (unsigned long) state->timeout); /* If we're waiting for a reply, then we re-send the last * DHCP request periodically in-case of a bad line */ retval = 0; while (state->timeout > 0 && retval == 0) { if (iface->fd == -1) - tv.tv_sec = SELECT_MAX; + timeout = INFTIM; else - tv.tv_sec = TIMEOUT_MINI; - if (state->timeout < tv.tv_sec) - tv.tv_sec = (time_t) state->timeout; - tv.tv_usec = 0; + timeout = TIMEOUT_MINI; + if (state->timeout < timeout) + timeout = (int) state->timeout; state->start = uptime (); - maxfd = signal_fd_set (rset, iface->fd); - retval = select (maxfd + 1, rset, NULL, NULL, &tv); + retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout * 1000); state->timeout -= uptime () - state->start; if (retval == 0 && iface->fd != -1 && state->timeout > 0) _send_message (state, state->last_type, options); @@ -765,7 +762,7 @@ static int handle_timeout (state_t *state, const options_t *options) static int handle_dhcp (state_t *state, int type, const options_t *options) { - struct timeval tv; + struct timespec ts; interface_t *iface = state->interface; dhcp_t *dhcp = state->dhcp; @@ -782,12 +779,12 @@ static int handle_dhcp (state_t *state, int type, const options_t *options) if (state->nakoff > 0) { logger (LOG_DEBUG, "sleeping for %ld seconds", (long) state->nakoff); - tv.tv_sec = state->nakoff; - tv.tv_usec = 0; + ts.tv_sec = state->nakoff; + ts.tv_nsec = 0; state->nakoff *= 2; if (state->nakoff > NAKOFF_MAX) state->nakoff = NAKOFF_MAX; - select (0, NULL, NULL, NULL, &tv); + nanosleep (&ts, NULL); } return (0); @@ -864,9 +861,9 @@ static int handle_dhcp (state_t *state, int type, const options_t *options) /* RFC 2131 says that we should wait for 10 seconds * before doing anything else */ logger (LOG_INFO, "sleeping for 10 seconds"); - tv.tv_sec = 10; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); + ts.tv_sec = 10; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); return (0); } else if (errno == EINTR) return (0); @@ -892,7 +889,7 @@ static int handle_dhcp (state_t *state, int type, const options_t *options) state->state = STATE_INIT; } else if (dhcp->leasetime == (unsigned) -1) { dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; - state->timeout = 1; /* So we select on infinity */ + state->timeout = 1; /* So we wait for infinity */ logger (LOG_INFO, "leased %s for infinity", inet_ntoa (dhcp->address)); state->state = STATE_BOUND; @@ -1039,7 +1036,10 @@ int dhcp_run (const options_t *options, int *pidfd) { interface_t *iface; state_t *state = NULL; - fd_set rset; + struct pollfd fds[] = { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; int retval = -1; int sig; @@ -1063,11 +1063,13 @@ int dhcp_run (const options_t *options, int *pidfd) if (signal_setup () == -1) goto eexit; + fds[POLLFD_SIGNAL].fd = signal_fd (); + for (;;) { - retval = wait_for_packet (&rset, state, options); + retval = wait_for_packet (fds, state, options); /* We should always handle our signals first */ - if ((sig = (signal_read (&rset))) != -1) { + if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) { if (handle_signal (sig, state, options)) retval = 0; else @@ -1076,14 +1078,13 @@ int dhcp_run (const options_t *options, int *pidfd) retval = handle_timeout (state, options); else if (retval > 0 && state->socket != SOCKET_CLOSED && - FD_ISSET (iface->fd, &rset)) + fds[POLLFD_IFACE].revents & POLLIN) retval = handle_packet (state, options); else if (retval == -1 && errno == EINTR) { /* The interupt will be handled above */ retval = 0; } else { - logger (LOG_ERR, "error on select: %s", - strerror (errno)); + logger (LOG_ERR, "poll: %s", strerror (errno)); retval = -1; } diff --git a/interface.c b/interface.c index 6f546487..0b608a97 100644 --- a/interface.c +++ b/interface.c @@ -684,7 +684,7 @@ static int do_route (const char *ifname, * send_netlink handles the actual transmission so we can work out * if there was an error or not. */ #define BUFFERLEN 256 -static int send_netlink(struct nlmsghdr *hdr) +int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) { int s; pid_t mypid = getpid (); @@ -795,9 +795,15 @@ static int send_netlink(struct nlmsghdr *hdr) } if (err->error == 0) { + int retval = 0; + close (s); + if (callback) { + if ((retval = callback (hdr, arg)) == -1) + logger (LOG_ERR, "netlink: callback failed"); + } free (buffer); - return 0; + return (retval); } errno = -err->error; @@ -910,7 +916,7 @@ static int do_address(const char *ifname, add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, &broadcast.s_addr, sizeof (broadcast.s_addr)); - retval = send_netlink (&nlm->hdr); + retval = send_netlink (&nlm->hdr, NULL, NULL); free (nlm); return retval; } @@ -971,7 +977,7 @@ static int do_route (const char *ifname, add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); - retval = send_netlink (&nlm->hdr); + retval = send_netlink (&nlm->hdr, NULL, NULL); free (nlm); return retval; } diff --git a/interface.h b/interface.h index 6a05a6b8..61bf1e90 100644 --- a/interface.h +++ b/interface.h @@ -150,4 +150,8 @@ int del_route (const char *ifname, struct in_addr destination, int inet_ntocidr (struct in_addr address); int inet_cidrtoaddr (int cidr, struct in_addr *addr); +#ifdef __linux__ +typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg); +int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg); +#endif #endif diff --git a/signal.c b/signal.c index c9430e1c..37b59e8f 100644 --- a/signal.c +++ b/signal.c @@ -27,8 +27,8 @@ #include #include -#include #include +#include #include #include #include @@ -67,20 +67,15 @@ static void signal_handler (int sig) errno = serrno; } -/* Add the signal pipe to an fd set */ -int signal_fd_set (fd_set *rset, int fd) +int signal_fd (void) { - FD_ZERO (rset); - FD_SET (signal_pipe[0], rset); - if (fd >= 0) - FD_SET (fd, rset); - return (signal_pipe[0] > fd ? signal_pipe[0] : fd); + return (signal_pipe[0]); } /* Check if we have a signal or not */ -int signal_exists (const fd_set *rset) +int signal_exists (const struct pollfd *fd) { - if (signals[0] || (rset && FD_ISSET (signal_pipe[0], rset))) + if (signals[0] || (fd && fd->revents & POLLIN)) return (0); return (-1); } @@ -88,7 +83,7 @@ int signal_exists (const fd_set *rset) /* Read a signal from the signal pipe. Returns 0 if there is * no signal, -1 on error (and sets errno appropriately), and * your signal on success */ -int signal_read (fd_set *rset) +int signal_read (struct pollfd *fd) { int sig = -1; @@ -104,7 +99,7 @@ int signal_read (fd_set *rset) } } - if (rset && FD_ISSET (signal_pipe[0], rset)) { + if (fd && fd->revents & POLLIN) { char buf[16]; size_t bytes; @@ -117,7 +112,7 @@ int signal_read (fd_set *rset) /* We need to clear us from rset if nothing left in the buffer * in case we are called many times */ if (bytes == sizeof (sig)) - FD_CLR (signal_pipe[0], rset); + fd->revents = 0; } return (sig); diff --git a/signal.h b/signal.h index e72b9964..63a59060 100644 --- a/signal.h +++ b/signal.h @@ -28,11 +28,13 @@ #ifndef SIGNAL_H #define SIGNAL_H +#include + int signal_init (void); int signal_setup (void); int signal_reset (void); -int signal_fd_set (fd_set *rset, int fd); -int signal_exists (const fd_set *rset); -int signal_read (fd_set *rset); +int signal_fd (void); +int signal_exists (const struct pollfd *fd); +int signal_read (struct pollfd *fd); #endif diff --git a/socket.c b/socket.c index 814d051b..8292705f 100644 --- a/socket.c +++ b/socket.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include #include #include +#include #include #ifdef BSD @@ -375,12 +375,12 @@ ssize_t get_packet (const interface_t *iface, unsigned char *data, *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); *buffer_pos = 0; if (*buffer_len < 1) { - struct timeval tv; + struct timespec tv; logger (LOG_ERR, "read: %s", strerror (errno)); - tv.tv_sec = 3; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); - return -1; + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (-1); } } else bpf.buffer += *buffer_pos; @@ -566,11 +566,11 @@ ssize_t get_packet (const interface_t *iface, unsigned char *data, bytes = read (iface->fd, buffer, iface->buffer_length); if (bytes == -1) { - struct timeval tv; + struct timespec ts; logger (LOG_ERR, "read: %s", strerror (errno)); - tv.tv_sec = 3; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); return (-1); }