std: Swap arguments in Thread.spawn

Beside the new order being consistent with the ThreadPool API and making
more sense, this shuffling allows to write the context argument type in
terms of the startFn arguments, reducing the use of anytype (eg. less
explicit casts when using comptime_int parameters, yay).

Sorry for the breakage.

Closes #8082
This commit is contained in:
LemonBoy 2021-02-28 10:01:55 +01:00
parent e65b6d99ac
commit 566adc2510
13 changed files with 49 additions and 35 deletions

View File

@ -165,18 +165,32 @@ pub const SpawnError = error{
Unexpected,
};
/// caller must call wait on the returned thread
/// fn startFn(@TypeOf(context)) T
/// where T is u8, noreturn, void, or !void
/// caller must call wait on the returned thread
pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread {
// Given `T`, the type of the thread startFn, extract the expected type for the
// context parameter.
fn SpawnContextType(comptime T: type) type {
const TI = @typeInfo(T);
if (TI != .Fn)
@compileError("expected function type, found " ++ @typeName(T));
if (TI.Fn.args.len != 1)
@compileError("expected function with single argument, found " ++ @typeName(T));
return TI.Fn.args[0].arg_type orelse
@compileError("cannot use a generic function as thread startFn");
}
/// Spawns a new thread executing startFn, returning an handle for it.
/// Caller must call wait on the returned thread.
/// The `startFn` function must take a single argument of type T and return a
/// value of type u8, noreturn, void or !void.
/// The `context` parameter is of type T and is passed to the spawned thread.
pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startFn))) SpawnError!*Thread {
if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
// TODO compile-time call graph analysis to determine stack upper bound
// https://github.com/ziglang/zig/issues/157
const default_stack_size = 16 * 1024 * 1024;
const Context = @TypeOf(context);
comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
if (std.Target.current.os.tag == .windows) {
const WinThread = struct {

View File

@ -220,8 +220,8 @@ test "basic usage" {
};
var context = Context{};
const send_thread = try std.Thread.spawn(&context, Context.sender);
const recv_thread = try std.Thread.spawn(&context, Context.receiver);
const send_thread = try std.Thread.spawn(Context.sender, &context);
const recv_thread = try std.Thread.spawn(Context.receiver, &context);
send_thread.wait();
recv_thread.wait();

View File

@ -299,7 +299,7 @@ test "basic usage" {
const thread_count = 10;
var threads: [thread_count]*std.Thread = undefined;
for (threads) |*t| {
t.* = try std.Thread.spawn(&context, worker);
t.* = try std.Thread.spawn(worker, &context);
}
for (threads) |t|
t.wait();

View File

@ -281,7 +281,7 @@ test "basic usage" {
var context: Context = undefined;
try context.init();
defer context.deinit();
const receiver = try std.Thread.spawn(&context, Context.receiver);
const receiver = try std.Thread.spawn(Context.receiver, &context);
defer receiver.wait();
context.sender();
@ -290,7 +290,7 @@ test "basic usage" {
// https://github.com/ziglang/zig/issues/7009
var timed = Context.init();
defer timed.deinit();
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
defer sleeper.wait();
try timed.timedWaiter();
}

View File

@ -379,7 +379,7 @@ test "basic usage" {
};
var context = Context{};
const receiver = try std.Thread.spawn(&context, Context.receiver);
const receiver = try std.Thread.spawn(Context.receiver, &context);
defer receiver.wait();
context.sender();
@ -388,7 +388,7 @@ test "basic usage" {
// https://github.com/ziglang/zig/issues/7009
var timed = Context.init();
defer timed.deinit();
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
defer sleeper.wait();
try timed.timedWaiter();
}

View File

@ -216,11 +216,11 @@ test "std.atomic.Queue" {
var putters: [put_thread_count]*std.Thread = undefined;
for (putters) |*t| {
t.* = try std.Thread.spawn(&context, startPuts);
t.* = try std.Thread.spawn(startPuts, &context);
}
var getters: [put_thread_count]*std.Thread = undefined;
for (getters) |*t| {
t.* = try std.Thread.spawn(&context, startGets);
t.* = try std.Thread.spawn(startGets, &context);
}
for (putters) |t|

View File

@ -123,11 +123,11 @@ test "std.atomic.stack" {
} else {
var putters: [put_thread_count]*std.Thread = undefined;
for (putters) |*t| {
t.* = try std.Thread.spawn(&context, startPuts);
t.* = try std.Thread.spawn(startPuts, &context);
}
var getters: [put_thread_count]*std.Thread = undefined;
for (getters) |*t| {
t.* = try std.Thread.spawn(&context, startGets);
t.* = try std.Thread.spawn(startGets, &context);
}
for (putters) |t|

View File

@ -185,7 +185,7 @@ pub const Loop = struct {
errdefer self.deinitOsData();
if (!builtin.single_threaded) {
self.fs_thread = try Thread.spawn(self, posixFsRun);
self.fs_thread = try Thread.spawn(posixFsRun, self);
}
errdefer if (!builtin.single_threaded) {
self.posixFsRequest(&self.fs_end_request);
@ -264,7 +264,7 @@ pub const Loop = struct {
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
}
},
.macos, .freebsd, .netbsd, .dragonfly, .openbsd => {
@ -329,7 +329,7 @@ pub const Loop = struct {
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
}
},
.windows => {
@ -378,7 +378,7 @@ pub const Loop = struct {
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
}
},
else => {},
@ -798,7 +798,7 @@ pub const Loop = struct {
.event = std.Thread.AutoResetEvent{},
.is_running = true,
// Must be last so that it can read the other state, such as `is_running`.
.thread = try std.Thread.spawn(self, DelayQueue.run),
.thread = try std.Thread.spawn(DelayQueue.run, self),
};
}

View File

@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" {
try evt.init();
defer evt.deinit();
const t = try std.Thread.spawn(S.C{ .dir = &tmp.dir, .evt = &evt }, S.checkFn);
const t = try std.Thread.spawn(S.checkFn, S.C{ .dir = &tmp.dir, .evt = &evt });
defer t.wait();
const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;

View File

@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" {
}
};
const t = try std.Thread.spawn(server.listen_address, S.clientFn);
const t = try std.Thread.spawn(S.clientFn, server.listen_address);
defer t.wait();
var client = try server.accept();
@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
}
};
const t = try std.Thread.spawn({}, S.clientFn);
const t = try std.Thread.spawn(S.clientFn, {});
defer t.wait();
var client = try server.accept();

View File

@ -59,11 +59,11 @@ test "Once executes its function just once" {
defer for (threads) |handle| handle.wait();
for (threads) |*handle| {
handle.* = try std.Thread.spawn(@as(u8, 0), struct {
handle.* = try std.Thread.spawn(struct {
fn thread_fn(x: u8) void {
global_once.call();
}
}.thread_fn);
}.thread_fn, 0);
}
}

View File

@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {
if (builtin.single_threaded) return error.SkipZigTest;
var thread_current_id: Thread.Id = undefined;
const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
const thread = try Thread.spawn(testThreadIdFn, &thread_current_id);
const thread_id = thread.handle();
thread.wait();
if (Thread.use_pthreads) {
@ -336,10 +336,10 @@ test "spawn threads" {
var shared_ctx: i32 = 1;
const thread1 = try Thread.spawn({}, start1);
const thread2 = try Thread.spawn(&shared_ctx, start2);
const thread3 = try Thread.spawn(&shared_ctx, start2);
const thread4 = try Thread.spawn(&shared_ctx, start2);
const thread1 = try Thread.spawn(start1, {});
const thread2 = try Thread.spawn(start2, &shared_ctx);
const thread3 = try Thread.spawn(start2, &shared_ctx);
const thread4 = try Thread.spawn(start2, &shared_ctx);
thread1.wait();
thread2.wait();
@ -367,8 +367,8 @@ test "cpu count" {
test "thread local storage" {
if (builtin.single_threaded) return error.SkipZigTest;
const thread1 = try Thread.spawn({}, testTls);
const thread2 = try Thread.spawn({}, testTls);
const thread1 = try Thread.spawn(testTls, {});
const thread2 = try Thread.spawn(testTls, {});
testTls({});
thread1.wait();
thread2.wait();

View File

@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {
try worker.idle_node.data.init();
errdefer worker.idle_node.data.deinit();
worker.thread = try std.Thread.spawn(worker, Worker.run);
worker.thread = try std.Thread.spawn(Worker.run, worker);
}
}