Makefile.am: Clean flake8-check too.
[cascardo/ovs.git] / lib / poll-loop.c
index 510903e..e83d989 100644 (file)
 #include "seq.h"
 #include "socket-util.h"
 #include "timeval.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 #include "hmap.h"
 #include "hash.h"
 
 VLOG_DEFINE_THIS_MODULE(poll_loop);
 
-COVERAGE_DEFINE(poll_fd_wait);
+COVERAGE_DEFINE(poll_create_node);
 COVERAGE_DEFINE(poll_zero_timeout);
 
 struct poll_node {
@@ -57,15 +57,20 @@ struct poll_loop {
 
 static struct poll_loop *poll_loop(void);
 
-/* Look up the node with same fd and wevent. */
+/* Look up the node with same fd or wevent. */
 static struct poll_node *
-find_poll_node(struct poll_loop *loop, int fd, uint32_t wevent)
+find_poll_node(struct poll_loop *loop, int fd, HANDLE wevent)
 {
     struct poll_node *node;
 
-    HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_2words(fd, wevent),
+    /* Both 'fd' and 'wevent' cannot be set. */
+    ovs_assert(!fd != !wevent);
+
+    HMAP_FOR_EACH_WITH_HASH (node, hmap_node,
+                             hash_2words(fd, (uint32_t)wevent),
                              &loop->poll_nodes) {
-        if (node->pollfd.fd == fd && node->wevent == wevent) {
+        if ((fd && node->pollfd.fd == fd)
+            || (wevent && node->wevent == wevent)) {
             return node;
         }
     }
@@ -77,52 +82,91 @@ find_poll_node(struct poll_loop *loop, int fd, uint32_t wevent)
  *     Registers 'fd' as waiting for the specified 'events' (which should be
  *     POLLIN or POLLOUT or POLLIN | POLLOUT).  The following call to
  *     poll_block() will wake up when 'fd' becomes ready for one or more of the
- *     requested events.  the 'fd's are given to poll() function later.
+ *     requested events. The 'fd's are given to poll() function later.
  *
  * On Windows system:
  *
- *     If both 'wevent' handle and 'fd' is specified, associate the 'fd' with
- *     with that 'wevent' for 'events' (implemented in poll_block()).
- *     In case of no 'fd' specified, wake up on any event on that 'wevent'.
- *     These wevents are given to the WaitForMultipleObjects() to be polled.
- *     The event registration is one-shot: only the following call to
- *     poll_block() is affected.  The event will need to be re-registered after
- *     poll_block() is called if it is to persist.
+ *     If 'fd' is specified, create a new 'wevent'. Association of 'fd' and
+ *     'wevent' for 'events' happens in poll_block(). If 'wevent' is specified,
+ *     it is assumed that it is unrelated to any sockets and poll_block()
+ *     will wake up on any event on that 'wevent'. It is an error to pass
+ *     both 'wevent' and 'fd'.
+ *
+ * The event registration is one-shot: only the following call to
+ * poll_block() is affected.  The event will need to be re-registered after
+ * poll_block() is called if it is to persist.
  *
  * ('where' is used in debug logging.  Commonly one would use poll_fd_wait() to
  * automatically provide the caller's source file and line number for
  * 'where'.) */
-void
-poll_fd_wait_at(int fd, HANDLE wevent, short int events, const char *where)
+static void
+poll_create_node(int fd, HANDLE wevent, short int events, const char *where)
 {
     struct poll_loop *loop = poll_loop();
     struct poll_node *node;
 
-    COVERAGE_INC(poll_fd_wait);
+    COVERAGE_INC(poll_create_node);
 
-#ifdef _WIN32
-    /* Null event cannot be polled. */
-    if (wevent == 0) {
-        VLOG_ERR("No event to wait fd %d", fd);
-        return;
-    }
-#endif
+    /* Both 'fd' and 'wevent' cannot be set. */
+    ovs_assert(!fd != !wevent);
 
-    /* Check for duplicate.  If found, "or" the event. */
+    /* Check for duplicate.  If found, "or" the events. */
     node = find_poll_node(loop, fd, wevent);
     if (node) {
         node->pollfd.events |= events;
     } else {
         node = xzalloc(sizeof *node);
         hmap_insert(&loop->poll_nodes, &node->hmap_node,
-                    hash_2words(fd, wevent));
+                    hash_2words(fd, (uint32_t)wevent));
         node->pollfd.fd = fd;
         node->pollfd.events = events;
+#ifdef _WIN32
+        if (!wevent) {
+            wevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+        }
+#endif
         node->wevent = wevent;
         node->where = where;
     }
 }
 
+/* Registers 'fd' as waiting for the specified 'events' (which should be POLLIN
+ * or POLLOUT or POLLIN | POLLOUT).  The following call to poll_block() will
+ * wake up when 'fd' becomes ready for one or more of the requested events.
+ *
+ * On Windows, 'fd' must be a socket.
+ *
+ * The event registration is one-shot: only the following call to poll_block()
+ * is affected.  The event will need to be re-registered after poll_block() is
+ * called if it is to persist.
+ *
+ * ('where' is used in debug logging.  Commonly one would use poll_fd_wait() to
+ * automatically provide the caller's source file and line number for
+ * 'where'.) */
+void
+poll_fd_wait_at(int fd, short int events, const char *where)
+{
+    poll_create_node(fd, 0, events, where);
+}
+
+#ifdef _WIN32
+/* Registers for the next call to poll_block() to wake up when 'wevent' is
+ * signaled.
+ *
+ * The event registration is one-shot: only the following call to poll_block()
+ * is affected.  The event will need to be re-registered after poll_block() is
+ * called if it is to persist.
+ *
+ * ('where' is used in debug logging.  Commonly one would use
+ * poll_wevent_wait() to automatically provide the caller's source file and
+ * line number for 'where'.) */
+void
+poll_wevent_wait_at(HANDLE wevent, const char *where)
+{
+    poll_create_node(0, wevent, 0, where);
+}
+#endif /* _WIN32 */
+
 /* Causes the following call to poll_block() to block for no more than 'msec'
  * milliseconds.  If 'msec' is nonpositive, the following call to poll_block()
  * will not block at all.
@@ -209,7 +253,9 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
     cpu_usage = get_cpu_usage();
     if (VLOG_IS_DBG_ENABLED()) {
         level = VLL_DBG;
-    } else if (cpu_usage > 50 && !VLOG_DROP_INFO(&rl)) {
+    } else if (cpu_usage > 50
+               && !thread_is_pmd()
+               && !VLOG_DROP_INFO(&rl)) {
         level = VLL_INFO;
     } else {
         return;
@@ -256,6 +302,12 @@ free_poll_nodes(struct poll_loop *loop)
 
     HMAP_FOR_EACH_SAFE (node, next, hmap_node, &loop->poll_nodes) {
         hmap_remove(&loop->poll_nodes, &node->hmap_node);
+#ifdef _WIN32
+        if (node->wevent && node->pollfd.fd) {
+            WSAEventSelect(node->pollfd.fd, NULL, 0);
+            CloseHandle(node->wevent);
+        }
+#endif
         free(node);
     }
 }
@@ -282,7 +334,7 @@ poll_block(void)
         COVERAGE_INC(poll_zero_timeout);
     }
 
-    timewarp_wait();
+    timewarp_run();
     pollfds = xmalloc(hmap_count(&loop->poll_nodes) * sizeof *pollfds);
 
 #ifdef _WIN32