authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-28 20:42:34-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-02-28 20:42:34-08:00
log9550db33cbb7dadd555842ef6d7214660e2b00d6
treeffcf41a01dc8a55f06f5a630ed174550be33dad3
parenta5a3ad4f956bae1ca0e5a49de2e9ac7145170039
parentd3d3e55fae2299d1ff594c77da2f1f41f44ab525
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8097 from LemonBoy/thread-spawn-order

std: Swap arguments in Thread.spawn

14 files changed, 51 insertions(+), 37 deletions(-)

doc/langref.html.in+2-2
...@@ -933,8 +933,8 @@ const assert = std.debug.assert;...@@ -933,8 +933,8 @@ const assert = std.debug.assert;
933threadlocal var x: i32 = 1234;933threadlocal var x: i32 = 1234;
934934
935test "thread local storage" {935test "thread local storage" {
936 const thread1 = try std.Thread.spawn({}, testTls);936 const thread1 = try std.Thread.spawn(testTls, {});
937 const thread2 = try std.Thread.spawn({}, testTls);937 const thread2 = try std.Thread.spawn(testTls, {});
938 testTls({});938 testTls({});
939 thread1.wait();939 thread1.wait();
940 thread2.wait();940 thread2.wait();
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