Skip to content

Commit 2d98631

Browse files
MaxKellermanndevnexen
authored andcommitted
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.
1 parent 7d6821a commit 2d98631

File tree

3 files changed

+18
-4
lines changed

3 files changed

+18
-4
lines changed

NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ PHP NEWS
2828
- ODBC:
2929
. Fixed handling of single-key connection strings. (Calvin Buckley)
3030

31+
- OpenSSL:
32+
. Discard poll calls on socket when no timeout/non blocking/MSG_DONTWAIT. (Max Kellermann)
33+
3134
- PCRE:
3235
. Implemented FR #77726 (Allow null character in regex patterns). (cmb)
3336

@@ -37,6 +40,9 @@ PHP NEWS
3740
- Standard:
3841
. Deprecated utf8_encode() and utf8_decode(). (Rowan Tommins)
3942

43+
- Streams:
44+
. Discard poll calls on socket when no timeout/non blocking/MSG_DONTWAIT. (Max Kellermann)
45+
4046
09 Jun 2022, PHP 8.2.0alpha1
4147

4248
- CLI:

ext/openssl/xp_ssl.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
#undef X509_EXTENSIONS
4747
#endif
4848

49+
#ifndef MSG_DONTWAIT
50+
# define MSG_DONTWAIT 0
51+
#endif
52+
4953
/* Flags for determining allowed stream crypto methods */
5054
#define STREAM_CRYPTO_IS_CLIENT (1<<0)
5155
#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
23952399

23962400
if (sslsock->s.socket == -1) {
23972401
alive = 0;
2398-
} else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
2402+
} else if ((!sslsock->ssl_active && value == 0 && (MSG_DONTWAIT || !sslsock->s.is_blocked)) ||
2403+
php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
2404+
/* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */
2405+
/* additionally, we don't use this optimization if SSL is active because in that case, we're not using MSG_DONTWAIT */
23992406
if (sslsock->ssl_active) {
24002407
int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
24012408
if (n <= 0) {
@@ -2413,7 +2420,7 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
24132420
alive = 0;
24142421
}
24152422
}
2416-
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
2423+
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT) && php_socket_errno() != EAGAIN) {
24172424
alive = 0;
24182425
}
24192426
}

main/streams/xp_socket.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,16 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
337337

338338
if (sock->socket == -1) {
339339
alive = 0;
340-
} else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
340+
} else if ((value == 0 && (MSG_DONTWAIT || !sock->is_blocked)) || php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
341+
/* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */
341342
#ifdef PHP_WIN32
342343
int ret;
343344
#else
344345
ssize_t ret;
345346
#endif
346347
int err;
347348

348-
ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK);
349+
ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT);
349350
err = php_socket_errno();
350351
if (0 == ret || /* the counterpart did properly shutdown*/
351352
(0 > ret && err != EWOULDBLOCK && err != EAGAIN && err != EMSGSIZE)) { /* there was an unrecoverable error */

0 commit comments

Comments
 (0)