Here's the code for the general-case poll API. I've run out
of time for today, so I'm posting this as a patch rather than
committing it, in hopes that someone else may be able to pick
it up tomorrow (I'll be in meetings much of the day).
This code compiles, but it hasn't been tested.
Known problems:
* It's missing a fallback implementation for systems without poll(2)
* The "add descriptor" function doesn't check for duplicates.
I did this on purpose: it's implemented as a simple append
so that addition runs in O(1) time. The long-term solution
is probably to build a balanced tree out of the entries for
O(log(n)) insertion, deletion, and lookup; but I think the
current solution is probably good enough for the first release.
(The original poll API was O(n) for all of these.)
Brian
Jeff Trawick wrote:
Brian Pane <[EMAIL PROTECTED]> writes:
To continue the recent discussions on the problems in the current
apr_poll API, here's a patch for apr_poll.h that illustrates my
proposed fix.
...
- A general-purpose poll API for larger sets of descriptors.
This one is an abstract data type, accessible only through
functions, so that we can do internal optimizations in the
future (like replacing poll with /dev/poll on supported
platforms).
In the interest of making progress I think you need to go ahead with
this and we can all deal with the details (i.e., stick in the old code
with new names and other tweaks) over the next couple of days.
Index: include/apr_poll.h
===================================================================
RCS file: /home/cvs/apr/include/apr_poll.h,v
retrieving revision 1.2
diff -u -r1.2 apr_poll.h
--- include/apr_poll.h 11 Jul 2002 14:39:04 -0000 1.2
+++ include/apr_poll.h 1 Aug 2002 03:55:33 -0000
@@ -219,6 +219,60 @@
apr_socket_t *sock,
apr_pollfd_t *aprset);
+/* General-purpose poll API for arbitrarily large numbers of
+ * file descriptors
+ */
+
+typedef struct apr_pollset_t apr_pollset_t;
+
+/**
+ * Setup a pollset object
+ * @param pollset The pointer in which to return the newly created object
+ * @param size The maximum number of descriptors that this pollset can hold
+ * @param p The pool from which to allocate the pollset
+ */
+APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
+ apr_uint32_t size,
+ apr_pool_t *p);
+
+/**
+ * Destroy a pollset object
+ * @param pollset The pollset to destroy
+ * @param descriptors An initial set of descriptors to add to the pollset
+ * (may be NULL)
+ * @param num The number of elements in the descriptors array
+ * @param p The pool from which to allocate the pollset
+ */
+APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset);
+
+/**
+ * Add a socket or file descriptor to a pollset
+ * @param pollset The pollset to which to add the descriptor
+ * @param descriptor The descriptor to add
+ */
+APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor);
+
+/**
+ * Remove a descriptor from a pollset
+ * @param pollset The pollset from which to remove the descriptor
+ * @param descriptor The descriptor to remove
+ */
+APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor);
+
+/**
+ * Block for activity on the descriptor(s) in a pollset
+ * @param pollset The pollset to use
+ * @param timeout Timeout in microseconds
+ * @param num Number of signalled descriptors (output parameter)
+ * @param descriptors Array of signalled descriptors (output parameter)
+ */
+APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
+ apr_interval_time_t timeout,
+ apr_int32_t *num,
+ const apr_pollfd_t **descriptors);
+
#ifdef __cplusplus
}
#endif
Index: poll/unix/poll.c
===================================================================
RCS file: /home/cvs/apr/poll/unix/poll.c,v
retrieving revision 1.9
diff -u -r1.9 poll.c
--- poll/unix/poll.c 31 Jul 2002 01:12:43 -0000 1.9
+++ poll/unix/poll.c 1 Aug 2002 03:55:33 -0000
@@ -259,3 +259,115 @@
}
#endif
+
+
+struct apr_pollset_t {
+ apr_uint32_t nelts;
+ apr_uint32_t nalloc;
+ struct pollfd *pollset;
+ apr_pollfd_t *query_set;
+ apr_pollfd_t *result_set;
+ apr_pool_t *pool;
+};
+
+APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
+ apr_uint32_t size,
+ apr_pool_t *p)
+{
+ *pollset = apr_palloc(p, sizeof(**pollset));
+ (*pollset)->nelts = 0;
+ (*pollset)->nalloc = size;
+ (*pollset)->pollset = apr_palloc(p, size * sizeof(struct pollfd));
+ (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+ (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+ (*pollset)->pool = p;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
+{
+ /* A no-op function for now. If we later implement /dev/poll
+ * support, we'll need to close the /dev/poll fd here
+ */
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ if (pollset->nelts == pollset->nalloc) {
+ return APR_ENOMEM;
+ }
+
+ pollset->query_set[pollset->nelts] = *descriptor;
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ pollset->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
+ }
+ else {
+ pollset->pollset[pollset->nelts].fd = descriptor->desc.f->filedes;
+ }
+ pollset->pollset[pollset->nelts].events = get_event(descriptor->reqevents);
+ pollset->nelts++;
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ apr_uint32_t i;
+ int fd;
+
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ fd = descriptor->desc.s->socketdes;
+ }
+ else {
+ fd = descriptor->desc.f->filedes;
+ }
+
+ for (i = 0; i < pollset->nelts; i++) {
+ if (fd == pollset->pollset[i].fd) {
+ /* Found an instance of the fd: remove this and any other copies */
+ apr_uint32_t dst = i;
+ apr_uint32_t old_nelts = pollset->nelts;
+ pollset->nelts--;
+ for (i++; i < old_nelts; i++) {
+ if (fd == pollset->pollset[i].fd) {
+ pollset->nelts--;
+ }
+ else {
+ pollset->pollset[dst] = pollset->pollset[i];
+ }
+ }
+ return APR_SUCCESS;
+ }
+ }
+ return APR_NOTFOUND;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
+ apr_interval_time_t timeout,
+ apr_int32_t *num,
+ const apr_pollfd_t **descriptors)
+{
+ int rv;
+ apr_uint32_t i, j;
+
+ if (timeout > 0) {
+ timeout /= 1000;
+ }
+ rv = poll(pollset->pollset, pollset->nelts, timeout);
+ (*num) = rv;
+ if (rv < 0) {
+ return errno;
+ }
+ j = 0;
+ for (i = 0; i < pollset->nelts; i++) {
+ if (pollset->pollset[i].revents != 0) {
+ pollset->result_set[j] = pollset->query_set[i];
+ pollset->result_set[j].rtnevents =
+ get_revent(pollset->pollset[i].revents);
+ j++;
+ }
+ }
+ *descriptors = pollset->result_set;
+ return APR_SUCCESS;
+}