Skip to content

Commit

Permalink
Add support for pipe2() on Linux.
Browse files Browse the repository at this point in the history
* configure.in: Test for working pipe2().

* file_io/unix/pipe.c (file_pipe_create): Use pipe2(,O_NONBLOCK) if
  APR_FULL_NONBLOCK is requested.

* test/testpipe.c (nonblock_pipe): New test.
  • Loading branch information
notroj committed May 10, 2024
1 parent dea097b commit cd2571b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 7 deletions.
16 changes: 16 additions & 0 deletions configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,22 @@ if test "$apr_cv_dup3" = "yes"; then
AC_DEFINE([HAVE_DUP3], 1, [Define if dup3 function is supported])
fi

# test for pipe2
AC_CACHE_CHECK([for pipe2 support], [apr_cv_pipe2],
[AC_TRY_RUN([
#include <fcntl.h>
#include <unistd.h>

int main(int argc, const char **argv)
{
int fds[2];
return pipe2(fds, O_NONBLOCK) == -1;
}], [apr_cv_pipe2=yes], [apr_cv_pipe2=no], [apr_cv_pipe2=no])])

if test "$apr_cv_pipe2" = "yes"; then
AC_DEFINE([HAVE_PIPE2], 1, [Define if pipe2 function is supported])
fi

# Test for accept4(). Create a non-blocking socket, bind it to
# an unspecified port & address (kernel picks), and attempt to
# call accept4() on it. If the syscall is wired up (i.e. the
Expand Down
30 changes: 23 additions & 7 deletions file_io/unix/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,25 @@ static apr_status_t file_pipe_create(apr_file_t **in,
apr_pool_t *pool_in,
apr_pool_t *pool_out)
{
int filedes[2];
int filedes[2], fd_blocking;
apr_interval_time_t fd_timeout;

if (pipe(filedes) == -1) {
return errno;
#ifdef HAVE_PIPE2
if (blocking == APR_FULL_NONBLOCK) {
if (pipe2(filedes, O_NONBLOCK) == -1) {
return errno;
}
fd_blocking = BLK_OFF;
fd_timeout = 0;
}
else
#endif
{
if (pipe(filedes) == -1) {
return errno;
}
fd_blocking = BLK_ON;
fd_timeout = -1;
}

(*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
Expand All @@ -194,8 +209,8 @@ static apr_status_t file_pipe_create(apr_file_t **in,
(*in)->is_pipe = 1;
(*in)->fname = NULL;
(*in)->buffered = 0;
(*in)->blocking = BLK_ON;
(*in)->timeout = -1;
(*in)->blocking = fd_blocking;
(*in)->timeout = fd_timeout;
(*in)->ungetchar = -1;
(*in)->flags = APR_INHERIT;
#if APR_HAS_THREADS
Expand All @@ -210,9 +225,9 @@ static apr_status_t file_pipe_create(apr_file_t **in,
(*out)->is_pipe = 1;
(*out)->fname = NULL;
(*out)->buffered = 0;
(*out)->blocking = BLK_ON;
(*out)->blocking = fd_blocking;
(*out)->flags = APR_INHERIT;
(*out)->timeout = -1;
(*out)->timeout = fd_timeout;
#if APR_HAS_THREADS
(*out)->thlock = NULL;
#endif
Expand All @@ -234,6 +249,7 @@ static apr_status_t file_pipe_create(apr_file_t **in,
apr_file_pipe_timeout_set(*in, 0);
break;
default:
/* These are noops for the pipe2() case */
apr_file_pipe_timeout_set(*out, 0);
apr_file_pipe_timeout_set(*in, 0);
break;
Expand Down
39 changes: 39 additions & 0 deletions test/testpipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,42 @@ static void wait_pipe(abts_case *tc, void *data)
APR_ASSERT_SUCCESS(tc, "Wait for pipe failed", rv);
}

static void nonblock_pipe(abts_case *tc, void *data)
{
apr_status_t rv;
apr_interval_time_t delay;
char buf[8192];
apr_size_t nbytes;
unsigned iter;

rv = apr_file_pipe_create_ex(&readp, &writep, APR_FULL_NONBLOCK, p);
APR_ASSERT_SUCCESS(tc, "Couldn't create pipe", rv);

rv = apr_file_pipe_timeout_get(readp, &delay);
APR_ASSERT_SUCCESS(tc, "Couldn't set pipe timeout", rv);
ABTS_INT_EQUAL(tc, delay, 0);

nbytes = sizeof buf;
rv = apr_file_read(readp, buf, &nbytes);
ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EAGAIN(rv));

/* Fill the pipe buffer, although the pipe buffer size is
* platform-specific, write up to 8MiB. */
nbytes = sizeof buf;
memset(buf, 'A', sizeof buf);
rv = APR_SUCCESS;

for (iter = 0; iter < 1024 && rv == APR_SUCCESS; iter++)
rv = apr_file_write(writep, buf, &nbytes);

ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EAGAIN(rv));

nbytes = sizeof buf;
/* Reading should now work. */
rv = apr_file_read(readp, buf, &nbytes);
APR_ASSERT_SUCCESS(tc, "Reading from pipe", rv);
}

abts_suite *testpipe(abts_suite *suite)
{
suite = ADD_SUITE(suite)
Expand All @@ -234,6 +270,9 @@ abts_suite *testpipe(abts_suite *suite)
abts_run_test(suite, test_pipe_writefull, NULL);
abts_run_test(suite, close_pipe, NULL);
abts_run_test(suite, wait_pipe, NULL);
abts_run_test(suite, close_pipe, NULL);
abts_run_test(suite, nonblock_pipe, NULL);
abts_run_test(suite, close_pipe, NULL);

return suite;
}
Expand Down

0 comments on commit cd2571b

Please sign in to comment.