]> xenbits.xensource.com Git - people/liuw/mini-os.git/commitdiff
mini-os: implement poll(2)
authorWei Liu <wei.liu2@citrix.com>
Mon, 25 Mar 2013 11:17:30 +0000 (11:17 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Thu, 11 Apr 2013 14:42:39 +0000 (15:42 +0100)
It is just a wrapper around select(2). This implementation mimics Linux's
do_poll.

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
include/posix/poll.h [new file with mode: 0644]
lib/sys.c

diff --git a/include/posix/poll.h b/include/posix/poll.h
new file mode 100644 (file)
index 0000000..06fb41a
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/poll.h>
index 3cc334000cc8bffa573353186517a08f759571c9..cfbdc90eb9415a2fa0cb4a1a118c0ac3c51df234 100644 (file)
--- a/lib/sys.c
+++ b/lib/sys.c
@@ -31,6 +31,7 @@
 #include <tpm_tis.h>
 #include <xenbus.h>
 #include <xenstore.h>
+#include <poll.h>
 
 #include <sys/types.h>
 #include <sys/unistd.h>
@@ -678,6 +679,29 @@ static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *except
 #define dump_set(nfds, readfds, writefds, exceptfds, timeout)
 #endif
 
+#ifdef LIBC_DEBUG
+static void dump_pollfds(struct pollfd *pfd, int nfds, int timeout)
+{
+    int i, comma, fd;
+
+    printk("[");
+    comma = 0;
+    for (i = 0; i < nfds; i++) {
+        fd = pfd[i].fd;
+        if (comma)
+            printk(", ");
+        printk("%d(%c)/%02x", fd, file_types[files[fd].type],
+            pfd[i].events);
+            comma = 1;
+    }
+    printk("]");
+
+    printk(", %d, %d", nfds, timeout);
+}
+#else
+#define dump_pollfds(pfds, nfds, timeout)
+#endif
+
 /* Just poll without blocking */
 static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
 {
@@ -983,6 +1007,98 @@ out:
     return ret;
 }
 
+/* Wrap around select */
+int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
+{
+    int n, ret;
+    int i, fd;
+    struct timeval _timeo, *timeo = NULL;
+    fd_set rfds, wfds, efds;
+    int max_fd = -1;
+
+    DEBUG("poll(");
+    dump_pollfds(_pfd, _nfds, _timeout);
+    DEBUG(")\n");
+
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&efds);
+
+    n = 0;
+
+    for (i = 0; i < _nfds; i++) {
+        fd = _pfd[i].fd;
+        _pfd[i].revents = 0;
+
+        /* fd < 0, revents = 0, which is already set */
+        if (fd < 0) continue;
+
+        /* fd is invalid, revents = POLLNVAL, increment counter */
+        if (fd >= NOFILE || files[fd].type == FTYPE_NONE) {
+            n++;
+            _pfd[i].revents |= POLLNVAL;
+            continue;
+        }
+
+        /* normal case, map POLL* into readfds and writefds:
+         * POLLIN  -> readfds
+         * POLLOUT -> writefds
+         * POLL*   -> none
+         */
+        if (_pfd[i].events & POLLIN)
+            FD_SET(fd, &rfds);
+        if (_pfd[i].events & POLLOUT)
+            FD_SET(fd, &wfds);
+        /* always set exceptfds */
+        FD_SET(fd, &efds);
+        if (fd > max_fd)
+            max_fd = fd;
+    }
+
+    /* should never sleep when we already have events */
+    if (n) {
+        _timeo.tv_sec  = 0;
+        _timeo.tv_usec = 0;
+        timeo = &_timeo;
+    } else if (_timeout >= 0) {
+        /* normal case, construct _timeout, might sleep */
+        _timeo.tv_sec  = _timeout / 1000;
+        _timeo.tv_usec = (_timeout % 1000) * 1000;
+        timeo = &_timeo;
+    } else {
+        /* _timeout < 0, block forever */
+        timeo = NULL;
+    }
+
+
+    ret = select(max_fd+1, &rfds, &wfds, &efds, timeo);
+    /* error in select, just return, errno is set by select() */
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < _nfds; i++) {
+        fd = _pfd[i].fd;
+
+        /* the revents has already been set for all error case */
+        if (fd < 0 || fd >= NOFILE || files[fd].type == FTYPE_NONE)
+            continue;
+
+        if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds) || FD_ISSET(fd, &efds))
+            n++;
+        if (FD_ISSET(fd, &efds)) {
+            /* anything bad happens we set POLLERR */
+            _pfd[i].revents |= POLLERR;
+            continue;
+        }
+        if (FD_ISSET(fd, &rfds))
+            _pfd[i].revents |= POLLIN;
+        if (FD_ISSET(fd, &wfds))
+            _pfd[i].revents |= POLLOUT;
+    }
+
+    return n;
+}
+
 #ifdef HAVE_LWIP
 int socket(int domain, int type, int protocol)
 {
@@ -1360,7 +1476,6 @@ unsupported_function(int, tcgetattr, 0);
 unsupported_function(int, grantpt, -1);
 unsupported_function(int, unlockpt, -1);
 unsupported_function(char *, ptsname, NULL);
-unsupported_function(int, poll, -1);
 
 /* net/if.h */
 unsupported_function_log(unsigned int, if_nametoindex, -1);