diff --git a/lib/u_async.c b/lib/u_async.c index e7399e58..3d54ccdc 100644 --- a/lib/u_async.c +++ b/lib/u_async.c @@ -1157,47 +1157,58 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) { int idx = ua->sockets->active_indices[i]; 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); int has_write = FD_ISSET(s, &write_fds); int has_except = FD_ISSET(s, &except_fds); - + if (!has_read && !has_write && !has_except) continue; 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); } } } @@ -1249,45 +1260,56 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) { node = socket_array_get_by_sock(ua->sockets, lookup_sock); } 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); } } } - + /* 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); } } }