--- debian/patches/poll | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 debian/patches/poll
diff --git a/debian/patches/poll b/debian/patches/poll new file mode 100644 index 0000000..b85ae06 --- /dev/null +++ b/debian/patches/poll @@ -0,0 +1,518 @@ +--- a/src/api/sockets.c ++++ b/src/api/sockets.c +@@ -238,6 +238,12 @@ + fd_set *writeset; + /** unimplemented: exceptset passed to select */ + fd_set *exceptset; ++#if LWIP_POLL ++ /** fds passed to poll; NULL if select */ ++ struct pollfd *poll_fds; ++ /** nfds passed to poll; 0 if select */ ++ nfds_t poll_nfds; ++#endif + /** don't signal the same semaphore twice: set to 1 when signalled */ + int sem_signalled; + /** semaphore to wake up a task waiting for select */ +@@ -1288,6 +1294,51 @@ + return lwip_sendmsg(s, &msg, 0); + } + ++/* Add select_cb to select_cb_list. */ ++static void ++lwip_link_select_cb(struct lwip_select_cb *select_cb) ++{ ++ SYS_ARCH_DECL_PROTECT(lev); ++ ++ /* Protect the select_cb_list */ ++ SYS_ARCH_PROTECT(lev); ++ ++ /* Put this select_cb on top of list */ ++ select_cb->next = select_cb_list; ++ if (select_cb_list != NULL) { ++ select_cb_list->prev = select_cb; ++ } ++ select_cb_list = select_cb; ++ /* Increasing this counter tells event_callback that the list has changed. */ ++ select_cb_ctr++; ++ ++ /* Now we can safely unprotect */ ++ SYS_ARCH_UNPROTECT(lev); ++} ++ ++/* Remove select_cb from select_cb_list. */ ++void ++lwip_unlink_select_cb(struct lwip_select_cb *select_cb) ++{ ++ SYS_ARCH_DECL_PROTECT(lev); ++ ++ /* Take us off the list */ ++ SYS_ARCH_PROTECT(lev); ++ if (select_cb->next != NULL) { ++ select_cb->next->prev = select_cb->prev; ++ } ++ if (select_cb_list == select_cb) { ++ LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); ++ select_cb_list = select_cb->next; ++ } else { ++ LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); ++ select_cb->prev->next = select_cb->next; ++ } ++ /* Increasing this counter tells event_callback that the list has changed. */ ++ select_cb_ctr++; ++ SYS_ARCH_UNPROTECT(lev); ++} ++ + /** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have +@@ -1411,6 +1462,10 @@ + select_cb.readset = readset; + select_cb.writeset = writeset; + select_cb.exceptset = exceptset; ++#if LWIP_POLL ++ select_cb.poll_fds = NULL; ++ select_cb.poll_nfds = 0; ++#endif + select_cb.sem_signalled = 0; + #if LWIP_NETCONN_SEM_PER_THREAD + select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); +@@ -1422,20 +1477,7 @@ + } + #endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +- /* Protect the select_cb_list */ +- SYS_ARCH_PROTECT(lev); +- +- /* Put this select_cb on top of list */ +- select_cb.next = select_cb_list; +- if (select_cb_list != NULL) { +- select_cb_list->prev = &select_cb; +- } +- select_cb_list = &select_cb; +- /* Increasing this counter tells event_callback that the list has changed. */ +- select_cb_ctr++; +- +- /* Now we can safely unprotect */ +- SYS_ARCH_UNPROTECT(lev); ++ lwip_link_select_cb(&select_cb); + + /* Increase select_waiting for each socket we are interested in */ + maxfdp2 = maxfdp1; +@@ -1505,21 +1547,7 @@ + SYS_ARCH_UNPROTECT(lev); + } + } +- /* Take us off the list */ +- SYS_ARCH_PROTECT(lev); +- if (select_cb.next != NULL) { +- select_cb.next->prev = select_cb.prev; +- } +- if (select_cb_list == &select_cb) { +- LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); +- select_cb_list = select_cb.next; +- } else { +- LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); +- select_cb.prev->next = select_cb.next; +- } +- /* Increasing this counter tells event_callback that the list has changed. */ +- select_cb_ctr++; +- SYS_ARCH_UNPROTECT(lev); ++ lwip_unlink_select_cb(&select_cb); + + #if LWIP_NETCONN_SEM_PER_THREAD + if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { +@@ -1563,6 +1591,253 @@ + return nready; + } + ++#if LWIP_POLL ++ ++/** Options for the lwip_pollscan function. */ ++enum lwip_pollscan_opts ++{ ++ /** Clear revents in each struct pollfd. */ ++ LWIP_POLLSCAN_CLEAR = 1, ++ ++ /** Increment select_waiting in each struct lwip_sock. */ ++ LWIP_POLLSCAN_INC_WAIT = 2, ++ ++ /** Decrement select_waiting in each struct lwip_sock. */ ++ LWIP_POLLSCAN_DEC_WAIT = 4 ++}; ++ ++/** ++ * Update revents in each struct pollfd. ++ * Optionally update select_waiting in struct lwip_sock. ++ * ++ * @param fds array of structures to update ++ * @param nfds number of structures in fds ++ * @param opts what to update and how ++ * @return number of structures that have revents != 0 ++ */ ++static int ++lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) ++{ ++ int nready = 0; ++ nfds_t fdi; ++ struct lwip_sock *sock; ++ SYS_ARCH_DECL_PROTECT(lev); ++ ++ /* Go through each struct pollfd in the array. */ ++ for (fdi = 0; fdi < nfds; fdi++) { ++ if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { ++ fds[fdi].revents = 0; ++ } ++ ++ /* Negative fd means the caller wants us to ignore this struct. ++ POLLNVAL means we already detected that the fd is invalid; ++ if another thread has since opened a new socket with that fd, ++ we must not use that socket. */ ++ if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { ++ /* First get the socket's status (protected)... */ ++ SYS_ARCH_PROTECT(lev); ++ sock = tryget_socket(fds[fdi].fd); ++ if (sock != NULL) { ++ void* lastdata = sock->lastdata; ++ s16_t rcvevent = sock->rcvevent; ++ u16_t sendevent = sock->sendevent; ++ u16_t errevent = sock->errevent; ++ int err = sock->err; ++ ++ if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { ++ sock->select_waiting++; ++ LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); ++ } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { ++ /* @todo: what if this is a new socket (reallocated?) in this case, ++ select_waiting-- would be wrong (a global 'sockalloc' counter, ++ stored per socket could help; the POLLNVAL checks reduce the ++ risk but do not eliminate it) */ ++ LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); ++ if (sock->select_waiting > 0) { ++ sock->select_waiting--; ++ } ++ } ++ ++ SYS_ARCH_UNPROTECT(lev); ++ ++ /* ++ * FIXME: Workaround for handling the particular case when iioctl ++ * operations or fsysopts remove and add new interfaces while there are ++ * opened connections. ++ */ ++ if (err != ECONNABORTED) { ++ /* ... then examine it: */ ++ /* See if netconn of this socket is ready for read */ ++ if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { ++ fds[fdi].revents |= POLLIN; ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); ++ } ++ /* See if netconn of this socket is ready for write */ ++ if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { ++ fds[fdi].revents |= POLLOUT; ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); ++ } ++ /* See if netconn of this socket had an error */ ++ if (errevent != 0) { ++ /* POLLERR is output only. */ ++ fds[fdi].revents |= POLLERR; ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); ++ } ++ } ++ } else { ++ /* Not a valid socket */ ++ SYS_ARCH_UNPROTECT(lev); ++ /* POLLNVAL is output only. */ ++ fds[fdi].revents |= POLLNVAL; ++ /* continue on to next struct pollfd in array */ ++ } ++ } ++ ++ /* Will return the number of structures that have events, ++ not the number of events. */ ++ if (fds[fdi].revents != 0) { ++ nready++; ++ } ++ } ++ ++ LWIP_ASSERT("nready >= 0", nready >= 0); ++ return nready; ++} ++ ++int ++lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) ++{ ++ u32_t waitres = 0; ++ int nready; ++ u32_t msectimeout; ++ struct lwip_select_cb select_cb; ++#if LWIP_NETCONN_SEM_PER_THREAD ++ int waited = 0; ++#endif ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", ++ (void*)fds, (int)nfds, timeout)); ++ ++ /* Go through each struct pollfd to count number of structures ++ which currently match */ ++ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); ++ ++ /* If we don't have any current events, then suspend if we are supposed to */ ++ if (!nready) { ++ if (timeout == 0) { ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); ++ goto return_success; ++ } ++ ++ /* None ready: add our semaphore to list: ++ We don't actually need any dynamic memory. Our entry on the ++ list is only valid while we are in this function, so it's ok ++ to use local variables. */ ++ ++ select_cb.next = NULL; ++ select_cb.prev = NULL; ++ select_cb.readset = NULL; ++ select_cb.writeset = NULL; ++ select_cb.exceptset = NULL; ++ select_cb.poll_fds = fds; ++ select_cb.poll_nfds = nfds; ++ select_cb.sem_signalled = 0; ++#if LWIP_NETCONN_SEM_PER_THREAD ++ select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); ++#else /* LWIP_NETCONN_SEM_PER_THREAD */ ++ if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) { ++ /* failed to create semaphore */ ++ set_errno(ENOMEM); ++ return -1; ++ } ++#endif /* LWIP_NETCONN_SEM_PER_THREAD */ ++ ++ lwip_link_select_cb(&select_cb); ++ ++ /* Increase select_waiting for each socket we are interested in. ++ Also, check for events again: there could have been events between ++ the last scan (without us on the list) and putting us on the list! */ ++ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); ++ ++ if (!nready) { ++ /* Still none ready, just wait to be woken */ ++ if (timeout < 0) { ++ /* Wait forever */ ++ msectimeout = 0; ++ } else { ++ /* timeout == 0 would have been handled earlier. */ ++ LWIP_ASSERT("timeout > 0", timeout > 0); ++ msectimeout = timeout; ++ } ++ waitres = sys_arch_sem_wait_intr(SELECT_SEM_PTR(select_cb.sem), msectimeout); ++#if LWIP_NETCONN_SEM_PER_THREAD ++ waited = 1; ++#endif ++ } ++ ++ /* Decrease select_waiting for each socket we are interested in, ++ and check which events occurred while we waited. ++ It is OK to discard the previous value of nready because ++ we don't set LWIP_POLLSCAN_CLEAR. */ ++ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); ++ ++ lwip_unlink_select_cb(&select_cb); ++ ++#if LWIP_NETCONN_SEM_PER_THREAD ++ if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { ++ /* don't leave the thread-local semaphore signalled */ ++ sys_arch_sem_wait(select_cb.sem, 1); ++ } ++#else /* LWIP_NETCONN_SEM_PER_THREAD */ ++ sys_sem_free(&select_cb.sem); ++#endif /* LWIP_NETCONN_SEM_PER_THREAD */ ++ ++ /* Unlike lwip_select, lwip_poll never fails with EBADF; ++ it sets revents |= POLLNVAL, instead. */ ++ ++ if (waitres == SYS_ARCH_TIMEOUT) { ++ /* Timeout */ ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); ++ goto return_success; ++ } ++ } ++ ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); ++return_success: ++ set_errno(0); ++ return nready; ++} ++ ++/** ++ * Check whether event_callback should wake up a thread waiting in ++ * lwip_poll. ++ */ ++static int ++lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, struct lwip_sock *sock) ++{ ++ nfds_t fdi; ++ for (fdi = 0; fdi < scb->poll_nfds; fdi++) { ++ const struct pollfd *pollfd = &scb->poll_fds[fdi]; ++ if (pollfd->fd == fd) { ++ /* Do not update pollfd->revents right here; ++ that would be a data race because lwip_pollscan ++ accesses revents without protecting. */ ++ if (sock->rcvevent > 0 && (pollfd->events & POLLIN) != 0) { ++ return 1; ++ } ++ if (sock->sendevent != 0 && (pollfd->events & POLLOUT) != 0) { ++ return 1; ++ } ++ if (sock->errevent != 0) { ++ /* POLLERR is output only. */ ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++#endif /* LWIP_POLL */ ++ + /** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. +@@ -1649,20 +1924,27 @@ + if (scb->sem_signalled == 0) { + /* semaphore not signalled yet */ + int do_signal = 0; +- /* Test this select call for our socket */ +- if (sock->rcvevent > 0) { +- if (scb->readset && FD_ISSET(s, scb->readset)) { +- do_signal = 1; ++#if LWIP_POLL ++ if (scb->poll_fds != NULL) { ++ do_signal = lwip_poll_should_wake(scb, s, sock); ++ } else ++#endif /* LWIP_POLL */ ++ { ++ /* Test this select call for our socket */ ++ if (sock->rcvevent > 0) { ++ if (scb->readset && FD_ISSET(s, scb->readset)) { ++ do_signal = 1; ++ } + } +- } +- if (sock->sendevent != 0) { +- if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { +- do_signal = 1; ++ if (sock->sendevent != 0) { ++ if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { ++ do_signal = 1; ++ } + } +- } +- if (sock->errevent != 0) { +- if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { +- do_signal = 1; ++ if (sock->errevent != 0) { ++ if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { ++ do_signal = 1; ++ } + } + } + if (do_signal) { +--- a/src/include/lwip/opt.h ++++ b/src/include/lwip/opt.h +@@ -1751,6 +1751,17 @@ + #endif + + /** ++ * LWIP_POLL==0: Do not define lwip_poll. ++ * LWIP_POLL==1: Define lwip_poll, using someone else's data types. ++ * LWIP_POLL==2: Define lwip_poll, struct pollfd, nfds_t, and constants. ++ */ ++#if defined __DOXYGEN__ ++#define LWIP_POLL 1 ++#elif !defined LWIP_POLL ++#define LWIP_POLL 0 ++#endif ++ ++/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) +--- a/src/include/lwip/lwip_sockets.h ++++ b/src/include/lwip/lwip_sockets.h +@@ -430,6 +430,21 @@ + #error "external FD_SETSIZE too small for number of sockets" + #endif /* FD_SET */ + ++#if LWIP_POLL == 2 ++#define POLLIN 0x01 ++#define POLLOUT 0x02 ++#define POLLERR 0x04 ++#define POLLNVAL 0x08 ++/* No support for POLLPRI, POLLHUP, POLLMSG, POLLRDBAND, POLLWRBAND. */ ++typedef int nfds_t; ++struct pollfd ++{ ++ int fd; ++ short events; ++ short revents; ++}; ++#endif ++ + /** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include <sys/time.h> in cc.h */ + #ifndef LWIP_TIMEVAL_PRIVATE +@@ -466,6 +481,9 @@ + #define lwip_sendto sendto + #define lwip_socket socket + #define lwip_select select ++#if LWIP_POLL ++#define lwip_poll poll ++#endif + #define lwip_ioctlsocket ioctl + + #if LWIP_POSIX_SOCKETS_IO_NAMES +@@ -516,6 +534,10 @@ + #define socket(domain,type,protocol) lwip_socket(domain,type,protocol) + /** @ingroup socket */ + #define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) ++#if LWIP_POLL ++/** @ingroup socket */ ++#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) ++#endif + /** @ingroup socket */ + #define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) + +--- a/src/include/lwip/sockets.h ++++ b/src/include/lwip/sockets.h +@@ -75,6 +75,9 @@ + int lwip_writev(int s, const struct iovec *iov, int iovcnt); + int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); ++#if LWIP_POLL ++int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); ++#endif + int lwip_ioctl(int s, long cmd, void *argp); + int lwip_fcntl(int s, int cmd, int val); + +--- a/port/include/lwipopts.h ++++ b/port/include/lwipopts.h +@@ -26,6 +26,9 @@ + /* Don't rename Sockets API functions */ + #define LWIP_COMPAT_SOCKETS 0 + ++/* We're using lwip_poll() */ ++#define LWIP_POLL 1 ++ + /* Use Glibc's sockets headers */ + #define LWIP_STD_SOCKETS 1 + #define LWIP_INCLUDE_STD_SOCKETS "posix/socket.h" +--- a/port/include/arch/cc.h ++++ b/port/include/arch/cc.h +@@ -46,6 +46,9 @@ + #include <netinet/tcp.h> + #include <netinet/udp.h> + ++/* We use poll() instead of select()*/ ++#include <poll.h> ++ + /* Use our own htons() and pals */ + #define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 1 + -- 2.14.0