aboutsummaryrefslogtreecommitdiff
path: root/src/scheduler.zig
blob: 9034a84d04689fb1f1a9eb897c95cd51a901d307 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const std = @import("std");

pub fn Scheduler(function: anytype) type {
	const FuncType = @TypeOf(function);
	const func_info = @typeInfo(FuncType).@"fn";
	const R = func_info.return_type orelse std.builtin.Type.Void;
	const ArgType = std.meta.ArgsTuple(FuncType);

	const wrapper = struct {
		pub fn call(args: ArgType, result: *R) void {
			result.* = @call(.auto, function, args);
		}
	}.call;

	return struct {
		const Self = @This();

		allocator: std.mem.Allocator,
		pool: std.Thread.Pool,
		wait_group: std.Thread.WaitGroup,
		results: std.ArrayList(*R),

		pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
			self.allocator = allocator;
			self.results = std.ArrayList(*R).init(allocator);
			self.wait_group.reset();

			try self.pool.init(.{
				.allocator = allocator,
			});
		}

		pub fn push_task(self: *Self, args: ArgType) !void {
			const result = try self.allocator.create(R);
			try self.results.append(result);
			self.pool.spawnWg(
				&self.wait_group,
				wrapper,
				.{ args, result }
			);
		}

		pub fn deinit(self: *Self) ![]R {
			self.pool.waitAndWork(&self.wait_group);
			self.pool.deinit();

			const results = try self.allocator.alloc(R, self.results.items.len);
			
			for (self.results.items, 0..) |result, index| {
				results[index] = result.*;
				self.allocator.destroy(result);
			}

			self.results.deinit();
			self.* = undefined;

			return results;
		}
	};
}