std.Io.net.HostName.connect: fix resource leaks

Must free other succeeded connections that lost the race.
This commit is contained in:
Andrew Kelley 2025-10-15 11:01:03 -07:00
parent 426a377c7b
commit 870a682cd8
2 changed files with 25 additions and 9 deletions

View File

@ -18,3 +18,4 @@
* migrate child process into std.Io * migrate child process into std.Io
* eliminate std.Io.poll (it should be replaced by "select" functionality) * eliminate std.Io.poll (it should be replaced by "select" functionality)
* finish moving all of std.posix into Threaded * finish moving all of std.posix into Threaded
* TCP fastopen - sends initial payload along with connection. can be done for idempotent http requests

View File

@ -210,25 +210,38 @@ pub fn connect(
var connect_many_queue: Io.Queue(ConnectManyResult) = .init(&connect_many_buffer); var connect_many_queue: Io.Queue(ConnectManyResult) = .init(&connect_many_buffer);
var connect_many = io.async(connectMany, .{ host_name, io, port, &connect_many_queue, options }); var connect_many = io.async(connectMany, .{ host_name, io, port, &connect_many_queue, options });
defer connect_many.cancel(io); var saw_end = false;
defer {
connect_many.cancel(io);
if (!saw_end) while (true) switch (connect_many_queue.getOneUncancelable(io)) {
.connection => |loser| if (loser) |s| s.closeConst(io) else |_| continue,
.end => break,
};
}
var aggregate_error: ConnectError = error.UnknownHostName; var aggregate_error: ConnectError = error.UnknownHostName;
while (connect_many_queue.getOne(io)) |result| switch (result) { while (connect_many_queue.getOne(io)) |result| switch (result) {
.connection => |connection| if (connection) |stream| return stream else |err| switch (err) { .connection => |connection| if (connection) |stream| return stream else |err| switch (err) {
error.SystemResources => |e| return e, error.SystemResources,
error.OptionUnsupported => |e| return e, error.OptionUnsupported,
error.ProcessFdQuotaExceeded => |e| return e, error.ProcessFdQuotaExceeded,
error.SystemFdQuotaExceeded => |e| return e, error.SystemFdQuotaExceeded,
error.Canceled => |e| return e, error.Canceled,
=> |e| return e,
error.WouldBlock => return error.Unexpected, error.WouldBlock => return error.Unexpected,
else => |e| aggregate_error = e, else => |e| aggregate_error = e,
}, },
.end => |end| { .end => |end| {
saw_end = true;
try end; try end;
return aggregate_error; return aggregate_error;
}, },
} else |err| return err; } else |err| switch (err) {
error.Canceled => |e| return e,
}
} }
pub const ConnectManyResult = union(enum) { pub const ConnectManyResult = union(enum) {
@ -255,7 +268,6 @@ pub fn connectMany(
}); });
var group: Io.Group = .init; var group: Io.Group = .init;
defer group.cancel(io);
while (lookup_queue.getOne(io)) |dns_result| switch (dns_result) { while (lookup_queue.getOne(io)) |dns_result| switch (dns_result) {
.address => |address| group.async(io, enqueueConnection, .{ address, io, results, options }), .address => |address| group.async(io, enqueueConnection, .{ address, io, results, options }),
@ -266,7 +278,10 @@ pub fn connectMany(
return; return;
}, },
} else |err| switch (err) { } else |err| switch (err) {
error.Canceled => |e| results.putOneUncancelable(io, .{ .end = e }), error.Canceled => |e| {
group.cancel(io);
results.putOneUncancelable(io, .{ .end = e });
},
} }
} }