Patchwork [02/11] poller: add Poller for growable GPollFD arrays

login
register
mail settings
Submitter Stefan Hajnoczi
Date Jan. 31, 2013, 10:53 a.m.
Message ID <1359629644-21920-3-git-send-email-stefanha@redhat.com>
Download mbox | patch
Permalink /patch/217173/
State New
Headers show

Comments

Stefan Hajnoczi - Jan. 31, 2013, 10:53 a.m.
QEMU currently uses select(2)-style rfds/wfds/xfds for file descriptor
event polling.  Unfortunately the underlying fd_set type and its macros
(FD_SET()) have a hardcoded maximum for file descriptors.  It is
possible to exceed this limit so we need a more scalable event polling
structure.

Poller is a growable array of GPollFDs that will allow us to use
g_poll(3) instead of select(2) in the future.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/qemu/poller.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
 util/Makefile.objs    |  1 +
 util/poller.c         | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 include/qemu/poller.h
 create mode 100644 util/poller.c
Anthony Liguori - Jan. 31, 2013, 12:56 p.m.
Stefan Hajnoczi <stefanha@redhat.com> writes:

> QEMU currently uses select(2)-style rfds/wfds/xfds for file descriptor
> event polling.  Unfortunately the underlying fd_set type and its macros
> (FD_SET()) have a hardcoded maximum for file descriptors.  It is
> possible to exceed this limit so we need a more scalable event polling
> structure.
>
> Poller is a growable array of GPollFDs that will allow us to use
> g_poll(3) instead of select(2) in the future.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

How about using a GArray instead?

Regards,

Anthony Liguori

> ---
>  include/qemu/poller.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  util/Makefile.objs    |  1 +
>  util/poller.c         | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 111 insertions(+)
>  create mode 100644 include/qemu/poller.h
>  create mode 100644 util/poller.c
>
> diff --git a/include/qemu/poller.h b/include/qemu/poller.h
> new file mode 100644
> index 0000000..7630099
> --- /dev/null
> +++ b/include/qemu/poller.h
> @@ -0,0 +1,56 @@
> +/*
> + * Growable GPollFD arrays
> + *
> + * Copyright 2013 Red Hat, Inc. and/or its affiliates
> + *
> + * Authors:
> + *   Stefan Hajnoczi    <stefanha@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QEMU_POLLER_H
> +#define QEMU_POLLER_H
> +
> +#include "qemu-common.h"
> +
> +typedef struct {
> +    GPollFD *poll_fds;
> +    int nfds;
> +    int max;
> +} Poller;
> +
> +void poller_init(Poller *p);
> +void poller_cleanup(Poller *p);
> +
> +/**
> + * poller_reset: Forget all added file descriptors
> + */
> +void poller_reset(Poller *p);
> +
> +/**
> + * poller_add_fd: Enable event polling on a file descriptor
> + *
> + * Called by *_fill() functions that are invoked by the main loop to enable
> + * event polling on file descriptors that they care about.  The results can be
> + * fetched with poller_get_revents() when the corresponding *_poll() function
> + * is invoked by the main loop.
> + *
> + * Return an index that can be used with poller_get_revents().
> + *
> + * @events: GIOCondition (G_IO_IN, G_IO_OUT, etc) bitmask
> + */
> +int poller_add_fd(Poller *p, int fd, int events);
> +
> +/**
> + * poller_get_revents: Fetch event polling results for an added file descriptor
> + *
> + * Return the GIOCondition (G_IO_IN, G_IO_OUT, etc) bitmask.
> + *
> + * @index: Return value from poller_add_fd().  This is not an fd!
> + */
> +int poller_get_revents(Poller *p, int index);
> +
> +#endif /* QEMU_POLLER_H */
> diff --git a/util/Makefile.objs b/util/Makefile.objs
> index 495a178..7ff18d6 100644
> --- a/util/Makefile.objs
> +++ b/util/Makefile.objs
> @@ -8,3 +8,4 @@ util-obj-y += error.o qemu-error.o
>  util-obj-$(CONFIG_POSIX) += compatfd.o
>  util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
>  util-obj-y += qemu-option.o qemu-progress.o
> +util-obj-y += poller.o
> diff --git a/util/poller.c b/util/poller.c
> new file mode 100644
> index 0000000..663e7a9
> --- /dev/null
> +++ b/util/poller.c
> @@ -0,0 +1,54 @@
> +/*
> + * Growable GPollFD arrays
> + *
> + * Copyright 2013 Red Hat, Inc. and/or its affiliates
> + *
> + * Authors:
> + *   Stefan Hajnoczi    <stefanha@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include <assert.h>
> +#include <string.h>
> +#include "qemu/poller.h"
> +
> +void poller_init(Poller *p)
> +{
> +    memset(p, 0, sizeof(*p));
> +}
> +
> +void poller_cleanup(Poller *p)
> +{
> +    g_free(p->poll_fds);
> +}
> +
> +void poller_reset(Poller *p)
> +{
> +    p->nfds = 0;
> +}
> +
> +int poller_add_fd(Poller *p, int fd, int events)
> +{
> +    int index;
> +
> +    index = p->nfds++;
> +    if (index >= p->max) {
> +        p->max += 64; /* avoid constant reallocation */
> +        p->poll_fds = g_realloc(p->poll_fds, p->max * sizeof(p->poll_fds[0]));
> +    }
> +
> +    p->poll_fds[index] = (GPollFD){
> +        .fd = fd,
> +        .events = events,
> +    };
> +    return index;
> +}
> +
> +int poller_get_revents(Poller *p, int index)
> +{
> +    assert(index < p->nfds);
> +    return p->poll_fds[index].revents;
> +}
> -- 
> 1.8.1
Stefan Hajnoczi - Jan. 31, 2013, 3:58 p.m.
On Thu, Jan 31, 2013 at 06:56:56AM -0600, Anthony Liguori wrote:
> Stefan Hajnoczi <stefanha@redhat.com> writes:
> 
> > QEMU currently uses select(2)-style rfds/wfds/xfds for file descriptor
> > event polling.  Unfortunately the underlying fd_set type and its macros
> > (FD_SET()) have a hardcoded maximum for file descriptors.  It is
> > possible to exceed this limit so we need a more scalable event polling
> > structure.
> >
> > Poller is a growable array of GPollFDs that will allow us to use
> > g_poll(3) instead of select(2) in the future.
> >
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> 
> How about using a GArray instead?

g_poll(3) needs a contiguous array of GPollFD structs.  I can't see how
GArray can provide that - it seems to only work if you're using
g_array_*() accessor functions and doesn't give you a contiguous C
array.

Stefan
Anthony Liguori - Jan. 31, 2013, 7:09 p.m.
Stefan Hajnoczi <stefanha@redhat.com> writes:

> On Thu, Jan 31, 2013 at 06:56:56AM -0600, Anthony Liguori wrote:
>> Stefan Hajnoczi <stefanha@redhat.com> writes:
>> 
>> > QEMU currently uses select(2)-style rfds/wfds/xfds for file descriptor
>> > event polling.  Unfortunately the underlying fd_set type and its macros
>> > (FD_SET()) have a hardcoded maximum for file descriptors.  It is
>> > possible to exceed this limit so we need a more scalable event polling
>> > structure.
>> >
>> > Poller is a growable array of GPollFDs that will allow us to use
>> > g_poll(3) instead of select(2) in the future.
>> >
>> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>> 
>> How about using a GArray instead?
>
> g_poll(3) needs a contiguous array of GPollFD structs.  I can't see how
> GArray can provide that - it seems to only work if you're using
> g_array_*() accessor functions and doesn't give you a contiguous C
> array.

The data member is public and points to the start of the array.  So you
can just pass array->data.

Regards,

Anthony Liguori

>
> Stefan

Patch

diff --git a/include/qemu/poller.h b/include/qemu/poller.h
new file mode 100644
index 0000000..7630099
--- /dev/null
+++ b/include/qemu/poller.h
@@ -0,0 +1,56 @@ 
+/*
+ * Growable GPollFD arrays
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi    <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_POLLER_H
+#define QEMU_POLLER_H
+
+#include "qemu-common.h"
+
+typedef struct {
+    GPollFD *poll_fds;
+    int nfds;
+    int max;
+} Poller;
+
+void poller_init(Poller *p);
+void poller_cleanup(Poller *p);
+
+/**
+ * poller_reset: Forget all added file descriptors
+ */
+void poller_reset(Poller *p);
+
+/**
+ * poller_add_fd: Enable event polling on a file descriptor
+ *
+ * Called by *_fill() functions that are invoked by the main loop to enable
+ * event polling on file descriptors that they care about.  The results can be
+ * fetched with poller_get_revents() when the corresponding *_poll() function
+ * is invoked by the main loop.
+ *
+ * Return an index that can be used with poller_get_revents().
+ *
+ * @events: GIOCondition (G_IO_IN, G_IO_OUT, etc) bitmask
+ */
+int poller_add_fd(Poller *p, int fd, int events);
+
+/**
+ * poller_get_revents: Fetch event polling results for an added file descriptor
+ *
+ * Return the GIOCondition (G_IO_IN, G_IO_OUT, etc) bitmask.
+ *
+ * @index: Return value from poller_add_fd().  This is not an fd!
+ */
+int poller_get_revents(Poller *p, int index);
+
+#endif /* QEMU_POLLER_H */
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 495a178..7ff18d6 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -8,3 +8,4 @@  util-obj-y += error.o qemu-error.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
 util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
 util-obj-y += qemu-option.o qemu-progress.o
+util-obj-y += poller.o
diff --git a/util/poller.c b/util/poller.c
new file mode 100644
index 0000000..663e7a9
--- /dev/null
+++ b/util/poller.c
@@ -0,0 +1,54 @@ 
+/*
+ * Growable GPollFD arrays
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi    <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "qemu/poller.h"
+
+void poller_init(Poller *p)
+{
+    memset(p, 0, sizeof(*p));
+}
+
+void poller_cleanup(Poller *p)
+{
+    g_free(p->poll_fds);
+}
+
+void poller_reset(Poller *p)
+{
+    p->nfds = 0;
+}
+
+int poller_add_fd(Poller *p, int fd, int events)
+{
+    int index;
+
+    index = p->nfds++;
+    if (index >= p->max) {
+        p->max += 64; /* avoid constant reallocation */
+        p->poll_fds = g_realloc(p->poll_fds, p->max * sizeof(p->poll_fds[0]));
+    }
+
+    p->poll_fds[index] = (GPollFD){
+        .fd = fd,
+        .events = events,
+    };
+    return index;
+}
+
+int poller_get_revents(Poller *p, int index)
+{
+    assert(index < p->nfds);
+    return p->poll_fds[index].revents;
+}