Brian Havard wrote:
> Jeff Trawick wrote:
[...]
>> For an external API that satisfies this use case, I'd rather see
>> something like separate apr_file_wait()/apr_socket_wait() instead of
>> the current interface. (They probably need enums for the I/O type
>> too, instead of the int flag.)
>>
>> This can use wait-for-io-or-timeout internally if appropriate.
>>
>
> Sounds good. I can start hacking something together if there's agreement.
>
Ok, here's what I've come up with.
I haven't done a Win32 implementation because I'm not sure how to wait
on a file/pipe. I could probably take a stab at doing apr_socket_wait()
if I get around to digging out a windows compiler but probably best left
to someone more familiar with apr on windows.
Comments?
Index: test/testpipe.c
===================================================================
--- test/testpipe.c (revision 931631)
+++ test/testpipe.c (working copy)
@@ -186,6 +186,35 @@
ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT);
}
+static void wait_pipe(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_interval_time_t delay = 200000;
+ apr_time_t start_time;
+ apr_time_t end_time;
+ apr_size_t nbytes;
+
+ rv = apr_file_pipe_create(&readp, &writep, p);
+ APR_ASSERT_SUCCESS(tc, "Couldn't create pipe", rv);
+
+ rv = apr_file_pipe_timeout_set(readp, delay);
+ APR_ASSERT_SUCCESS(tc, "Couldn't set pipe timeout", rv);
+
+ start_time = apr_time_now();
+ rv = apr_file_wait(readp, APR_WAIT_READ);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+
+ end_time = apr_time_now();
+ ABTS_ASSERT(tc, "apr_file_wait() waited for the time out", end_time
- start_time >= delay);
+
+ nbytes = 4;
+ rv = apr_file_write(writep, "data", &nbytes);
+ APR_ASSERT_SUCCESS(tc, "Couldn't write to pipe", rv);
+
+ rv = apr_file_wait(readp, APR_WAIT_READ);
+ APR_ASSERT_SUCCESS(tc, "Wait for pipe failed", rv);
+}
+
abts_suite *testpipe(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@@ -199,6 +228,7 @@
abts_run_test(suite, read_write_notimeout, NULL);
abts_run_test(suite, test_pipe_writefull, NULL);
abts_run_test(suite, close_pipe, NULL);
+ abts_run_test(suite, wait_pipe, NULL);
return suite;
}
Index: test/testsock.c
===================================================================
--- test/testsock.c (revision 931631)
+++ test/testsock.c (working copy)
@@ -403,6 +403,64 @@
apr_socket_close(ld);
}
+static void test_wait(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_socket_t *server;
+ apr_socket_t *server_connection;
+ apr_sockaddr_t *server_addr;
+ apr_socket_t *client;
+ apr_interval_time_t delay = 200000;
+ apr_time_t start_time;
+ apr_time_t end_time;
+ apr_size_t nbytes;
+ int connected = FALSE;
+
+ server = setup_socket(tc);
+ rv = apr_sockaddr_info_get(&server_addr, socket_name, socket_type,
8021, 0, p);
+ APR_ASSERT_SUCCESS(tc, "setting up sockaddr", rv);
+
+ rv = apr_socket_create(&client, server_addr->family, SOCK_STREAM,
0, p);
+ APR_ASSERT_SUCCESS(tc, "creating client socket", rv);
+
+ rv = apr_socket_timeout_set(client, 0);
+ APR_ASSERT_SUCCESS(tc, "setting client socket timeout", rv);
+
+ rv = apr_socket_connect(client, server_addr);
+
+ if (rv == APR_SUCCESS) {
+ connected = TRUE;
+ }
+ else {
+ ABTS_ASSERT(tc, "connecting client to server",
APR_STATUS_IS_EINPROGRESS(rv));
+ }
+
+ rv = apr_socket_accept(&server_connection, server, p);
+ APR_ASSERT_SUCCESS(tc, "accepting client connection", rv);
+
+ if (!connected) {
+ rv = apr_socket_connect(client, server_addr);
+ APR_ASSERT_SUCCESS(tc, "connecting client to server", rv);
+ }
+
+ rv = apr_socket_timeout_set(client, delay);
+ APR_ASSERT_SUCCESS(tc, "setting client socket timeout", rv);
+
+ start_time = apr_time_now();
+ rv = apr_socket_wait(client, APR_WAIT_READ);
+ ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+
+ end_time = apr_time_now();
+ ABTS_ASSERT(tc, "apr_socket_wait() waited for the time out",
end_time - start_time >= delay);
+
+ nbytes = 4;
+ rv = apr_socket_send(server_connection, "data", &nbytes);
+ APR_ASSERT_SUCCESS(tc, "Couldn't write to client", rv);
+
+ rv = apr_socket_wait(client, APR_WAIT_READ);
+ APR_ASSERT_SUCCESS(tc, "Wait for socket failed", rv);
+}
+
abts_suite *testsock(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@@ -416,6 +474,7 @@
abts_run_test(suite, test_timeout, NULL);
abts_run_test(suite, test_print_addr, NULL);
abts_run_test(suite, test_get_addr, NULL);
+ abts_run_test(suite, test_wait, NULL);
#if APR_HAVE_SOCKADDR_UN
socket_name = UNIX_SOCKET_NAME;
socket_type = APR_UNIX;
@@ -423,6 +482,7 @@
abts_run_test(suite, test_send, NULL);
abts_run_test(suite, test_recv, NULL);
abts_run_test(suite, test_timeout, NULL);
+ abts_run_test(suite, test_wait, NULL);
#endif
return suite;
}
Index: network_io/os2/sendrecv.c
===================================================================
--- network_io/os2/sendrecv.c (revision 931631)
+++ network_io/os2/sendrecv.c (working copy)
@@ -153,3 +153,21 @@
*len = rv;
return APR_SUCCESS;
}
+
+
+
+APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock,
apr_wait_type_t direction)
+{
+ int pollsocket = sock->socketdes;
+ int wait_rc = select(&pollsocket, direction == APR_WAIT_READ,
+ direction == APR_WAIT_WRITE, 0, sock->timeout
/ 1000);
+
+ if (wait_rc == 0) {
+ return APR_TIMEUP;
+ }
+ else if (wait_rc < 0) {
+ return APR_FROM_OS_ERROR(sock_errno());
+ }
+
+ return APR_SUCCESS;
+}
Index: network_io/unix/sendrecv.c
===================================================================
--- network_io/unix/sendrecv.c (revision 931631)
+++ network_io/unix/sendrecv.c (working copy)
@@ -235,6 +235,11 @@
#endif
}
+apr_status_t apr_socket_wait(apr_socket_t *sock, apr_wait_type_t direction)
+{
+ return apr_wait_for_io_or_timeout(NULL, sock, direction ==
APR_WAIT_READ);
+}
+
#if APR_HAS_SENDFILE
/* TODO: Verify that all platforms handle the fd the same way,
Index: include/apr_support.h
===================================================================
--- include/apr_support.h (revision 931631)
+++ include/apr_support.h (working copy)
@@ -1,57 +0,0 @@
-/* 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.
- */
-
-#ifndef APR_SUPPORT_H
-#define APR_SUPPORT_H
-
-/**
- * @file apr_support.h
- * @brief APR Support functions
- */
-
-#include "apr.h"
-#include "apr_network_io.h"
-#include "apr_file_io.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/**
- * @defgroup apr_support Internal APR support functions
- * @ingroup APR
- * @{
- */
-
-/**
- * Wait for IO to occur or timeout.
- *
- * @param f The file to wait on.
- * @param s The socket to wait on if @a f is @c NULL.
- * @param for_read If non-zero wait for data to be available to read,
- * otherwise wait for data to be able to be written.
- * @return APR_TIMEUP if we run out of time.
- */
-apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s,
- int for_read);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ! APR_SUPPORT_H */
Index: include/apr_general.h
===================================================================
--- include/apr_general.h (revision 931631)
+++ include/apr_general.h (working copy)
@@ -67,6 +67,9 @@
/** signal numbers typedef */
typedef int apr_signum_t;
+/* Type of I/O to wait for */
+typedef enum { APR_WAIT_READ, APR_WAIT_WRITE } apr_wait_type_t;
+
/**
* Finding offsets of elements within structures.
* Taken from the X code... they've sweated portability of this stuff
Index: include/apr_file_io.h
===================================================================
--- include/apr_file_io.h (revision 931631)
+++ include/apr_file_io.h (working copy)
@@ -569,6 +569,16 @@
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t
*thefile);
/**
+ * Wait for a file or pipe to be ready for input or output
+ * @param thefile the file to wait on
+ * @param direction whether to wait for reading or writing to be ready
+ * @remark Will time out if thefile has a time out set for it
+ * @remark direction can be either APR_WAIT_READ or APR_WAIT_WRITE
+ */
+APR_DECLARE(apr_status_t) apr_file_wait(apr_file_t *thefile,
+ apr_wait_type_t direction);
+
+/**
* Flush the file's buffer.
* @param thefile The file descriptor to flush
*/
Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h (revision 931631)
+++ include/apr_network_io.h (working copy)
@@ -621,6 +621,16 @@
char *buf, apr_size_t *len);
/**
+ * Wait for a socket to be ready for input or output
+ * @param sock the socket to wait on
+ * @param direction whether to wait for reading or writing to be ready
+ * @remark Will time out if socket has a time out set for it
+ * @remark direction can be either APR_WAIT_READ or APR_WAIT_WRITE
+ */
+APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock,
+ apr_wait_type_t direction);
+
+/**
* Setup socket options for the specified socket
* @param sock The socket to set up.
* @param opt The option we would like to configure. One of:
Index: file_io/os2/readwrite.c
===================================================================
--- file_io/os2/readwrite.c (revision 931631)
+++ file_io/os2/readwrite.c (working copy)
@@ -409,6 +409,31 @@
+APR_DECLARE(apr_status_t) apr_file_wait(apr_file_t *f, apr_wait_type_t
direction)
+{
+ int rc;
+
+ if (!f->pipe) {
+ /* No support for waiting on a regular file */
+ return APR_ENOTIMPL;
+ }
+
+ if (((f->flags & APR_FOPEN_READ) > 0) != (direction ==
APR_WAIT_READ)) {
+ /* Attempt to wait for read from the write end of the pipe or
vica versa */
+ return APR_EINVAL;
+ }
+
+ rc = DosWaitEventSem(f->pipeSem, f->timeout >= 0 ? f->timeout /
1000 : SEM_INDEFINITE_WAIT);
+
+ if (rc == ERROR_TIMEOUT) {
+ return APR_TIMEUP;
+ }
+
+ return APR_FROM_OS_ERROR(rc);
+}
+
+
+
APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile)
{
return APR_ENOTIMPL;
Index: file_io/os2/pipe.c
===================================================================
--- file_io/os2/pipe.c (revision 931631)
+++ file_io/os2/pipe.c (working copy)
@@ -81,7 +81,7 @@
(*in)->fname = apr_pstrdup(pool, pipename);
(*in)->isopen = TRUE;
(*in)->buffered = FALSE;
- (*in)->flags = 0;
+ (*in)->flags = APR_FOPEN_READ;
(*in)->pipe = 1;
(*in)->timeout = -1;
(*in)->blocking = BLK_ON;
@@ -113,7 +113,7 @@
(*out)->fname = apr_pstrdup(pool, pipename);
(*out)->isopen = TRUE;
(*out)->buffered = FALSE;
- (*out)->flags = 0;
+ (*out)->flags = APR_FOPEN_WRITE;
(*out)->pipe = 1;
(*out)->timeout = -1;
(*out)->blocking = BLK_ON;
Index: file_io/unix/readwrite.c
===================================================================
--- file_io/unix/readwrite.c (revision 931631)
+++ file_io/unix/readwrite.c (working copy)
@@ -562,3 +562,10 @@
}
return rv;
}
+
+
+
+APR_DECLARE(apr_status_t) apr_file_wait(apr_file_t *thefile,
apr_wait_type_t direction)
+{
+ return apr_wait_for_io_or_timeout(thefile, NULL, direction ==
APR_WAIT_READ);
+}
Index: support/os2/waitio.c
===================================================================
--- support/os2/waitio.c (revision 931631)
+++ support/os2/waitio.c (working copy)
@@ -19,51 +19,14 @@
#include "apr_errno.h"
#include "apr_support.h"
-static apr_status_t wait_for_file(apr_file_t *f, int for_read)
-{
- int rc;
-
- if (!f->pipe) {
- /* No support for waiting on a regular file */
- return APR_ENOTIMPL;
- }
-
- rc = DosWaitEventSem(f->pipeSem, f->timeout >= 0 ? f->timeout /
1000 : SEM_INDEFINITE_WAIT);
-
- if (rc == ERROR_TIMEOUT) {
- return APR_TIMEUP;
- }
-
- return APR_FROM_OS_ERROR(rc);
-}
-
-
-
-static apr_status_t wait_for_socket(apr_socket_t *s, int for_read)
-{
- int pollsocket = s->socketdes;
- int wait_rc = select(&pollsocket, for_read != 0, for_read == 0, 0,
s->timeout / 1000);
-
- if (wait_rc == 0) {
- return APR_TIMEUP;
- }
- else if (wait_rc < 0) {
- return APR_FROM_OS_ERROR(sock_errno());
- }
-
- return APR_SUCCESS;
-}
-
-
-
apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s,
int for_read)
{
if (f) {
- return wait_for_file(f, for_read);
+ return apr_file_wait(f, for_read ? APR_WAIT_READ : APR_WAIT_WRITE);
}
else if (s) {
- return wait_for_socket(s, for_read);
+ return apr_socket_wait(s, for_read ? APR_WAIT_READ :
APR_WAIT_WRITE);
}
/* Didn't specify a file or socket */