[ovs-dev] [PATCH] poll-loop: windows poll_block implementation
Ben Pfaff
blp at nicira.com
Mon Dec 30 18:33:13 UTC 2013
On Wed, Dec 18, 2013 at 06:26:31PM -0800, Linda Sun wrote:
> Use WaitForMultipleObjects for polling on windows. This works on all kinds
> of objects, e.g. sockets, files, especially ioctl calls to the kernel.
> poll_fd_wait_event() is used if events need to be passed to pollfds.
> latch is signaled with event, to be waited/polled by WaitForMultipleObjects()
> as well.
> Changed array of fds to hmap to check for duplicate fds.
>
> Signed-off-by: Linda Sun <lsun at vmware.com>
Thanks!
It appears to me that latch-windows doesn't use fds[] at all. If so,
then it would make sense to omit them from the data structure.
I don't think that it's safe to do the operations that latch_poll()
and latch_set() do without synchronization. I suggest putting a lock
around those two whole functions. (Probably, one global lock is
plenty.)
> +struct poll_node {
> + struct hmap_node hmap_node;
> + struct pollfd poll_fd; /* Events to pass to time_poll() */
> + HANDLE wevent; /* events for waitformultipleobjects */
> + const char *where; /* where each pollfd was created */
We don't generally line up member names like this. Just use a space
between the type and the member name.
> +/* Look up the node with same fd and wevent */
> +static struct poll_node *
> +poll_fd_node_find(struct poll_loop *loop, int fd, uint32_t wevent)
> +{
> + struct poll_node *node;
> +
> + HMAP_FOR_EACH_WITH_HASH(node, hmap_node, hash_2words(fd, wevent), &loop->poll_nodes) {
Please put a space after HASH_FUNC. Also, the line is too line,
please limit lines to 79 characters.
> + if (node->poll_fd.fd == fd && node->wevent == wevent) {
> + return node;
> + }
> + }
> + return NULL;
> +}
> +
> /* 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.
> @@ -63,23 +83,37 @@ static struct poll_loop *poll_loop(void);
> * 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_fd_wait_at(int fd, HANDLE wevent, short int events, const char *where)
> {
This function really needs a comment describing how either fd or
wevent is used, depending on OS.
> struct poll_loop *loop = poll_loop();
> + struct poll_node *node;
>
> COVERAGE_INC(poll_fd_wait);
> - if (loop->n_waiters >= loop->allocated_waiters) {
> - loop->where = x2nrealloc(loop->where, &loop->allocated_waiters,
> - sizeof *loop->where);
> - loop->pollfds = xrealloc(loop->pollfds,
> - (loop->allocated_waiters
> - * sizeof *loop->pollfds));
> +
> +#ifdef _WIN32
> + /* null event cannot be polled */
> + if (wevent == 0) {
> + VLOG_ERR("No event to wait fd %d\n", fd);
The \n is unnecessary.
> + return;
> }
> +#endif
>
> - loop->where[loop->n_waiters] = where;
> - loop->pollfds[loop->n_waiters].fd = fd;
> - loop->pollfds[loop->n_waiters].events = events;
> - loop->n_waiters++;
> + /* check for duplicate. If found, "or" the event */
> + node = poll_fd_node_find(loop, fd, wevent);
> + if (node) {
> + node->poll_fd.events |= events;
> + } else {
> + node = xzalloc(sizeof *node);
> + if (node == NULL) {
This NULL check is unnecessary because xzalloc never returns NULL.
> + return;
> + }
> + node->where = where;
> + node->poll_fd.fd = fd;
> + node->wevent = wevent;
> + node->poll_fd.events = events;
> + hmap_insert(&loop->poll_nodes, &node->hmap_node,
> + hash_2words(fd, wevent));
> + }
> }
>
> /* Causes the following call to poll_block() to block for no more than 'msec'
> @@ -227,7 +265,29 @@ poll_block(void)
> }
>
> timewarp_wait();
> - retval = time_poll(loop->pollfds, loop->n_waiters,
> + pollfds = xzalloc(hmap_count(&loop->poll_nodes) * sizeof *pollfds);
Please use xmalloc() here, it is unnecessary to zero the whole block.
> + if (pollfds == NULL) {
This NULL check is unnecessary because xzalloc never returns NULL.
> + return;
> + }
> +
> +#ifdef _WIN32
> + wevents = xzalloc(hmap_count(&loop->poll_nodes) * sizeof *wevents);
> + if (wevents == NULL) {
This NULL check is unnecessary because xzalloc never returns NULL.
> + free(pollfds);
> + return;
> + }
> +#endif
> +
> + /* populate with all the fds and events */
> + HMAP_FOR_EACH(node, hmap_node, &loop->poll_nodes) {
> + memcpy(&pollfds[i], &node->poll_fd, sizeof node->poll_fd);
> +#ifdef _WIN32
> + wevents[i] = node->wevent;
> +#endif
> + i++;
> + }
> +
> + retval = time_poll(pollfds, hmap_count(&loop->poll_nodes), wevents,
> loop->timeout_when, &elapsed);
> if (retval < 0) {
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> @@ -235,18 +295,23 @@ poll_block(void)
> } else if (!retval) {
> log_wakeup(loop->timeout_where, NULL, elapsed);
> } else if (get_cpu_usage() > 50 || VLOG_IS_DBG_ENABLED()) {
> - size_t i;
> -
> - for (i = 0; i < loop->n_waiters; i++) {
> - if (loop->pollfds[i].revents) {
> - log_wakeup(loop->where[i], &loop->pollfds[i], 0);
> + HMAP_FOR_EACH(node, hmap_node, &loop->poll_nodes) {
> + if (node->poll_fd.revents) {
I don't think this is going to work because that pollfd didn't get
updated by time_poll().
> + log_wakeup(node->where, &node->poll_fd, 0);
> }
> }
> }
>
> + HMAP_FOR_EACH_SAFE(node, next, hmap_node, &loop->poll_nodes) {
> + hmap_remove(&loop->poll_nodes, &node->hmap_node);
> + free(node);
> + }
> +
> loop->timeout_when = LLONG_MAX;
> loop->timeout_where = NULL;
> - loop->n_waiters = 0;
> + free(pollfds);
> + if (wevents)
> + free(wevents);
Needs {} around the conditional statement.
> /* Handle any pending signals before doing anything else. */
> fatal_signal_run();
> @@ -258,9 +323,14 @@ static void
> free_poll_loop(void *loop_)
> {
> struct poll_loop *loop = loop_;
> + struct poll_node *node, *next;
> +
> + HMAP_FOR_EACH_SAFE(node, next, hmap_node, &loop->poll_nodes) {
Please add a space after HMAP_FOR_EACH_SAFE.
> + hmap_remove(&loop->poll_nodes, &node->hmap_node);
> + free(node);
> + }
>
> - free(loop->pollfds);
> - free(loop->where);
> + hmap_destroy(&loop->poll_nodes);
> free(loop);
> }
>
> + if (retval < 0) {
> + /* This will be replace by a win error to errno conversion function */
I'd add XXX to the comment to make it easier to spot.
> + retval = -WSAGetLastError();
> + retval = -EINVAL;
> + }
> +#endif
Thanks,
Ben.
More information about the dev
mailing list