authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-02-28 10:01:55+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-02-28 14:03:19+01:00
log566adc2510859eaa30eb7c318260c98e712daccf
tree963d59321381ff91148c356ba761dcb5c246cf2f
parente65b6d99ac38686228bf5b5b9c1121382e05da4b

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

13 files changed, 49 insertions(+), 35 deletions(-)

lib/std/Thread.zig+20-6
...@@ -165,18 +165,32 @@ pub const SpawnError = error{...@@ -165,18 +165,32 @@ pub const SpawnError = error{
165 Unexpected,165 Unexpected,
166};166};
167167
168/// caller must call wait on the returned thread168// Given `T`, the type of the thread startFn, extract the expected type for the
169/// fn startFn(@TypeOf(context)) T169// context parameter.
170/// where T is u8, noreturn, void, or !void170fn SpawnContextType(comptime T: type) type {
171/// caller must call wait on the returned thread171 const TI = @typeInfo(T);
172pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread {172 if (TI != .Fn)
173 @compileError("expected function type, found " ++ @typeName(T));
174
175 if (TI.Fn.args.len != 1)
176 @compileError("expected function with single argument, found " ++ @typeName(T));
177
178 return TI.Fn.args[0].arg_type orelse
179 @compileError("cannot use a generic function as thread startFn");
180}
181
182/// Spawns a new thread executing startFn, returning an handle for it.
183/// Caller must call wait on the returned thread.
184/// The `startFn` function must take a single argument of type T and return a
185/// value of type u8, noreturn, void or !void.
186/// The `context` parameter is of type T and is passed to the spawned thread.
187pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startFn))) SpawnError!*Thread {
173 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");188 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
174 // TODO compile-time call graph analysis to determine stack upper bound189 // TODO compile-time call graph analysis to determine stack upper bound
175 // https://github.com/ziglang/zig/issues/157190 // https://github.com/ziglang/zig/issues/157
176 const default_stack_size = 16 * 1024 * 1024;191 const default_stack_size = 16 * 1024 * 1024;
177192
178 const Context = @TypeOf(context);193 const Context = @TypeOf(context);
179 comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
180194
181 if (std.Target.current.os.tag == .windows) {195 if (std.Target.current.os.tag == .windows) {
182 const WinThread = struct {196 const WinThread = struct {
lib/std/Thread/AutoResetEvent.zig+2-2
...@@ -220,8 +220,8 @@ test "basic usage" {...@@ -220,8 +220,8 @@ test "basic usage" {
220 };220 };
221221
222 var context = Context{};222 var context = Context{};
223 const send_thread = try std.Thread.spawn(&context, Context.sender);223 const send_thread = try std.Thread.spawn(Context.sender, &context);
224 const recv_thread = try std.Thread.spawn(&context, Context.receiver);224 const recv_thread = try std.Thread.spawn(Context.receiver, &context);
225225
226 send_thread.wait();226 send_thread.wait();
227 recv_thread.wait();227 recv_thread.wait();
lib/std/Thread/Mutex.zig+1-1
...@@ -299,7 +299,7 @@ test "basic usage" {...@@ -299,7 +299,7 @@ test "basic usage" {
299 const thread_count = 10;299 const thread_count = 10;
300 var threads: [thread_count]*std.Thread = undefined;300 var threads: [thread_count]*std.Thread = undefined;
301 for (threads) |*t| {301 for (threads) |*t| {
302 t.* = try std.Thread.spawn(&context, worker);302 t.* = try std.Thread.spawn(worker, &context);
303 }303 }
304 for (threads) |t|304 for (threads) |t|
305 t.wait();305 t.wait();
lib/std/Thread/ResetEvent.zig+2-2
...@@ -281,7 +281,7 @@ test "basic usage" {...@@ -281,7 +281,7 @@ test "basic usage" {
281 var context: Context = undefined;281 var context: Context = undefined;
282 try context.init();282 try context.init();
283 defer context.deinit();283 defer context.deinit();
284 const receiver = try std.Thread.spawn(&context, Context.receiver);284 const receiver = try std.Thread.spawn(Context.receiver, &context);
285 defer receiver.wait();285 defer receiver.wait();
286 context.sender();286 context.sender();
287287
...@@ -290,7 +290,7 @@ test "basic usage" {...@@ -290,7 +290,7 @@ test "basic usage" {
290 // https://github.com/ziglang/zig/issues/7009290 // https://github.com/ziglang/zig/issues/7009
291 var timed = Context.init();291 var timed = Context.init();
292 defer timed.deinit();292 defer timed.deinit();
293 const sleeper = try std.Thread.spawn(&timed, Context.sleeper);293 const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
294 defer sleeper.wait();294 defer sleeper.wait();
295 try timed.timedWaiter();295 try timed.timedWaiter();
296 }296 }
lib/std/Thread/StaticResetEvent.zig+2-2
...@@ -379,7 +379,7 @@ test "basic usage" {...@@ -379,7 +379,7 @@ test "basic usage" {
379 };379 };
380380
381 var context = Context{};381 var context = Context{};
382 const receiver = try std.Thread.spawn(&context, Context.receiver);382 const receiver = try std.Thread.spawn(Context.receiver, &context);
383 defer receiver.wait();383 defer receiver.wait();
384 context.sender();384 context.sender();
385385
...@@ -388,7 +388,7 @@ test "basic usage" {...@@ -388,7 +388,7 @@ test "basic usage" {
388 // https://github.com/ziglang/zig/issues/7009388 // https://github.com/ziglang/zig/issues/7009
389 var timed = Context.init();389 var timed = Context.init();
390 defer timed.deinit();390 defer timed.deinit();
391 const sleeper = try std.Thread.spawn(&timed, Context.sleeper);391 const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
392 defer sleeper.wait();392 defer sleeper.wait();
393 try timed.timedWaiter();393 try timed.timedWaiter();
394 }394 }
lib/std/atomic/queue.zig+2-2
...@@ -216,11 +216,11 @@ test "std.atomic.Queue" {...@@ -216,11 +216,11 @@ test "std.atomic.Queue" {
216216
217 var putters: [put_thread_count]*std.Thread = undefined;217 var putters: [put_thread_count]*std.Thread = undefined;
218 for (putters) |*t| {218 for (putters) |*t| {
219 t.* = try std.Thread.spawn(&context, startPuts);219 t.* = try std.Thread.spawn(startPuts, &context);
220 }220 }
221 var getters: [put_thread_count]*std.Thread = undefined;221 var getters: [put_thread_count]*std.Thread = undefined;
222 for (getters) |*t| {222 for (getters) |*t| {
223 t.* = try std.Thread.spawn(&context, startGets);223 t.* = try std.Thread.spawn(startGets, &context);
224 }224 }
225225
226 for (putters) |t|226 for (putters) |t|
lib/std/atomic/stack.zig+2-2
...@@ -123,11 +123,11 @@ test "std.atomic.stack" {...@@ -123,11 +123,11 @@ test "std.atomic.stack" {
123 } else {123 } else {
124 var putters: [put_thread_count]*std.Thread = undefined;124 var putters: [put_thread_count]*std.Thread = undefined;
125 for (putters) |*t| {125 for (putters) |*t| {
126 t.* = try std.Thread.spawn(&context, startPuts);126 t.* = try std.Thread.spawn(startPuts, &context);
127 }127 }
128 var getters: [put_thread_count]*std.Thread = undefined;128 var getters: [put_thread_count]*std.Thread = undefined;
129 for (getters) |*t| {129 for (getters) |*t| {
130 t.* = try std.Thread.spawn(&context, startGets);130 t.* = try std.Thread.spawn(startGets, &context);
131 }131 }
132132
133 for (putters) |t|133 for (putters) |t|
lib/std/event/loop.zig+5-5
...@@ -185,7 +185,7 @@ pub const Loop = struct {...@@ -185,7 +185,7 @@ pub const Loop = struct {
185 errdefer self.deinitOsData();185 errdefer self.deinitOsData();
186186
187 if (!builtin.single_threaded) {187 if (!builtin.single_threaded) {
188 self.fs_thread = try Thread.spawn(self, posixFsRun);188 self.fs_thread = try Thread.spawn(posixFsRun, self);
189 }189 }
190 errdefer if (!builtin.single_threaded) {190 errdefer if (!builtin.single_threaded) {
191 self.posixFsRequest(&self.fs_end_request);191 self.posixFsRequest(&self.fs_end_request);
...@@ -264,7 +264,7 @@ pub const Loop = struct {...@@ -264,7 +264,7 @@ pub const Loop = struct {
264 }264 }
265 }265 }
266 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {266 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
267 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);267 self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
268 }268 }
269 },269 },
270 .macos, .freebsd, .netbsd, .dragonfly, .openbsd => {270 .macos, .freebsd, .netbsd, .dragonfly, .openbsd => {
...@@ -329,7 +329,7 @@ pub const Loop = struct {...@@ -329,7 +329,7 @@ pub const Loop = struct {
329 }329 }
330 }330 }
331 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {331 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
332 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);332 self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
333 }333 }
334 },334 },
335 .windows => {335 .windows => {
...@@ -378,7 +378,7 @@ pub const Loop = struct {...@@ -378,7 +378,7 @@ pub const Loop = struct {
378 }378 }
379 }379 }
380 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {380 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
381 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);381 self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
382 }382 }
383 },383 },
384 else => {},384 else => {},
...@@ -798,7 +798,7 @@ pub const Loop = struct {...@@ -798,7 +798,7 @@ pub const Loop = struct {
798 .event = std.Thread.AutoResetEvent{},798 .event = std.Thread.AutoResetEvent{},
799 .is_running = true,799 .is_running = true,
800 // Must be last so that it can read the other state, such as `is_running`.800 // Must be last so that it can read the other state, such as `is_running`.
801 .thread = try std.Thread.spawn(self, DelayQueue.run),801 .thread = try std.Thread.spawn(DelayQueue.run, self),
802 };802 };
803 }803 }
804804
lib/std/fs/test.zig+1-1
...@@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" {...@@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" {
762 try evt.init();762 try evt.init();
763 defer evt.deinit();763 defer evt.deinit();
764764
765 const t = try std.Thread.spawn(S.C{ .dir = &tmp.dir, .evt = &evt }, S.checkFn);765 const t = try std.Thread.spawn(S.checkFn, S.C{ .dir = &tmp.dir, .evt = &evt });
766 defer t.wait();766 defer t.wait();
767767
768 const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;768 const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;
lib/std/net/test.zig+2-2
...@@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" {
161 }161 }
162 };162 };
163163
164 const t = try std.Thread.spawn(server.listen_address, S.clientFn);164 const t = try std.Thread.spawn(S.clientFn, server.listen_address);
165 defer t.wait();165 defer t.wait();
166166
167 var client = try server.accept();167 var client = try server.accept();
...@@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" {...@@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
285 }285 }
286 };286 };
287287
288 const t = try std.Thread.spawn({}, S.clientFn);288 const t = try std.Thread.spawn(S.clientFn, {});
289 defer t.wait();289 defer t.wait();
290290
291 var client = try server.accept();291 var client = try server.accept();
lib/std/once.zig+2-2
...@@ -59,11 +59,11 @@ test "Once executes its function just once" {...@@ -59,11 +59,11 @@ test "Once executes its function just once" {
59 defer for (threads) |handle| handle.wait();59 defer for (threads) |handle| handle.wait();
6060
61 for (threads) |*handle| {61 for (threads) |*handle| {
62 handle.* = try std.Thread.spawn(@as(u8, 0), struct {62 handle.* = try std.Thread.spawn(struct {
63 fn thread_fn(x: u8) void {63 fn thread_fn(x: u8) void {
64 global_once.call();64 global_once.call();
65 }65 }
66 }.thread_fn);66 }.thread_fn, 0);
67 }67 }
68 }68 }
6969
lib/std/os/test.zig+7-7
...@@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {...@@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {
317 if (builtin.single_threaded) return error.SkipZigTest;317 if (builtin.single_threaded) return error.SkipZigTest;
318318
319 var thread_current_id: Thread.Id = undefined;319 var thread_current_id: Thread.Id = undefined;
320 const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);320 const thread = try Thread.spawn(testThreadIdFn, &thread_current_id);
321 const thread_id = thread.handle();321 const thread_id = thread.handle();
322 thread.wait();322 thread.wait();
323 if (Thread.use_pthreads) {323 if (Thread.use_pthreads) {
...@@ -336,10 +336,10 @@ test "spawn threads" {...@@ -336,10 +336,10 @@ test "spawn threads" {
336336
337 var shared_ctx: i32 = 1;337 var shared_ctx: i32 = 1;
338338
339 const thread1 = try Thread.spawn({}, start1);339 const thread1 = try Thread.spawn(start1, {});
340 const thread2 = try Thread.spawn(&shared_ctx, start2);340 const thread2 = try Thread.spawn(start2, &shared_ctx);
341 const thread3 = try Thread.spawn(&shared_ctx, start2);341 const thread3 = try Thread.spawn(start2, &shared_ctx);
342 const thread4 = try Thread.spawn(&shared_ctx, start2);342 const thread4 = try Thread.spawn(start2, &shared_ctx);
343343
344 thread1.wait();344 thread1.wait();
345 thread2.wait();345 thread2.wait();
...@@ -367,8 +367,8 @@ test "cpu count" {...@@ -367,8 +367,8 @@ test "cpu count" {
367367
368test "thread local storage" {368test "thread local storage" {
369 if (builtin.single_threaded) return error.SkipZigTest;369 if (builtin.single_threaded) return error.SkipZigTest;
370 const thread1 = try Thread.spawn({}, testTls);370 const thread1 = try Thread.spawn(testTls, {});
371 const thread2 = try Thread.spawn({}, testTls);371 const thread2 = try Thread.spawn(testTls, {});
372 testTls({});372 testTls({});
373 thread1.wait();373 thread1.wait();
374 thread2.wait();374 thread2.wait();
src/ThreadPool.zig+1-1
...@@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {...@@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {
74 try worker.idle_node.data.init();74 try worker.idle_node.data.init();
75 errdefer worker.idle_node.data.deinit();75 errdefer worker.idle_node.data.deinit();
7676
77 worker.thread = try std.Thread.spawn(worker, Worker.run);77 worker.thread = try std.Thread.spawn(Worker.run, worker);
78 }78 }
79}79}
8080