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