Skip to content

Commit 8ecf22b

Browse files
committed
php#53: % Optimize network_async_accept_incoming: try accept() first before waiting
- Try accept() immediately instead of waiting for READ event first - Only wait in event loop if accept() returns EAGAIN/EWOULDBLOCK - Eliminates unnecessary syscalls when connections are already ready - Refactor code structure with centralized error handling via goto - Use EXPECTED/UNEXPECTED macros and const variables for better optimization
1 parent f472b46 commit 8ecf22b

File tree

1 file changed

+44
-25
lines changed

1 file changed

+44
-25
lines changed

main/network_async.c

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,39 +1145,58 @@ ZEND_API php_socket_t network_async_accept_incoming(php_stream *stream,
11451145
php_socket_t clisock = -1;
11461146
int error = 0;
11471147
php_sockaddr_storage sa;
1148-
socklen_t sl;
1148+
socklen_t sl = sizeof(sa);
11491149

1150-
// Use the modern async await mechanism instead of php_pollfd_for
1151-
int n = network_async_await_stream_socket(stream, PHP_POLLREADABLE, timeout);
1150+
// Get the underlying fd from stream
1151+
php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
11521152

1153-
if (n == 0) {
1154-
error = PHP_TIMEOUT_ERROR_VALUE;
1155-
} else if (n == -1) {
1156-
error = errno; // errno set by network_async_await_stream_socket
1157-
} else {
1158-
// Socket is ready for accept, get the underlying fd from stream
1159-
php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
1160-
if (sock == NULL) {
1161-
error = EBADF;
1162-
} else {
1163-
sl = sizeof(sa);
1153+
if (sock == NULL) {
1154+
error = EBADF;
1155+
goto return_error;
1156+
}
1157+
// Try accept() first - there might be a connection ready already
1158+
clisock = accept(sock->socket, (struct sockaddr*)&sa, &sl);
1159+
1160+
if (clisock == SOCK_ERR) {
1161+
1162+
// Check if we need to wait or if it's a real error
1163+
const int accept_errno = php_socket_errno();
1164+
1165+
if (UNEXPECTED(accept_errno != EAGAIN && accept_errno != EWOULDBLOCK)) {
1166+
error = accept_errno;
1167+
goto return_error;
1168+
}
1169+
1170+
// No connection ready, need to wait for one
1171+
const int events_count = network_async_await_stream_socket(stream, PHP_POLLREADABLE, timeout);
1172+
1173+
if (EXPECTED(events_count > 0)) {
1174+
// Socket is ready for accept, try again
11641175
clisock = accept(sock->socket, (struct sockaddr*)&sa, &sl);
1176+
} else if (events_count == 0) {
1177+
error = PHP_TIMEOUT_ERROR_VALUE;
1178+
} else if (events_count == -1) {
1179+
error = errno; // errno set by network_async_await_stream_socket
1180+
}
1181+
}
1182+
1183+
// Handle successful accept() (either first try or after waiting)
1184+
if (ZEND_VALID_SOCKET(clisock)) {
1185+
php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
1186+
textaddr,
1187+
addr, addrlen);
11651188

1166-
if (clisock != SOCK_ERR) {
1167-
php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
1168-
textaddr,
1169-
addr, addrlen);
1170-
if (tcp_nodelay) {
11711189
#ifdef TCP_NODELAY
1172-
setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
1173-
#endif
1174-
}
1175-
} else {
1176-
error = php_socket_errno();
1177-
}
1190+
if (tcp_nodelay) {
1191+
setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
11781192
}
1193+
#endif
1194+
} else {
1195+
error = php_socket_errno();
11791196
}
11801197

1198+
return_error:
1199+
11811200
if (error_code) {
11821201
*error_code = error;
11831202
}

0 commit comments

Comments
 (0)