summaryrefslogtreecommitdiffstats
path: root/test/testpoll.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/testpoll.c965
1 files changed, 965 insertions, 0 deletions
diff --git a/test/testpoll.c b/test/testpoll.c
new file mode 100644
index 0000000..9f90af2
--- /dev/null
+++ b/test/testpoll.c
@@ -0,0 +1,965 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr_strings.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "apr_lib.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+#define SMALL_NUM_SOCKETS 3
+/* We can't use 64 here, because some platforms *ahem* Solaris *ahem* have
+ * a default limit of 64 open file descriptors per process. If we use
+ * 64, the test will fail even though the code is correct.
+ */
+#define LARGE_NUM_SOCKETS 50
+
+static apr_socket_t *s[LARGE_NUM_SOCKETS];
+static apr_sockaddr_t *sa[LARGE_NUM_SOCKETS];
+static apr_pollset_t *pollset;
+static apr_pollcb_t *pollcb;
+
+/* ###: tests surrounded by ifdef OLD_POLL_INTERFACE either need to be
+ * converted to use the pollset interface or removed. */
+
+#ifdef OLD_POLL_INTERFACE
+static apr_pollfd_t *pollarray;
+static apr_pollfd_t *pollarray_large;
+#endif
+
+/* default_pollset_impl can be overridden temporarily to control
+ * testcases which don't specify an implementation explicitly
+ */
+static int default_pollset_impl = APR_POLLSET_DEFAULT;
+
+static void make_socket(apr_socket_t **sock, apr_sockaddr_t **sa,
+ apr_port_t port, apr_pool_t *p, abts_case *tc)
+{
+ apr_status_t rv;
+
+ rv = apr_sockaddr_info_get(sa, "127.0.0.1", APR_UNSPEC, port, 0, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_socket_create(sock, (*sa)->family, SOCK_DGRAM, 0, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_socket_bind((*sock), (*sa));
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+#ifdef OLD_POLL_INTERFACE
+static void check_sockets(const apr_pollfd_t *pollarray,
+ apr_socket_t **sockarray, int which, int pollin,
+ abts_case *tc)
+{
+ apr_status_t rv;
+ apr_int16_t event;
+ char *str;
+
+ rv = apr_poll_revents_get(&event, sockarray[which],
+ (apr_pollfd_t *)pollarray);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ if (pollin) {
+ str = apr_psprintf(p, "Socket %d not signalled when it should be",
+ which);
+ ABTS_ASSERT(tc, str, event & APR_POLLIN);
+ } else {
+ str = apr_psprintf(p, "Socket %d signalled when it should not be",
+ which);
+ ABTS_ASSERT(tc, str, !(event & APR_POLLIN));
+ }
+}
+#endif
+
+static void send_msg(apr_socket_t **sockarray, apr_sockaddr_t **sas, int which,
+ abts_case *tc)
+{
+ apr_size_t len = 5;
+ apr_status_t rv;
+
+ ABTS_PTR_NOTNULL(tc, sockarray[which]);
+
+ rv = apr_socket_sendto(sockarray[which], sas[which], 0, "hello", &len);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_SIZE_EQUAL(tc, strlen("hello"), len);
+}
+
+static void recv_msg(apr_socket_t **sockarray, int which, apr_pool_t *p,
+ abts_case *tc)
+{
+ apr_size_t buflen = 5;
+ char *buffer = apr_pcalloc(p, sizeof(char) * (buflen + 1));
+ apr_sockaddr_t *recsa;
+ apr_status_t rv;
+
+ ABTS_PTR_NOTNULL(tc, sockarray[which]);
+
+ apr_sockaddr_info_get(&recsa, "127.0.0.1", APR_UNSPEC, 7770, 0, p);
+
+ rv = apr_socket_recvfrom(recsa, sockarray[which], 0, buffer, &buflen);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_SIZE_EQUAL(tc, strlen("hello"), buflen);
+ ABTS_STR_EQUAL(tc, "hello", buffer);
+}
+
+
+static void create_all_sockets(abts_case *tc, void *data)
+{
+ int i;
+
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++){
+ make_socket(&s[i], &sa[i], 7777 + i, p, tc);
+ }
+}
+
+#ifdef OLD_POLL_INTERFACE
+static void setup_small_poll(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int i;
+
+ rv = apr_poll_setup(&pollarray, SMALL_NUM_SOCKETS, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < SMALL_NUM_SOCKETS;i++){
+ ABTS_INT_EQUAL(tc, 0, pollarray[i].reqevents);
+ ABTS_INT_EQUAL(tc, 0, pollarray[i].rtnevents);
+
+ rv = apr_poll_socket_add(pollarray, s[i], APR_POLLIN);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_PTR_EQUAL(tc, s[i], pollarray[i].desc.s);
+ }
+}
+
+static void setup_large_poll(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int i;
+
+ rv = apr_poll_setup(&pollarray_large, LARGE_NUM_SOCKETS, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < LARGE_NUM_SOCKETS;i++){
+ ABTS_INT_EQUAL(tc, 0, pollarray_large[i].reqevents);
+ ABTS_INT_EQUAL(tc, 0, pollarray_large[i].rtnevents);
+
+ rv = apr_poll_socket_add(pollarray_large, s[i], APR_POLLIN);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_PTR_EQUAL(tc, s[i], pollarray_large[i].desc.s);
+ }
+}
+
+static void nomessage(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ check_sockets(pollarray, s, 0, 0, tc);
+ check_sockets(pollarray, s, 1, 0, tc);
+ check_sockets(pollarray, s, 2, 0, tc);
+}
+
+static void send_2(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ send_msg(s, sa, 2, tc);
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ check_sockets(pollarray, s, 0, 0, tc);
+ check_sockets(pollarray, s, 1, 0, tc);
+ check_sockets(pollarray, s, 2, 1, tc);
+}
+
+static void recv_2_send_1(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ recv_msg(s, 2, p, tc);
+ send_msg(s, sa, 1, tc);
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ check_sockets(pollarray, s, 0, 0, tc);
+ check_sockets(pollarray, s, 1, 1, tc);
+ check_sockets(pollarray, s, 2, 0, tc);
+}
+
+static void send_2_signaled_1(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ send_msg(s, sa, 2, tc);
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ check_sockets(pollarray, s, 0, 0, tc);
+ check_sockets(pollarray, s, 1, 1, tc);
+ check_sockets(pollarray, s, 2, 1, tc);
+}
+
+static void recv_1_send_0(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ recv_msg(s, 1, p, tc);
+ send_msg(s, sa, 0, tc);
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ check_sockets(pollarray, s, 0, 1, tc);
+ check_sockets(pollarray, s, 1, 0, tc);
+ check_sockets(pollarray, s, 2, 1, tc);
+}
+
+static void clear_all_signalled(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int srv = SMALL_NUM_SOCKETS;
+
+ recv_msg(s, 0, p, tc);
+ recv_msg(s, 2, p, tc);
+
+ rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ check_sockets(pollarray, s, 0, 0, tc);
+ check_sockets(pollarray, s, 1, 0, tc);
+ check_sockets(pollarray, s, 2, 0, tc);
+}
+
+static void send_large_pollarray(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv = LARGE_NUM_SOCKETS;
+ int i;
+
+ send_msg(s, sa, LARGE_NUM_SOCKETS - 1, tc);
+
+ rv = apr_poll(pollarray_large, LARGE_NUM_SOCKETS, &lrv,
+ 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++) {
+ if (i == (LARGE_NUM_SOCKETS - 1)) {
+ check_sockets(pollarray_large, s, i, 1, tc);
+ }
+ else {
+ check_sockets(pollarray_large, s, i, 0, tc);
+ }
+ }
+}
+
+static void recv_large_pollarray(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv = LARGE_NUM_SOCKETS;
+ int i;
+
+ recv_msg(s, LARGE_NUM_SOCKETS - 1, p, tc);
+
+ rv = apr_poll(pollarray_large, LARGE_NUM_SOCKETS, &lrv,
+ 2 * APR_USEC_PER_SEC);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++) {
+ check_sockets(pollarray_large, s, i, 0, tc);
+ }
+}
+#endif
+
+static void setup_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ rv = apr_pollset_create_ex(&pollset, LARGE_NUM_SOCKETS, p, 0,
+ default_pollset_impl);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void multi_event_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pollfd_t socket_pollfd;
+ int lrv;
+ const apr_pollfd_t *descs = NULL;
+
+ ABTS_PTR_NOTNULL(tc, s[0]);
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN | APR_POLLOUT;
+ socket_pollfd.desc.s = s[0];
+ socket_pollfd.client_data = s[0];
+ rv = apr_pollset_add(pollset, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ send_msg(s, sa, 0, tc);
+
+ rv = apr_pollset_poll(pollset, -1, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ if (lrv == 1) {
+ int ev = descs[0].rtnevents;
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s);
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data);
+ ABTS_ASSERT(tc, "either or both of APR_POLLIN, APR_POLLOUT returned",
+ ((ev & APR_POLLIN) != 0) || ((ev & APR_POLLOUT) != 0));
+ }
+ else if (lrv == 2) {
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s);
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data);
+ ABTS_PTR_EQUAL(tc, s[0], descs[1].desc.s);
+ ABTS_PTR_EQUAL(tc, s[0], descs[1].client_data);
+ ABTS_ASSERT(tc, "returned events incorrect",
+ ((descs[0].rtnevents | descs[1].rtnevents)
+ == (APR_POLLIN | APR_POLLOUT))
+ && descs[0].rtnevents != descs[1].rtnevents);
+ }
+ else {
+ ABTS_ASSERT(tc, "either one or two events returned",
+ lrv == 1 || lrv == 2);
+ }
+
+ recv_msg(s, 0, p, tc);
+
+ rv = apr_pollset_poll(pollset, 0, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, 0, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 1, lrv);
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s);
+ ABTS_INT_EQUAL(tc, APR_POLLOUT, descs[0].rtnevents);
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data);
+
+ rv = apr_pollset_remove(pollset, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void add_sockets_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int i;
+
+ for (i = 0; i < LARGE_NUM_SOCKETS;i++){
+ apr_pollfd_t socket_pollfd;
+
+ ABTS_PTR_NOTNULL(tc, s[i]);
+
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN;
+ socket_pollfd.desc.s = s[i];
+ socket_pollfd.client_data = s[i];
+ rv = apr_pollset_add(pollset, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+}
+
+static void nomessage_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv;
+ const apr_pollfd_t *descs = NULL;
+
+ rv = apr_pollset_poll(pollset, 0, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, lrv);
+ ABTS_PTR_EQUAL(tc, NULL, descs);
+}
+
+static void send0_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ const apr_pollfd_t *descs = NULL;
+ int num;
+
+ send_msg(s, sa, 0, tc);
+ rv = apr_pollset_poll(pollset, -1, &num, &descs);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 1, num);
+ ABTS_PTR_NOTNULL(tc, descs);
+
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s);
+ ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data);
+}
+
+static void recv0_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv;
+ const apr_pollfd_t *descs = NULL;
+
+ recv_msg(s, 0, p, tc);
+ rv = apr_pollset_poll(pollset, 0, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, lrv);
+ ABTS_PTR_EQUAL(tc, NULL, descs);
+}
+
+static void send_middle_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ const apr_pollfd_t *descs = NULL;
+ int num;
+
+ send_msg(s, sa, 2, tc);
+ send_msg(s, sa, 5, tc);
+ rv = apr_pollset_poll(pollset, -1, &num, &descs);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_PTR_NOTNULL(tc, descs);
+ ABTS_ASSERT(tc, "either one or two events returned",
+ num == 1 || num == 2);
+
+ /* The poll might only see the first sent message, in which
+ * case we just don't bother checking this assertion */
+ if (num == 2) {
+ ABTS_ASSERT(tc, "Incorrect socket in result set",
+ ((descs[0].desc.s == s[2]) && (descs[1].desc.s == s[5])) ||
+ ((descs[0].desc.s == s[5]) && (descs[1].desc.s == s[2])));
+ }
+}
+
+static void clear_middle_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv;
+ const apr_pollfd_t *descs = NULL;
+
+ recv_msg(s, 2, p, tc);
+ recv_msg(s, 5, p, tc);
+
+ rv = apr_pollset_poll(pollset, 0, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, lrv);
+ ABTS_PTR_EQUAL(tc, NULL, descs);
+}
+
+static void send_last_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ const apr_pollfd_t *descs = NULL;
+ int num;
+
+ send_msg(s, sa, LARGE_NUM_SOCKETS - 1, tc);
+ rv = apr_pollset_poll(pollset, -1, &num, &descs);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 1, num);
+ ABTS_PTR_NOTNULL(tc, descs);
+
+ ABTS_PTR_EQUAL(tc, s[LARGE_NUM_SOCKETS - 1], descs[0].desc.s);
+ ABTS_PTR_EQUAL(tc, s[LARGE_NUM_SOCKETS - 1], descs[0].client_data);
+}
+
+static void clear_last_pollset(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int lrv;
+ const apr_pollfd_t *descs = NULL;
+
+ recv_msg(s, LARGE_NUM_SOCKETS - 1, p, tc);
+
+ rv = apr_pollset_poll(pollset, 0, &lrv, &descs);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, lrv);
+ ABTS_PTR_EQUAL(tc, NULL, descs);
+}
+
+static void close_all_sockets(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ int i;
+
+ for (i = 0; i < LARGE_NUM_SOCKETS; i++){
+ rv = apr_socket_close(s[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+}
+
+static void pollset_remove(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pollset_t *pollset;
+ const apr_pollfd_t *hot_files;
+ apr_pollfd_t pfd;
+ apr_int32_t num;
+
+ rv = apr_pollset_create_ex(&pollset, 5, p, 0,
+ default_pollset_impl);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ pfd.p = p;
+ pfd.desc_type = APR_POLL_SOCKET;
+ pfd.reqevents = APR_POLLOUT;
+
+ pfd.desc.s = s[0];
+ pfd.client_data = (void *)1;
+ rv = apr_pollset_add(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ pfd.desc.s = s[1];
+ pfd.client_data = (void *)2;
+ rv = apr_pollset_add(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ pfd.desc.s = s[2];
+ pfd.client_data = (void *)3;
+ rv = apr_pollset_add(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ pfd.desc.s = s[3];
+ pfd.client_data = (void *)4;
+ rv = apr_pollset_add(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 4, num);
+
+ /* now remove the pollset element referring to desc s[1] */
+ pfd.desc.s = s[1];
+ pfd.client_data = (void *)999; /* not used on this call */
+ rv = apr_pollset_remove(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* this time only three should match */
+ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 3, num);
+ ABTS_PTR_EQUAL(tc, (void *)1, hot_files[0].client_data);
+ ABTS_PTR_EQUAL(tc, s[0], hot_files[0].desc.s);
+ ABTS_PTR_EQUAL(tc, (void *)3, hot_files[1].client_data);
+ ABTS_PTR_EQUAL(tc, s[2], hot_files[1].desc.s);
+ ABTS_PTR_EQUAL(tc, (void *)4, hot_files[2].client_data);
+ ABTS_PTR_EQUAL(tc, s[3], hot_files[2].desc.s);
+
+ /* now remove the pollset elements referring to desc s[2] */
+ pfd.desc.s = s[2];
+ pfd.client_data = (void *)999; /* not used on this call */
+ rv = apr_pollset_remove(pollset, &pfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* this time only two should match */
+ rv = apr_pollset_poll(pollset, 1000, &num, &hot_files);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 2, num);
+ ABTS_ASSERT(tc, "Incorrect socket in result set",
+ ((hot_files[0].desc.s == s[0]) && (hot_files[1].desc.s == s[3])) ||
+ ((hot_files[0].desc.s == s[3]) && (hot_files[1].desc.s == s[0])));
+ ABTS_ASSERT(tc, "Incorrect client data in result set",
+ ((hot_files[0].client_data == (void *)1) &&
+ (hot_files[1].client_data == (void *)4)) ||
+ ((hot_files[0].client_data == (void *)4) &&
+ (hot_files[1].client_data == (void *)1)));
+}
+
+#define POLLCB_PREREQ \
+ do { \
+ if (pollcb == NULL) { \
+ ABTS_NOT_IMPL(tc, "pollcb interface not supported"); \
+ return; \
+ } \
+ } while (0)
+
+static void setup_pollcb(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ rv = apr_pollcb_create(&pollcb, LARGE_NUM_SOCKETS, p, 0);
+ if (rv == APR_ENOTIMPL) {
+ pollcb = NULL;
+ ABTS_NOT_IMPL(tc, "pollcb interface not supported");
+ }
+ else {
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+}
+
+typedef struct pollcb_baton_t {
+ abts_case *tc;
+ int count;
+} pollcb_baton_t;
+
+static apr_status_t trigger_pollcb_cb(void *baton, apr_pollfd_t *descriptor)
+{
+ pollcb_baton_t *pcb = (pollcb_baton_t *) baton;
+ ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->desc.s);
+ ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->client_data);
+ pcb->count++;
+ return APR_SUCCESS;
+}
+
+static void trigger_pollcb(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pollfd_t socket_pollfd;
+ pollcb_baton_t pcb;
+
+ POLLCB_PREREQ;
+
+ ABTS_PTR_NOTNULL(tc, s[0]);
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN;
+ socket_pollfd.desc.s = s[0];
+ socket_pollfd.client_data = s[0];
+ rv = apr_pollcb_add(pollcb, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ send_msg(s, sa, 0, tc);
+ pcb.tc = tc;
+ pcb.count = 0;
+ rv = apr_pollcb_poll(pollcb, -1, trigger_pollcb_cb, &pcb);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 1, pcb.count);
+
+ rv = apr_pollcb_remove(pollcb, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void timeout_pollcb(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ pollcb_baton_t pcb;
+
+ POLLCB_PREREQ;
+
+ pcb.count = 0;
+ pcb.tc = tc;
+
+ rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, pcb.count);
+}
+
+static void timeout_pollin_pollcb(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ pollcb_baton_t pcb;
+ apr_pollfd_t socket_pollfd;
+
+ POLLCB_PREREQ;
+
+ recv_msg(s, 0, p, tc);
+
+ ABTS_PTR_NOTNULL(tc, s[0]);
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN;
+ socket_pollfd.desc.s = s[0];
+ socket_pollfd.client_data = s[0];
+ rv = apr_pollcb_add(pollcb, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ pcb.count = 0;
+ pcb.tc = tc;
+
+ rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, pcb.count);
+
+ rv = apr_pollcb_remove(pollcb, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void pollset_default(abts_case *tc, void *data)
+{
+ apr_status_t rv1, rv2;
+ apr_pollset_t *pollset;
+
+ /* verify that APR will successfully create a pollset if an invalid method
+ * is specified as long as APR_POLLSET_NODEFAULT isn't specified
+ * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at
+ * least one create call will succeed after having to switch to the default
+ * type)
+ */
+ rv1 = apr_pollset_create_ex(&pollset, 1, p, 0, APR_POLLSET_PORT);
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1);
+ ABTS_PTR_NOTNULL(tc, pollset);
+
+ rv1 = apr_pollset_create_ex(&pollset, 1, p, 0, APR_POLLSET_KQUEUE);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1);
+ ABTS_PTR_NOTNULL(tc, pollset);
+
+ /* verify that APR will fail to create a pollset if an invalid method is
+ * specified along with APR_POLLSET_NODEFAULT
+ * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at
+ * least one create call will fail since it can't switch to the default
+ * type)
+ */
+ rv1 = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_NODEFAULT,
+ APR_POLLSET_PORT);
+
+ if (rv1 == APR_SUCCESS) {
+ ABTS_PTR_NOTNULL(tc, pollset);
+ }
+
+ rv2 = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_NODEFAULT,
+ APR_POLLSET_KQUEUE);
+ if (rv2 == APR_SUCCESS) {
+ ABTS_PTR_NOTNULL(tc, pollset);
+ }
+
+ ABTS_ASSERT(tc,
+ "failure using APR_POLLSET_NODEFAULT with unsupported method",
+ rv1 != APR_SUCCESS || rv2 != APR_SUCCESS);
+}
+
+static void pollcb_default(abts_case *tc, void *data)
+{
+ apr_status_t rv1, rv2;
+ apr_pollcb_t *pollcb;
+
+ /* verify that APR will successfully create a pollcb if an invalid method
+ * is specified as long as APR_POLLSET_NODEFAULT isn't specified
+ * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at
+ * least one create call will succeed after having to switch to the default
+ * type)
+ */
+ rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_PORT);
+ if (rv1 == APR_ENOTIMPL) {
+ ABTS_NOT_IMPL(tc, "pollcb interface not supported");
+ return;
+ }
+
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1);
+ ABTS_PTR_NOTNULL(tc, pollcb);
+
+ rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_KQUEUE);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1);
+ ABTS_PTR_NOTNULL(tc, pollcb);
+
+ /* verify that APR will fail to create a pollcb if an invalid method is
+ * specified along with APR_POLLSET_NODEFAULT
+ * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at
+ * least one create call will fail since it can't switch to the default
+ * type)
+ */
+ rv1 = apr_pollcb_create_ex(&pollcb, 1, p, APR_POLLSET_NODEFAULT,
+ APR_POLLSET_PORT);
+
+ if (rv1 == APR_SUCCESS) {
+ ABTS_PTR_NOTNULL(tc, pollcb);
+ }
+
+ rv2 = apr_pollcb_create_ex(&pollcb, 1, p, APR_POLLSET_NODEFAULT,
+ APR_POLLSET_KQUEUE);
+ if (rv2 == APR_SUCCESS) {
+ ABTS_PTR_NOTNULL(tc, pollcb);
+ }
+
+ ABTS_ASSERT(tc,
+ "failure using APR_POLLSET_NODEFAULT with unsupported method",
+ rv1 != APR_SUCCESS || rv2 != APR_SUCCESS);
+
+
+ /* verify basic behavior for another method fallback case (this caused
+ * APR to crash before r834029)
+ */
+
+ rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_POLL);
+ if (rv1 != APR_ENOTIMPL) {
+ ABTS_INT_EQUAL(tc, rv1, APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, pollcb);
+ }
+}
+
+static void pollset_wakeup(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pollfd_t socket_pollfd;
+ apr_pollset_t *pollset;
+ apr_int32_t num;
+ const apr_pollfd_t *descriptors;
+ int i;
+
+ rv = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_WAKEABLE,
+ default_pollset_impl);
+ if (rv == APR_ENOTIMPL) {
+ ABTS_NOT_IMPL(tc, "apr_pollset_wakeup() not supported");
+ return;
+ }
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Send wakeup but no data; apr_pollset_poll() should return APR_EINTR.
+ * Do it twice to test implementations that need to re-arm the events after
+ * poll()ing (e.g. APR_POLLSET_PORT), hence verify that the wakeup pipe is
+ * still in the place afterward.
+ */
+ for (i = 0; i < 2; ++i) {
+ rv = apr_pollset_wakeup(pollset);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_pollset_poll(pollset, -1, &num, &descriptors);
+ ABTS_INT_EQUAL(tc, APR_EINTR, rv);
+ }
+
+ /* send wakeup and data; apr_pollset_poll() should return APR_SUCCESS */
+ socket_pollfd.desc_type = APR_POLL_SOCKET;
+ socket_pollfd.reqevents = APR_POLLIN;
+ socket_pollfd.desc.s = s[0];
+ socket_pollfd.client_data = s[0];
+ rv = apr_pollset_add(pollset, &socket_pollfd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ send_msg(s, sa, 0, tc); apr_sleep(1000);
+
+ rv = apr_pollset_wakeup(pollset);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_pollset_poll(pollset, -1, &num, &descriptors);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 1, num);
+}
+
+/* Should never be invoked */
+static apr_status_t wakeup_pollcb_cb(void *baton, apr_pollfd_t *descriptor)
+{
+ abts_case *tc = (abts_case *) baton;
+
+ ABTS_FAIL(tc, "pollcb callback invoked on apr_pollcb_wakeup()");
+ return APR_SUCCESS;
+}
+
+static void pollcb_wakeup(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pollcb_t *pcb;
+
+ rv = apr_pollcb_create(&pcb, 1, p, APR_POLLSET_WAKEABLE);
+ if (rv == APR_ENOTIMPL) {
+ ABTS_NOT_IMPL(tc, "pollcb interface not supported");
+ return;
+ }
+ else {
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ rv = apr_pollcb_wakeup(pcb);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_pollcb_poll(pcb, -1, wakeup_pollcb_cb, tc);
+ ABTS_INT_EQUAL(tc, APR_EINTR, rv);
+}
+
+static void justsleep(abts_case *tc, void *data)
+{
+ apr_int32_t nsds;
+ const apr_pollfd_t *hot_files;
+ apr_pollset_t *pollset;
+ apr_status_t rv;
+ apr_time_t t1, t2;
+ int i;
+ apr_pollset_method_e methods[] = {
+ APR_POLLSET_DEFAULT,
+ APR_POLLSET_SELECT,
+ APR_POLLSET_KQUEUE,
+ APR_POLLSET_PORT,
+ APR_POLLSET_EPOLL,
+ APR_POLLSET_POLL};
+
+ nsds = 1;
+ t1 = apr_time_now();
+ rv = apr_poll(NULL, 0, &nsds, apr_time_from_msec(200));
+ t2 = apr_time_now();
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, nsds);
+ ABTS_ASSERT(tc,
+ "apr_poll() didn't sleep",
+ (t2 - t1) > apr_time_from_msec(100));
+
+ for (i = 0; i < sizeof methods / sizeof methods[0]; i++) {
+ rv = apr_pollset_create_ex(&pollset, 5, p, 0, methods[i]);
+ if (rv != APR_ENOTIMPL) {
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ nsds = 1;
+ t1 = apr_time_now();
+ rv = apr_pollset_poll(pollset, apr_time_from_msec(200), &nsds,
+ &hot_files);
+ t2 = apr_time_now();
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_INT_EQUAL(tc, 0, nsds);
+ ABTS_ASSERT(tc,
+ "apr_pollset_poll() didn't sleep",
+ (t2 - t1) > apr_time_from_msec(100));
+
+ rv = apr_pollset_destroy(pollset);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ rv = apr_pollcb_create_ex(&pollcb, 5, p, 0, methods[0]);
+ if (rv != APR_ENOTIMPL) {
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ t1 = apr_time_now();
+ rv = apr_pollcb_poll(pollcb, apr_time_from_msec(200), NULL, NULL);
+ t2 = apr_time_now();
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+ ABTS_ASSERT(tc,
+ "apr_pollcb_poll() didn't sleep",
+ (t2 - t1) > apr_time_from_msec(100));
+
+ /* no apr_pollcb_destroy() */
+ }
+ }
+}
+
+abts_suite *testpoll(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite)
+
+ abts_run_test(suite, create_all_sockets, NULL);
+
+#ifdef OLD_POLL_INTERFACE
+ abts_run_test(suite, setup_small_poll, NULL);
+ abts_run_test(suite, setup_large_poll, NULL);
+ abts_run_test(suite, nomessage, NULL);
+ abts_run_test(suite, send_2, NULL);
+ abts_run_test(suite, recv_2_send_1, NULL);
+ abts_run_test(suite, send_2_signaled_1, NULL);
+ abts_run_test(suite, recv_1_send_0, NULL);
+ abts_run_test(suite, clear_all_signalled, NULL);
+ abts_run_test(suite, send_large_pollarray, NULL);
+ abts_run_test(suite, recv_large_pollarray, NULL);
+#endif
+
+ abts_run_test(suite, setup_pollset, NULL);
+ abts_run_test(suite, multi_event_pollset, NULL);
+ abts_run_test(suite, add_sockets_pollset, NULL);
+ abts_run_test(suite, nomessage_pollset, NULL);
+ abts_run_test(suite, send0_pollset, NULL);
+ abts_run_test(suite, recv0_pollset, NULL);
+ abts_run_test(suite, send_middle_pollset, NULL);
+ abts_run_test(suite, clear_middle_pollset, NULL);
+ abts_run_test(suite, send_last_pollset, NULL);
+ abts_run_test(suite, clear_last_pollset, NULL);
+ abts_run_test(suite, pollset_remove, NULL);
+ abts_run_test(suite, close_all_sockets, NULL);
+ abts_run_test(suite, create_all_sockets, NULL);
+ abts_run_test(suite, setup_pollcb, NULL);
+ abts_run_test(suite, trigger_pollcb, NULL);
+ abts_run_test(suite, timeout_pollcb, NULL);
+ abts_run_test(suite, timeout_pollin_pollcb, NULL);
+ abts_run_test(suite, pollset_wakeup, NULL);
+ abts_run_test(suite, pollcb_wakeup, NULL);
+ abts_run_test(suite, close_all_sockets, NULL);
+ abts_run_test(suite, pollset_default, NULL);
+ abts_run_test(suite, pollcb_default, NULL);
+ abts_run_test(suite, justsleep, NULL);
+
+ return suite;
+}
+