brianp 2002/08/01 14:17:59
Modified: include apr_poll.h
poll/unix poll.c
test testpoll.c
Log:
Added general-purpose pollset API to handle arbitrarily large
numbers of file descriptors
Revision Changes Path
1.3 +54 -0 apr/include/apr_poll.h
Index: apr_poll.h
===================================================================
RCS file: /home/cvs/apr/include/apr_poll.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- apr_poll.h 11 Jul 2002 14:39:04 -0000 1.2
+++ apr_poll.h 1 Aug 2002 21:17:58 -0000 1.3
@@ -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
1.10 +113 -0 apr/poll/unix/poll.c
Index: poll.c
===================================================================
RCS file: /home/cvs/apr/poll/unix/poll.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- poll.c 31 Jul 2002 01:12:43 -0000 1.9
+++ poll.c 1 Aug 2002 21:17:58 -0000 1.10
@@ -259,3 +259,116 @@
}
#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;
+ return APR_SUCCESS;
+}
+
+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;
+}
1.13 +61 -4 apr/test/testpoll.c
Index: testpoll.c
===================================================================
RCS file: /home/cvs/apr/test/testpoll.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- testpoll.c 1 Aug 2002 20:10:03 -0000 1.12
+++ testpoll.c 1 Aug 2002 21:17:58 -0000 1.13
@@ -149,7 +149,10 @@
apr_socket_t *s[LARGE_NUM_SOCKETS];
apr_sockaddr_t *sa[LARGE_NUM_SOCKETS];
apr_pollfd_t *pollarray;
+ apr_pollset_t *pollset;
int i = 0, srv = SMALL_NUM_SOCKETS;
+ apr_int32_t num;
+ const apr_pollfd_t *descriptors_out;
fprintf (stdout,"APR Poll Test\n*************\n\n");
@@ -169,7 +172,7 @@
printf("OK\n");
printf("\tCreating the sockets I'll use..........");
- for (i = 0; i < SMALL_NUM_SOCKETS; i++){
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++){
if (make_socket(&s[i], &sa[i], 7777 + i, context) != 0){
exit(-1);
}
@@ -190,7 +193,7 @@
printf("OK\n");
printf("Starting Tests\n");
- apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 10 * APR_USEC_PER_SEC);
+ apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
check_sockets(pollarray, s);
send_msg(s, sa, 2);
@@ -214,15 +217,69 @@
apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 10 * APR_USEC_PER_SEC);
check_sockets(pollarray, s);
-
+
+ recv_msg(s, 0, context);
+ recv_msg(s, 2, context);
+
printf("Tests completed.\n");
+
+ fprintf (stdout,"\nAPR Pollset Test\n****************\n\n");
+
+ printf ("\tSetting up pollset....................");
+ if (apr_pollset_create(&pollset, LARGE_NUM_SOCKETS, context) !=
APR_SUCCESS){
+ printf("Couldn't create a pollset!\n");
+ exit (-1);
+ }
+ for (i = 0; i < LARGE_NUM_SOCKETS;i++){
+ apr_pollfd_t socket_pollfd;
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN;
+ socket_pollfd.desc.s = s[i];
+ if (apr_pollset_add(pollset, &socket_pollfd) != APR_SUCCESS){
+ printf("Failed to add socket %d\n", i);
+ exit (-1);
+ }
+ }
+ printf("OK\n");
+
+ printf("\nTest 1: No descriptors signalled.......");
+ if ((apr_pollset_poll(pollset, 0, &num, &descriptors_out) !=
APR_SUCCESS) ||
+ (num != 0)) {
+ printf("FAILED\n");
+ exit(-1);
+ }
+ printf("OK\n");
+
+ printf("\nTest 2: First descriptor signalled.....\n");
+ send_msg(s, sa, 0);
+ if ((apr_pollset_poll(pollset, 0, &num, &descriptors_out) !=
APR_SUCCESS) ||
+ (num != 1)) {
+ printf("Test 2: FAILED\n");
+ exit(-1);
+ }
+ recv_msg(s, 0, context);
+ printf("Test 2: OK\n");
+
+ printf("\nTest 3: Last descriptor signalled......\n");
+ send_msg(s, sa, 99);
+ if ((apr_pollset_poll(pollset, 0, &num, &descriptors_out) !=
APR_SUCCESS) ||
+ (num != 1)) {
+ printf("Test 3: FAILED\n");
+ exit(-1);
+ }
+ recv_msg(s, 99, context);
+ printf("Test 3: OK\n");
+
+ printf("\nTests completed.\n");
+
printf("\tClosing sockets........................");
- for (i = 0; i < SMALL_NUM_SOCKETS; i++){
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++){
if (apr_socket_close(s[i]) != APR_SUCCESS){
printf("Failed!\n");
exit(-1);
}
}
printf ("OK\n");
+
return 0;
}