Skip to content

Don't continue polling on EINTR #5521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,18 @@ ZEND_API uint32_t zend_get_executed_lineno(void);
ZEND_API zend_class_entry *zend_get_executed_scope(void);
ZEND_API zend_bool zend_is_executing(void);

ZEND_API zend_bool zend_handle_interrupt_impl();
ZEND_API void zend_set_timeout(zend_long seconds, int reset_signals);
ZEND_API void zend_unset_timeout(void);
ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void);

static zend_always_inline zend_bool zend_handle_interrupt() {
if (EG(vm_interrupt)) {
return zend_handle_interrupt_impl();
}
return 1;
}

ZEND_API zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type);
ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *lcname, int fetch_type);

Expand Down
20 changes: 12 additions & 8 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,14 +832,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /

/* This flag is regularly checked while running user functions, but not internal
* So see whether interrupt flag was set while the function was running... */
if (EG(vm_interrupt)) {
EG(vm_interrupt) = 0;
if (EG(timed_out)) {
zend_timeout();
} else if (zend_interrupt_function) {
zend_interrupt_function(EG(current_execute_data));
}
}
zend_handle_interrupt();
}

zend_vm_stack_free_call_frame(call);
Expand Down Expand Up @@ -1112,6 +1105,17 @@ ZEND_API int zend_eval_string_ex(const char *str, zval *retval_ptr, const char *
}
/* }}} */

ZEND_API zend_bool zend_handle_interrupt_impl() {
ZEND_ASSERT(EG(vm_interrupt));
EG(vm_interrupt) = 0;
if (EG(timed_out)) {
zend_timeout();
} else if (zend_interrupt_function) {
zend_interrupt_function(EG(current_execute_data));
}
return EG(exception) == NULL;
}

static void zend_set_timeout_ex(zend_long seconds, int reset_signals);

ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
Expand Down
33 changes: 14 additions & 19 deletions main/streams/xp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,10 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun
return didwrite;
}

static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock)
static int php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock)
{
int retval;
struct timeval *ptimeout;

if (!sock || sock->socket == -1) {
return;
}
ZEND_ASSERT(sock && sock->socket != -1);

sock->timeout_event = 0;

Expand All @@ -132,17 +128,16 @@ static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data
else
ptimeout = &sock->timeout;

while(1) {
retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);

if (retval == 0)
while (1) {
int retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
if (retval > 0) {
return SUCCESS;
} else if (retval == 0) {
sock->timeout_event = 1;

if (retval >= 0)
break;

if (php_socket_errno() != EINTR)
break;
return FAILURE;
} else if (php_socket_errno() != EINTR || !zend_handle_interrupt()) {
return FAILURE;
}
}
}

Expand All @@ -157,9 +152,9 @@ static ssize_t php_sockop_read(php_stream *stream, char *buf, size_t count)
}

if (sock->is_blocked) {
php_sock_stream_wait_for_data(stream, sock);
if (sock->timeout_event)
return 0;
if (php_sock_stream_wait_for_data(stream, sock) == FAILURE) {
return sock->timeout_event ? 0 : -1;
}
}

nr_bytes = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0);
Expand Down