libxev icon indicating copy to clipboard operation
libxev copied to clipboard

Different behavior on mac kqueue and linux

Open GrapeBaBa opened this issue 9 months ago • 0 comments

In this PR https://github.com/zen-eth/zig-libp2p/pull/8/files#diff-4b7042b2889c4dd7daa2ceb2cb50d1fd2f25cbff0f4d763646e9bc7f0d59ab3dR579 libxev.zig.

The loop is a threadlocal variable, it should be different eventloop in different thread. The test tested in different thread to dial unavailable address, it works fine on my Mac. But on linux io_uring the test blocking, if switch to epoll, the error below

error: 'transport.tcp.libxev.test.dial in separate thread with error' failed: Error connecting: error.ConnectionRefused
Error connecting: error.ConnectionRefused
expected error.ConnectionRefused, found error.FileDescriptorAlreadyPresentInSet
/home/grapepapa/.zvm/0.13.0/lib/std/posix.zig:3978:19: 0x105a687 in epoll_ctl (test)
        .EXIST => return error.FileDescriptorAlreadyPresentInSet,
                  ^
/home/grapepapa/.cache/zig/p/1220d220fe297775b574b0312faaf5afcc0044cbda650d0558ec2dda8fb1a6dc1228/src/backend/epoll.zig:306:17: 0x10595af in tick (test)
                return err;
                ^
/home/grapepapa/.cache/zig/p/1220d220fe297775b574b0312faaf5afcc0044cbda650d0558ec2dda8fb1a6dc1228/src/backend/epoll.zig:96:49: 0x105e2f1 in run (test)
            .until_done => while (!self.done()) try self.tick(1),
                                                ^
/home/grapepapa/.cache/zig/p/1220d220fe297775b574b0312faaf5afcc0044cbda650d0558ec2dda8fb1a6dc1228/src/dynamic.zig:169:42: 0x105e487 in run (test)
                    inline else => |tag| try @field(
                                         ^
/home/grapepapa/zig-projects/zig-libp2p/src/transport/tcp/libxev.zig:360:9: 0x105e7a5 in dial (test)
        try l.run(.until_done);
        ^
/home/grapepapa/.zvm/0.13.0/lib/std/testing.zig:47:13: 0x105ed59 in expectError__anon_5242 (test)
            return error.TestExpectedError;
            ^
/home/grapepapa/zig-projects/zig-libp2p/src/transport/tcp/libxev.zig:604:5: 0x105f414 in test.dial in separate thread with error (test)
    try std.testing.expectError(error.ConnectionRefused, transport.dial(addr1, &channel1));
    pub fn dial(self: *XevTransport, addr: std.net.Address, channel: *SocketChannel) !void {
        var socket = TCP.init(addr) catch unreachable;

        var err: ?anyerror = null;
        var connect_cb_data = OpenChannelCallbackData{
            .transport = self,
            .channel = channel,
            .err = &err,
        };

        var c: xev.Completion = undefined;
        var l = getLoop();
        socket.connect(&l, &c, addr, OpenChannelCallbackData, &connect_cb_data, connectCallback);
        try l.run(.until_done);
        if (err) |e| {
            return e;
        }
    }

test "dial in separate thread with error" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    const opts = Options{ .backlog = 128 };
    var transport = try XevTransport.init(allocator, opts);
    defer transport.deinit();

    const addr = try std.net.Address.parseIp("127.0.0.1", 1);
    var channel: SocketChannel = undefined;
    var result: ?anyerror = null;

    const thread = try std.Thread.spawn(.{}, struct {
        fn run(t: *XevTransport, a: std.net.Address, c: *SocketChannel, err: *?anyerror) void {
            t.dial(a, c) catch |e| {
                err.* = e;
            };
        }
    }.run, .{ &transport, addr, &channel, &result });

    // Add delay to ensure thread starts
    std.time.sleep(10 * std.time.ns_per_ms);

    var channel1: SocketChannel = undefined;
    const addr1 = try std.net.Address.parseIp("0.0.0.0", 8081);
    try std.testing.expectError(error.ConnectionRefused, transport.dial(addr1, &channel1));

    thread.join();
    try std.testing.expectEqual(result.?, error.ConnectionRefused);
}

GrapeBaBa avatar Feb 22 '25 14:02 GrapeBaBa