Skip to content

Commit 7b8d217

Browse files
committed
php#53: - Add 'nonblocking_applied' flag to php_netstream_data_t to track the
actual socket state at OS level - Modify network_async_set_socket_blocking() to check current state before making system calls, avoiding redundant fcntl() operations - Update function calls in xp_socket.c to pass socket structure for state tracking - Initialize the flag to false (blocking mode) in socket factory
1 parent 0f4fb1a commit 7b8d217

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

main/network_async.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,26 @@
3232

3333
/**
3434
* Sets a socket to blocking (true) or non-blocking (false) mode.
35+
* Optimized to avoid redundant fcntl() calls by tracking the actual socket state.
3536
*
3637
* @param socket
3738
* @param blocking
39+
* @param sock_data
3840
*/
39-
void network_async_set_socket_blocking(php_socket_t socket, bool blocking)
41+
void network_async_set_socket_blocking(php_socket_t socket, bool blocking, php_netstream_data_t *sock_data)
4042
{
43+
// Optimization: avoid redundant system calls if the socket is already in the desired mode
44+
if (sock_data != NULL) {
45+
if (!blocking && sock_data->nonblocking_applied) {
46+
// Already in non-blocking mode, skip system call
47+
return;
48+
}
49+
if (blocking && !sock_data->nonblocking_applied) {
50+
// Already in blocking mode, skip system call
51+
return;
52+
}
53+
}
54+
4155
#ifdef PHP_WIN32
4256
u_long mode = blocking ? 0 : 1;
4357

@@ -47,6 +61,7 @@ void network_async_set_socket_blocking(php_socket_t socket, bool blocking)
4761
ZEND_ASYNC_EXCEPTION_DEFAULT,
4862
"ioctlsocket(FIONBIO) failed (WSA error %d)", err
4963
);
64+
return;
5065
}
5166
#else
5267
int flags = fcntl(socket, F_GETFL, 0);
@@ -67,8 +82,14 @@ void network_async_set_socket_blocking(php_socket_t socket, bool blocking)
6782
ZEND_ASYNC_EXCEPTION_DEFAULT,
6883
"fcntl(F_SETFL) failed: %s", strerror(errno)
6984
);
85+
return;
7086
}
7187
#endif
88+
89+
// Update the flag to reflect the actual socket state
90+
if (sock_data != NULL) {
91+
sock_data->nonblocking_applied = !blocking;
92+
}
7293
}
7394

7495
bool network_async_ensure_socket_nonblocking(php_socket_t socket)

main/network_async.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
BEGIN_EXTERN_C()
2222

23-
ZEND_API void network_async_set_socket_blocking(php_socket_t socket, bool blocking);
23+
ZEND_API void network_async_set_socket_blocking(php_socket_t socket, bool blocking, php_netstream_data_t *sock_data);
2424
ZEND_API bool network_async_ensure_socket_nonblocking(php_socket_t socket);
2525
ZEND_API void network_async_wait_socket(php_socket_t socket, const zend_ulong events, const zend_ulong timeout);
2626

main/php_network.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ struct _php_netstream_data_t {
330330
bool timeout_event;
331331
struct timeval timeout;
332332
size_t ownsize;
333+
bool nonblocking_applied;
333334
};
334335
typedef struct _php_netstream_data_t php_netstream_data_t;
335336
PHPAPI extern const php_stream_ops php_stream_socket_ops;

main/streams/xp_socket.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun
7171
else
7272
ptimeout = &sock->timeout;
7373

74-
if (ZEND_ASYNC_IS_ACTIVE && sock->is_blocked) {
75-
network_async_set_socket_blocking(sock->socket, false);
74+
if (ZEND_ASYNC_IS_ACTIVE && sock->is_blocked && !sock->nonblocking_applied) {
75+
network_async_set_socket_blocking(sock->socket, false, sock);
7676
if (UNEXPECTED(EG(exception) != NULL)) {
7777
/* If we are in async context and an exception was thrown, we should not continue. */
7878
return -1;
@@ -126,8 +126,8 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun
126126
php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0);
127127
}
128128

129-
if (ZEND_ASYNC_IS_ACTIVE && sock->is_blocked) {
130-
network_async_set_socket_blocking(sock->socket, true);
129+
if (ZEND_ASYNC_IS_ACTIVE && sock->is_blocked && !sock->nonblocking_applied) {
130+
network_async_set_socket_blocking(sock->socket, true, sock);
131131
if (UNEXPECTED(EG(exception) != NULL)) {
132132
/* If we are in async context and an exception was thrown, we should not continue. */
133133
return -1;
@@ -982,6 +982,7 @@ PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, size_t p
982982
sock->is_blocked = true;
983983
sock->timeout.tv_sec = FG(default_socket_timeout);
984984
sock->timeout.tv_usec = 0;
985+
sock->nonblocking_applied = false;
985986

986987
/* we don't know the socket until we have determined if we are binding or
987988
* connecting */

0 commit comments

Comments
 (0)