|
|
|
|
@ -1158,11 +1158,22 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
|
|
|
|
|
struct socket_node* node = &ua->sockets->sockets[idx]; |
|
|
|
|
if (!node->active) continue; |
|
|
|
|
|
|
|
|
|
/* Снапшот полей — коллбэки могут реаллоцировать ua->sockets (node станет висячим) */ |
|
|
|
|
int local_fd = node->fd; |
|
|
|
|
socket_t local_sock = node->sock; |
|
|
|
|
int local_type = node->type; |
|
|
|
|
void* local_ud = node->user_data; |
|
|
|
|
socket_callback_t local_except = node->except_cbk; |
|
|
|
|
socket_callback_t local_read = node->read_cbk; |
|
|
|
|
socket_callback_t local_write = node->write_cbk; |
|
|
|
|
socket_t_callback_t local_read_sock = node->read_cbk_sock; |
|
|
|
|
socket_t_callback_t local_write_sock = node->write_cbk_sock; |
|
|
|
|
|
|
|
|
|
SOCKET s; |
|
|
|
|
if (node->type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
s = node->sock; |
|
|
|
|
if (local_type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
s = local_sock; |
|
|
|
|
} else { |
|
|
|
|
s = (SOCKET)node->fd; |
|
|
|
|
s = (SOCKET)local_fd; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int has_read = FD_ISSET(s, &read_fds); |
|
|
|
|
@ -1173,31 +1184,31 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "select→fd=%d r=%d w=%d e=%d", (int)s, has_read, has_write, has_except); |
|
|
|
|
|
|
|
|
|
if (has_except) { |
|
|
|
|
if (node->except_cbk) { |
|
|
|
|
node->except_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_except) { |
|
|
|
|
local_except(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (has_read) { |
|
|
|
|
if (node->type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (node->read_cbk_sock) { |
|
|
|
|
node->read_cbk_sock(node->sock, node->user_data); |
|
|
|
|
if (local_type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (local_read_sock) { |
|
|
|
|
local_read_sock(local_sock, local_ud); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (node->read_cbk) { |
|
|
|
|
node->read_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_read) { |
|
|
|
|
local_read(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (has_write) { |
|
|
|
|
if (node->type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (node->write_cbk_sock) { |
|
|
|
|
node->write_cbk_sock(node->sock, node->user_data); |
|
|
|
|
if (local_type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (local_write_sock) { |
|
|
|
|
local_write_sock(local_sock, local_ud); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (node->write_cbk) { |
|
|
|
|
node->write_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_write) { |
|
|
|
|
local_write(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -1250,28 +1261,39 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
|
|
|
|
|
} |
|
|
|
|
if (!node) continue; // Socket may have been removed
|
|
|
|
|
|
|
|
|
|
/* Снапшот полей — коллбэки могут реаллоцировать ua->sockets (node станет висячим) */ |
|
|
|
|
int local_fd = node->fd; |
|
|
|
|
socket_t local_sock = node->sock; |
|
|
|
|
int local_type = node->type; |
|
|
|
|
void* local_ud = node->user_data; |
|
|
|
|
socket_callback_t local_except = node->except_cbk; |
|
|
|
|
socket_callback_t local_read = node->read_cbk; |
|
|
|
|
socket_callback_t local_write = node->write_cbk; |
|
|
|
|
socket_t_callback_t local_read_sock = node->read_cbk_sock; |
|
|
|
|
socket_t_callback_t local_write_sock = node->write_cbk_sock; |
|
|
|
|
|
|
|
|
|
/* Read readiness BEFORE error — avoid losing data on combined IN+ERR/HUP events */ |
|
|
|
|
if (ua->poll_fds[i].revents & POLLIN) { |
|
|
|
|
if (node->type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (node->read_cbk_sock) { |
|
|
|
|
node->read_cbk_sock(node->sock, node->user_data); |
|
|
|
|
if (local_type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (local_read_sock) { |
|
|
|
|
local_read_sock(local_sock, local_ud); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (node->read_cbk) { |
|
|
|
|
node->read_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_read) { |
|
|
|
|
local_read(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Write readiness BEFORE error — flush pending writes before handling HUP */ |
|
|
|
|
if (ua->poll_fds[i].revents & POLLOUT) { |
|
|
|
|
if (node->type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (node->write_cbk_sock) { |
|
|
|
|
node->write_cbk_sock(node->sock, node->user_data); |
|
|
|
|
if (local_type == SOCKET_NODE_TYPE_SOCK) { |
|
|
|
|
if (local_write_sock) { |
|
|
|
|
local_write_sock(local_sock, local_ud); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (node->write_cbk) { |
|
|
|
|
node->write_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_write) { |
|
|
|
|
local_write(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -1279,15 +1301,15 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
|
|
|
|
|
/* Check for error conditions LAST — I/O handlers drain/process data first */ |
|
|
|
|
if (ua->poll_fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) { |
|
|
|
|
/* Treat as exceptional condition */ |
|
|
|
|
if (node->except_cbk) { |
|
|
|
|
node->except_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_except) { |
|
|
|
|
local_except(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Exceptional data (out-of-band) */ |
|
|
|
|
if (ua->poll_fds[i].revents & POLLPRI) { |
|
|
|
|
if (node->except_cbk) { |
|
|
|
|
node->except_cbk(node->fd, node->user_data); |
|
|
|
|
if (local_except) { |
|
|
|
|
local_except(local_fd, local_ud); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|