kernel-libipsec: Use poll(2) instead of select
authorMartin Willi <martin@revosec.ch>
Wed, 5 Nov 2014 16:44:30 +0000 (17:44 +0100)
committerMartin Willi <martin@revosec.ch>
Fri, 21 Nov 2014 11:02:07 +0000 (12:02 +0100)
src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c

index 6ce1d4e..830954e 100644 (file)
@@ -131,35 +131,6 @@ static void deliver_plain(private_kernel_libipsec_router_t *this,
 }
 
 /**
- * Create an FD set covering all TUN devices and the read end of the notify pipe
- */
-static int collect_fds(private_kernel_libipsec_router_t *this, fd_set *fds)
-{
-       enumerator_t *enumerator;
-       tun_entry_t *entry;
-       int maxfd;
-
-       FD_ZERO(fds);
-       FD_SET(this->notify[0], fds);
-       maxfd = this->notify[0];
-
-       FD_SET(this->tun.fd, fds);
-       maxfd = max(maxfd, this->tun.fd);
-
-       this->lock->read_lock(this->lock);
-       enumerator = this->tuns->create_enumerator(this->tuns);
-       while (enumerator->enumerate(enumerator, NULL, &entry))
-       {
-               FD_SET(entry->fd, fds);
-               maxfd = max(maxfd, entry->fd);
-       }
-       enumerator->destroy(enumerator);
-       this->lock->unlock(this->lock);
-
-       return maxfd + 1;
-}
-
-/**
  * Read and process outbound plaintext packet for the given TUN device
  */
 static void process_plain(tun_device_t *tun)
@@ -183,29 +154,20 @@ static void process_plain(tun_device_t *tun)
 }
 
 /**
- * Handle waiting data for any TUN device
+ * Find flagged revents in a pollfd set by fd
  */
-static void handle_tuns(private_kernel_libipsec_router_t *this, fd_set *fds)
+static int find_revents(struct pollfd *pfd, int count, int fd)
 {
-       enumerator_t *enumerator;
-       tun_entry_t *entry;
+       int i;
 
-       if (FD_ISSET(this->tun.fd, fds))
+       for (i = 0; i < count; i++)
        {
-               process_plain(this->tun.tun);
-       }
-
-       this->lock->read_lock(this->lock);
-       enumerator = this->tuns->create_enumerator(this->tuns);
-       while (enumerator->enumerate(enumerator, NULL, &entry))
-       {
-               if (FD_ISSET(entry->fd, fds))
+               if (pfd[i].fd == fd)
                {
-                       process_plain(entry->tun);
+                       return pfd[i].revents;
                }
        }
-       enumerator->destroy(enumerator);
-       this->lock->unlock(this->lock);
+       return 0;
 }
 
 /**
@@ -213,28 +175,68 @@ static void handle_tuns(private_kernel_libipsec_router_t *this, fd_set *fds)
  */
 static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
 {
+       enumerator_t *enumerator;
+       tun_entry_t *entry;
        bool oldstate;
-       fd_set fds;
-       int maxfd;
+       int count = 0;
+       char buf[1];
+       struct pollfd *pfd;
+
+       this->lock->read_lock(this->lock);
 
-       maxfd = collect_fds(this, &fds);
+       pfd = alloca(sizeof(*pfd) * (this->tuns->get_count(this->tuns) + 2));
+       pfd[count].fd = this->notify[0];
+       pfd[count].events = POLLIN;
+       count++;
+       pfd[count].fd = this->tun.fd;
+       pfd[count].events = POLLIN;
+       count++;
+
+       enumerator = this->tuns->create_enumerator(this->tuns);
+       while (enumerator->enumerate(enumerator, NULL, &entry))
+       {
+               pfd[count].fd = entry->fd;
+               pfd[count].events = POLLIN;
+               count++;
+       }
+       enumerator->destroy(enumerator);
+       this->lock->unlock(this->lock);
 
        oldstate = thread_cancelability(TRUE);
-       if (select(maxfd, &fds, NULL, NULL, NULL) <= 0)
+       if (poll(pfd, count, -1) <= 0)
        {
                thread_cancelability(oldstate);
                return JOB_REQUEUE_FAIR;
        }
        thread_cancelability(oldstate);
 
-       if (FD_ISSET(this->notify[0], &fds))
-       {       /* list of TUN devices changed, read notification data, rebuild FDs */
-               char buf[1];
-               while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf));
+       if (pfd[0].revents & POLLIN)
+       {
+               /* list of TUN devices changed, read notification data, rebuild FDs */
+               while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf))
+               {
+                       /* nop */
+               }
                return JOB_REQUEUE_DIRECT;
        }
 
-       handle_tuns(this, &fds);
+       if (pfd[1].revents & POLLIN)
+       {
+               process_plain(this->tun.tun);
+       }
+
+       this->lock->read_lock(this->lock);
+       enumerator = this->tuns->create_enumerator(this->tuns);
+       while (enumerator->enumerate(enumerator, NULL, &entry))
+       {
+               if (find_revents(pfd, count, entry->fd) & POLLIN)
+               {
+                       process_plain(entry->tun);
+               }
+       }
+       enumerator->destroy(enumerator);
+       this->lock->unlock(this->lock);
+
        return JOB_REQUEUE_DIRECT;
 }