An HTTP/1.1 server for zig
0

Configure Feed

Select the types of activity you want to include in your feed.

retire websocket reactor userdata without reuse

+17 -3
+17 -3
src/worker.zig
··· 662 662 } 663 663 thread_pool.spawn(.{ self, now, conn }); 664 664 }, 665 + // Stable tombstone for WebSocket userdata whose fd 666 + // was closed on a pool thread. A queued kernel event 667 + // may still carry this pointer; it must be ignored. 668 + .retired => continue, 665 669 }, 666 670 .shutdown => return, 667 671 } ··· 887 891 // here is unsafe because accept may already have reused that fd 888 892 // for another connection. In that race, this DEL removed the new 889 893 // connection's read monitor and left it stuck in request_list. 890 - // The graveyard's job is only to defer memory reclamation until 891 - // every pointer in the current event batch has been consumed. 894 + // More importantly, close happens on another thread, so the 895 + // reactor cannot prove that a readiness notification carrying 896 + // this userdata pointer is not still queued beyond the current 897 + // epoll_wait batch. Never recycle websocket Conn userdata: an 898 + // old notification must continue to point at retired websocket 899 + // state, never at a newly accepted HTTP connection (the ABA 900 + // that cross-wired responses in production). MemoryPool.deinit 901 + // releases these tiny stable-lifetime nodes at server shutdown. 892 902 self.websocket.cleanupConn(hc); 903 + conn.protocol = .{ .retired = {} }; 893 904 self.len -= 1; 894 - self.conn_mem_pool.destroy(conn); 895 905 } 896 906 return released; 897 907 } ··· 905 915 switch (conn.protocol) { 906 916 .http => |http_conn| self.processHTTPData(now, conn, thread_buf, http_conn), 907 917 .websocket => |hc| self.processWebsocketData(conn, thread_buf, hc), 918 + .retired => {}, 908 919 } 909 920 } 910 921 ··· 1661 1672 protocol: union(enum) { 1662 1673 http: *HTTPConn, 1663 1674 websocket: *ws.HandlerConn(WSH), 1675 + retired: void, 1664 1676 }, 1665 1677 1666 1678 // Node in a List(WSH). List is [obviously] intrusive. ··· 1689 1701 switch (self.protocol) { 1690 1702 .http => |http_conn| posix.close(http_conn.stream.socket.handle), 1691 1703 .websocket => |hc| hc.conn.close(.{}) catch {}, 1704 + .retired => {}, 1692 1705 } 1693 1706 } 1694 1707 ··· 1696 1709 return switch (self.protocol) { 1697 1710 .http => |hc| hc.stream.socket.handle, 1698 1711 .websocket => |hc| hc.socket, 1712 + .retired => unreachable, 1699 1713 }; 1700 1714 } 1701 1715