streams/xp_socket: eliminate poll() when MSG_DONTWAIT is available

If there is a zero timeout and MSG_DONTWAIT is available (or the
socket is non-blocking), the poll() call is not necessary, and we can
just call recv() right away.

Before this change:

 poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
 poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
 poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "", 1, MSG_PEEK, NULL, NULL) = 0

After this change:

 recvfrom(4, 0x7ffe0cc719a0, 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
 poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
 recvfrom(4, "", 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = 0

The first poll() is replaced by recvfrom(), and the third poll() is
omitted completely.

ext/openssl/xp_ssl: eliminate poll() when MSG_DONTWAIT is available

If there is a zero timeout and MSG_DONTWAIT is available (or the
socket is non-blocking), the poll() call is not necessary, and we can
just call recv() right away.

Closes GH-8092.
This commit is contained in:
Max Kellermann 2022-02-09 11:24:45 +01:00 committed by David Carlier
parent 7d6821a98a
commit 2d986310f1
3 changed files with 18 additions and 4 deletions

6
NEWS
View File

@ -28,6 +28,9 @@ PHP NEWS
- ODBC:
. Fixed handling of single-key connection strings. (Calvin Buckley)
- OpenSSL:
. Discard poll calls on socket when no timeout/non blocking/MSG_DONTWAIT. (Max Kellermann)
- PCRE:
. Implemented FR #77726 (Allow null character in regex patterns). (cmb)
@ -37,6 +40,9 @@ PHP NEWS
- Standard:
. Deprecated utf8_encode() and utf8_decode(). (Rowan Tommins)
- Streams:
. Discard poll calls on socket when no timeout/non blocking/MSG_DONTWAIT. (Max Kellermann)
09 Jun 2022, PHP 8.2.0alpha1
- CLI:

View File

@ -46,6 +46,10 @@
#undef X509_EXTENSIONS
#endif
#ifndef MSG_DONTWAIT
# define MSG_DONTWAIT 0
#endif
/* Flags for determining allowed stream crypto methods */
#define STREAM_CRYPTO_IS_CLIENT (1<<0)
#define STREAM_CRYPTO_METHOD_SSLv2 (1<<1)
@ -2395,7 +2399,10 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
if (sslsock->s.socket == -1) {
alive = 0;
} else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
} else if ((!sslsock->ssl_active && value == 0 && (MSG_DONTWAIT || !sslsock->s.is_blocked)) ||
php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
/* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */
/* additionally, we don't use this optimization if SSL is active because in that case, we're not using MSG_DONTWAIT */
if (sslsock->ssl_active) {
int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
if (n <= 0) {
@ -2413,7 +2420,7 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
alive = 0;
}
}
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT) && php_socket_errno() != EAGAIN) {
alive = 0;
}
}

View File

@ -337,7 +337,8 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
if (sock->socket == -1) {
alive = 0;
} else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
} else if ((value == 0 && (MSG_DONTWAIT || !sock->is_blocked)) || php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
/* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */
#ifdef PHP_WIN32
int ret;
#else
@ -345,7 +346,7 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
#endif
int err;
ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK);
ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT);
err = php_socket_errno();
if (0 == ret || /* the counterpart did properly shutdown*/
(0 > ret && err != EWOULDBLOCK && err != EAGAIN && err != EMSGSIZE)) { /* there was an unrecoverable error */