std.Thread.Pool: don't hold the job closure while blocking on IPC read

This commit is contained in:
Andrew Kelley 2024-06-21 11:03:00 -07:00
parent 6d3a78b8dd
commit dc207da184

View file

@ -310,58 +310,65 @@ pub fn spawn(pool: *Pool, comptime func: anytype, args: anytype) void {
pool.cond.signal(); pool.cond.signal();
} }
fn worker(pool: *Pool) void { fn acquireThreadToken(job_server_options: Options.JobServer, fd_ptr: *std.posix.fd_t) void {
var trash_buf: [1]u8 = undefined; if (fd_ptr.* >= 0) return;
var connection: ?std.posix.fd_t = null;
defer if (connection) |fd| std.posix.close(fd);
pool.mutex.lock(); switch (job_server_options) {
defer pool.mutex.unlock();
while (true) {
while (pool.run_queue.popFirst()) |run_node| {
// Temporarily unlock the mutex in order to execute the run_node.
pool.mutex.unlock();
defer pool.mutex.lock();
if (connection == null) switch (pool.job_server_options) {
.abstain => {}, .abstain => {},
.connect, .host => |addr| lock: { .connect, .host => |addr| {
const sockfd = std.posix.socket( const sockfd = std.posix.socket(
std.posix.AF.UNIX, std.posix.AF.UNIX,
std.posix.SOCK.STREAM | std.posix.SOCK.CLOEXEC, std.posix.SOCK.STREAM | std.posix.SOCK.CLOEXEC,
0, 0,
) catch |err| { ) catch |err| {
std.log.debug("failed to make socket: {s}", .{@errorName(err)}); std.log.debug("failed to make socket: {s}", .{@errorName(err)});
break :lock; return;
}; };
connection = sockfd; fd_ptr.* = sockfd;
std.posix.connect(sockfd, &addr.any, addr.getOsSockLen()) catch |err| { std.posix.connect(sockfd, &addr.any, addr.getOsSockLen()) catch |err| {
std.log.debug("failed to connect: {s}", .{@errorName(err)}); std.log.debug("failed to connect: {s}", .{@errorName(err)});
break :lock; return;
}; };
var trash_buf: [1]u8 = undefined;
_ = std.posix.read(sockfd, &trash_buf) catch |err| { _ = std.posix.read(sockfd, &trash_buf) catch |err| {
std.log.debug("failed to read: {s}", .{@errorName(err)}); std.log.debug("failed to read: {s}", .{@errorName(err)});
break :lock; return;
}; };
}, },
};
const runFn = run_node.data.runFn;
runFn(&run_node.data);
} }
}
// Stop executing instead of waiting if the thread pool is no longer running. fn releaseThreadToken(fd_ptr: *std.posix.fd_t) void {
if (pool.end_flag) const fd = fd_ptr.*;
break; if (fd >= 0) {
if (connection) |fd| {
std.posix.close(fd); std.posix.close(fd);
connection = null; fd_ptr.* = -1;
} }
}
fn worker(pool: *Pool) void {
var connection: std.posix.fd_t = -1;
defer releaseThreadToken(&connection);
pool.mutex.lock();
defer pool.mutex.unlock();
while (true) {
const work_available = pool.run_queue.first != null;
if (work_available) {
pool.mutex.unlock();
defer pool.mutex.lock();
acquireThreadToken(pool.job_server_options, &connection);
}
while (pool.run_queue.popFirst()) |run_node| {
pool.mutex.unlock();
defer pool.mutex.lock();
run_node.data.runFn(&run_node.data);
}
if (pool.end_flag) return;
releaseThreadToken(&connection);
pool.cond.wait(&pool.mutex); pool.cond.wait(&pool.mutex);
} }
} }