Skip to content

Commit 1766e37

Browse files
committed
stream stdio types copy optimisations for solaris via the sendfile api.
up to `INT_MAX` and when the output is in write mode.
1 parent 9e74e58 commit 1766e37

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ PHP_CHECK_FUNC(htonl, socket, network)
365365
PHP_CHECK_FUNC(gethostname, nsl, network)
366366
PHP_CHECK_FUNC(gethostbyaddr, nsl, network)
367367
PHP_CHECK_FUNC(copy_file_range)
368+
PHP_CHECK_FUNC(sendfilev, sendfile)
368369
PHP_CHECK_FUNC(dlopen, dl, root)
369370
PHP_CHECK_FUNC(dlsym, dl, root)
370371
if test "$ac_cv_func_dlopen" = "yes"; then
@@ -410,6 +411,7 @@ sys/mount.h \
410411
sys/poll.h \
411412
sys/resource.h \
412413
sys/select.h \
414+
sys/sendfile.h \
413415
sys/socket.h \
414416
sys/stat.h \
415417
sys/statfs.h \

main/streams/streams.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#include "ext/standard/basic_functions.h" /* for BG(CurrentStatFile) */
3030
#include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */
3131
#include <stddef.h>
32+
#if defined(HAVE_SYS_SENDFILE_H)
33+
#include <sys/sendfile.h>
34+
#endif
3235
#include <fcntl.h>
3336
#include "php_streams_int.h"
3437

@@ -1575,7 +1578,7 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de
15751578
php_stream_cast(src, PHP_STREAM_AS_FD, (void*)&src_fd, 0);
15761579
php_stream_cast(dest, PHP_STREAM_AS_FD, (void*)&dest_fd, 0);
15771580

1578-
/* clamp to INT_MAX to avoid EOVERFLOW */
1581+
/* clamp to SIZE_MAX to avoid EOVERFLOW */
15791582
const size_t cfr_max = MIN(maxlen, (size_t)SSIZE_MAX);
15801583

15811584
/* copy_file_range() is a Linux-specific system call
@@ -1638,6 +1641,53 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de
16381641
}
16391642
#endif // __FreeBSD__
16401643
#endif // HAVE_COPY_FILE_RANGE
1644+
#ifdef HAVE_SENDFILEV
1645+
if (php_stream_is(src, PHP_STREAM_IS_STDIO) &&
1646+
php_stream_is(dest, PHP_STREAM_IS_STDIO) &&
1647+
src->writepos == src->readpos &&
1648+
dest->mode[0] == 'w' &&
1649+
php_stream_can_cast(src, PHP_STREAM_AS_FD) == SUCCESS &&
1650+
php_stream_can_cast(dest, PHP_STREAM_AS_FD) == SUCCESS) {
1651+
int src_fd, dest_fd;
1652+
1653+
php_stream_cast(src, PHP_STREAM_AS_FD, (void*)&src_fd, 0);
1654+
php_stream_cast(dest, PHP_STREAM_AS_FD, (void*)&dest_fd, 0);
1655+
1656+
/* clamp to INT_MAX to avoid EOVERFLOW */
1657+
const size_t cfr_max = MIN(maxlen, (size_t)INT_MAX);
1658+
struct sendfilevec vec = {
1659+
.sfv_fd = src_fd,
1660+
.sfv_flag = 0,
1661+
.sfv_off = 0,
1662+
.sfv_len = cfr_max,
1663+
};
1664+
ssize_t result = -1;
1665+
size_t nbytes = 0;
1666+
/* we use the syscall only when output is in write mode */
1667+
do {
1668+
result = sendfilev(dest_fd, &vec, 1, &nbytes);
1669+
} while (result == -1 && errno == EAGAIN);
1670+
1671+
if (result > 0) {
1672+
haveread += nbytes;
1673+
1674+
src->position += nbytes;
1675+
dest->position += nbytes;
1676+
1677+
if ((maxlen != PHP_STREAM_COPY_ALL && nbytes == maxlen) ||
1678+
php_stream_eof(src)) {
1679+
*len = haveread;
1680+
return SUCCESS;
1681+
}
1682+
} else if (result == 0) {
1683+
*len = haveread;
1684+
return SUCCESS;
1685+
} else if (result < 0) {
1686+
*len = haveread;
1687+
return FAILURE;
1688+
}
1689+
}
1690+
#endif // HAVE_SENDFILEV
16411691

16421692
if (maxlen == PHP_STREAM_COPY_ALL) {
16431693
maxlen = 0;

0 commit comments

Comments
 (0)