Skip to content

Commit 22b7312

Browse files
authored
Merge pull request #1173 from ziglang/event-loop-channel
add event loop Channel abstraction
2 parents 3546352 + 2da9993 commit 22b7312

File tree

6 files changed

+465
-52
lines changed

6 files changed

+465
-52
lines changed

src-self-hosted/main.zig

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const std = @import("std");
22
const builtin = @import("builtin");
33

4+
const event = std.event;
45
const os = std.os;
56
const io = std.io;
67
const mem = std.mem;
@@ -43,6 +44,9 @@ const Command = struct {
4344
};
4445

4546
pub fn main() !void {
47+
// This allocator needs to be thread-safe because we use it for the event.Loop
48+
// which multiplexes coroutines onto kernel threads.
49+
// libc allocator is guaranteed to have this property.
4650
const allocator = std.heap.c_allocator;
4751

4852
var stdout_file = try std.io.getStdOut();
@@ -380,8 +384,10 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
380384
const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
381385
defer allocator.free(zig_lib_dir);
382386

387+
var loop = try event.Loop.init(allocator);
388+
383389
var module = try Module.create(
384-
allocator,
390+
&loop,
385391
root_name,
386392
root_source_file,
387393
Target.Native,
@@ -471,9 +477,35 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
471477
module.emit_file_type = emit_type;
472478
module.link_objects = link_objects;
473479
module.assembly_files = assembly_files;
480+
module.link_out_file = flags.single("out-file");
474481

475482
try module.build();
476-
try module.link(flags.single("out-file"));
483+
const process_build_events_handle = try async<loop.allocator> processBuildEvents(module, true);
484+
defer cancel process_build_events_handle;
485+
loop.run();
486+
}
487+
488+
async fn processBuildEvents(module: *Module, watch: bool) void {
489+
while (watch) {
490+
// TODO directly awaiting async should guarantee memory allocation elision
491+
const build_event = await (async module.events.get() catch unreachable);
492+
493+
switch (build_event) {
494+
Module.Event.Ok => {
495+
std.debug.warn("Build succeeded\n");
496+
// for now we stop after 1
497+
module.loop.stop();
498+
return;
499+
},
500+
Module.Event.Error => |err| {
501+
std.debug.warn("build failed: {}\n", @errorName(err));
502+
@panic("TODO error return trace");
503+
},
504+
Module.Event.Fail => |errs| {
505+
@panic("TODO print compile error messages");
506+
},
507+
}
508+
}
477509
}
478510

479511
fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void {
@@ -780,4 +812,3 @@ const CliPkg = struct {
780812
self.children.deinit();
781813
}
782814
};
783-

src-self-hosted/module.zig

Lines changed: 101 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ const warn = std.debug.warn;
1111
const Token = std.zig.Token;
1212
const ArrayList = std.ArrayList;
1313
const errmsg = @import("errmsg.zig");
14+
const ast = std.zig.ast;
15+
const event = std.event;
1416

1517
pub const Module = struct {
16-
allocator: *mem.Allocator,
18+
loop: *event.Loop,
1719
name: Buffer,
1820
root_src_path: ?[]const u8,
1921
module: llvm.ModuleRef,
@@ -76,6 +78,51 @@ pub const Module = struct {
7678

7779
kind: Kind,
7880

81+
link_out_file: ?[]const u8,
82+
events: *event.Channel(Event),
83+
84+
// TODO handle some of these earlier and report them in a way other than error codes
85+
pub const BuildError = error{
86+
OutOfMemory,
87+
EndOfStream,
88+
BadFd,
89+
Io,
90+
IsDir,
91+
Unexpected,
92+
SystemResources,
93+
SharingViolation,
94+
PathAlreadyExists,
95+
FileNotFound,
96+
AccessDenied,
97+
PipeBusy,
98+
FileTooBig,
99+
SymLinkLoop,
100+
ProcessFdQuotaExceeded,
101+
NameTooLong,
102+
SystemFdQuotaExceeded,
103+
NoDevice,
104+
PathNotFound,
105+
NoSpaceLeft,
106+
NotDir,
107+
FileSystem,
108+
OperationAborted,
109+
IoPending,
110+
BrokenPipe,
111+
WouldBlock,
112+
FileClosed,
113+
DestinationAddressRequired,
114+
DiskQuota,
115+
InputOutput,
116+
NoStdHandles,
117+
Overflow,
118+
};
119+
120+
pub const Event = union(enum) {
121+
Ok,
122+
Fail: []errmsg.Msg,
123+
Error: BuildError,
124+
};
125+
79126
pub const DarwinVersionMin = union(enum) {
80127
None,
81128
MacOS: []const u8,
@@ -104,7 +151,7 @@ pub const Module = struct {
104151
};
105152

106153
pub fn create(
107-
allocator: *mem.Allocator,
154+
loop: *event.Loop,
108155
name: []const u8,
109156
root_src_path: ?[]const u8,
110157
target: *const Target,
@@ -113,7 +160,7 @@ pub const Module = struct {
113160
zig_lib_dir: []const u8,
114161
cache_dir: []const u8,
115162
) !*Module {
116-
var name_buffer = try Buffer.init(allocator, name);
163+
var name_buffer = try Buffer.init(loop.allocator, name);
117164
errdefer name_buffer.deinit();
118165

119166
const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
@@ -125,8 +172,12 @@ pub const Module = struct {
125172
const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
126173
errdefer c.LLVMDisposeBuilder(builder);
127174

128-
const module_ptr = try allocator.create(Module{
129-
.allocator = allocator,
175+
const events = try event.Channel(Event).create(loop, 0);
176+
errdefer events.destroy();
177+
178+
return loop.allocator.create(Module{
179+
.loop = loop,
180+
.events = events,
130181
.name = name_buffer,
131182
.root_src_path = root_src_path,
132183
.module = module,
@@ -171,76 +222,87 @@ pub const Module = struct {
171222
.link_objects = [][]const u8{},
172223
.windows_subsystem_windows = false,
173224
.windows_subsystem_console = false,
174-
.link_libs_list = ArrayList(*LinkLib).init(allocator),
225+
.link_libs_list = ArrayList(*LinkLib).init(loop.allocator),
175226
.libc_link_lib = null,
176227
.err_color = errmsg.Color.Auto,
177228
.darwin_frameworks = [][]const u8{},
178229
.darwin_version_min = DarwinVersionMin.None,
179230
.test_filters = [][]const u8{},
180231
.test_name_prefix = null,
181232
.emit_file_type = Emit.Binary,
233+
.link_out_file = null,
182234
});
183-
errdefer allocator.destroy(module_ptr);
184-
return module_ptr;
185235
}
186236

187237
fn dump(self: *Module) void {
188238
c.LLVMDumpModule(self.module);
189239
}
190240

191241
pub fn destroy(self: *Module) void {
242+
self.events.destroy();
192243
c.LLVMDisposeBuilder(self.builder);
193244
c.LLVMDisposeModule(self.module);
194245
c.LLVMContextDispose(self.context);
195246
self.name.deinit();
196247

197-
self.allocator.destroy(self);
248+
self.a().destroy(self);
198249
}
199250

200251
pub fn build(self: *Module) !void {
201252
if (self.llvm_argv.len != 0) {
202-
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, [][]const []const u8{
253+
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.a(), [][]const []const u8{
203254
[][]const u8{"zig (LLVM option parsing)"},
204255
self.llvm_argv,
205256
});
206257
defer c_compatible_args.deinit();
258+
// TODO this sets global state
207259
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
208260
}
209261

262+
_ = try async<self.a()> self.buildAsync();
263+
}
264+
265+
async fn buildAsync(self: *Module) void {
266+
while (true) {
267+
// TODO directly awaiting async should guarantee memory allocation elision
268+
// TODO also async before suspending should guarantee memory allocation elision
269+
(await (async self.addRootSrc() catch unreachable)) catch |err| {
270+
await (async self.events.put(Event{ .Error = err }) catch unreachable);
271+
return;
272+
};
273+
await (async self.events.put(Event.Ok) catch unreachable);
274+
}
275+
}
276+
277+
async fn addRootSrc(self: *Module) !void {
210278
const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");
211-
const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
279+
const root_src_real_path = os.path.real(self.a(), root_src_path) catch |err| {
212280
try printError("unable to get real path '{}': {}", root_src_path, err);
213281
return err;
214282
};
215-
errdefer self.allocator.free(root_src_real_path);
283+
errdefer self.a().free(root_src_real_path);
216284

217-
const source_code = io.readFileAlloc(self.allocator, root_src_real_path) catch |err| {
285+
const source_code = io.readFileAlloc(self.a(), root_src_real_path) catch |err| {
218286
try printError("unable to open '{}': {}", root_src_real_path, err);
219287
return err;
220288
};
221-
errdefer self.allocator.free(source_code);
222-
223-
warn("====input:====\n");
224-
225-
warn("{}", source_code);
289+
errdefer self.a().free(source_code);
226290

227-
warn("====parse:====\n");
228-
229-
var tree = try std.zig.parse(self.allocator, source_code);
291+
var tree = try std.zig.parse(self.a(), source_code);
230292
defer tree.deinit();
231293

232-
var stderr_file = try std.io.getStdErr();
233-
var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
234-
const out_stream = &stderr_file_out_stream.stream;
235-
236-
warn("====fmt:====\n");
237-
_ = try std.zig.render(self.allocator, out_stream, &tree);
238-
239-
warn("====ir:====\n");
240-
warn("TODO\n\n");
241-
242-
warn("====llvm ir:====\n");
243-
self.dump();
294+
//var it = tree.root_node.decls.iterator();
295+
//while (it.next()) |decl_ptr| {
296+
// const decl = decl_ptr.*;
297+
// switch (decl.id) {
298+
// ast.Node.Comptime => @panic("TODO"),
299+
// ast.Node.VarDecl => @panic("TODO"),
300+
// ast.Node.UseDecl => @panic("TODO"),
301+
// ast.Node.FnDef => @panic("TODO"),
302+
// ast.Node.TestDecl => @panic("TODO"),
303+
// else => unreachable,
304+
// }
305+
//}
244306
}
245307

246308
pub fn link(self: *Module, out_file: ?[]const u8) !void {
@@ -263,18 +325,22 @@ pub const Module = struct {
263325
}
264326
}
265327

266-
const link_lib = try self.allocator.create(LinkLib{
328+
const link_lib = try self.a().create(LinkLib{
267329
.name = name,
268330
.path = null,
269331
.provided_explicitly = provided_explicitly,
270-
.symbols = ArrayList([]u8).init(self.allocator),
332+
.symbols = ArrayList([]u8).init(self.a()),
271333
});
272334
try self.link_libs_list.append(link_lib);
273335
if (is_libc) {
274336
self.libc_link_lib = link_lib;
275337
}
276338
return link_lib;
277339
}
340+
341+
fn a(self: Module) *mem.Allocator {
342+
return self.loop.allocator;
343+
}
278344
};
279345

280346
fn printError(comptime format: []const u8, args: ...) !void {

std/atomic/queue_mpsc.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const std = @import("std");
1+
const std = @import("../index.zig");
22
const assert = std.debug.assert;
33
const builtin = @import("builtin");
44
const AtomicOrder = builtin.AtomicOrder;

0 commit comments

Comments
 (0)