Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
on: [push, pull_request]
name: Test
env:
ZIG_VERSION: 0.15.2
ZIG_VERSION: 0.16.0

jobs:
build:
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ major event loops. This may differ on a feature-by-feature basis, and
if you can show really poor performance in an issue I'm interested
in resolving it!

### Integration with Zig 0.16+ std.Io

Libxev doesn't implement the `std.Io` interface and doesn't take
a `std.Io` for any of its operations. It calls IO directly using system
calls and in the few rare cases it must use a `std.Io` (such as for mutex
operations), libxev uses the global `std.Io.Threaded` implementation.

The reason for this is because libxev is a very old library that
predates `std.Io`, so it bakes in a lot of assumptions that don't really
fit into the new `std.Io` model. To support this, we'll have to break
our API significantly.

Additionally, the `std.Io` interface is still very new and unstable and
doesn't expose all the operations necessary to bring parity with libxev.

We will investigate better, more idiomatic integrations with `std.Io`
in the future. For now, libxev continues to work Zig 0.16 but mostly as
it did in prior Zig versions and doesn't integrate with `std.Io`.

## Example

The example below shows an identical program written in Zig and in C
Expand Down Expand Up @@ -272,7 +291,7 @@ directory.

# Build

Build requires the installation of the Zig 0.15.1. libxev follows stable
Build requires the installation of the Zig 0.16. libxev follows stable
Zig releases and generally does not support nightly builds. When a stable
release is imminent we may have a branch that supports it.
**libxev has no other build dependencies.**
Expand Down
94 changes: 53 additions & 41 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ pub fn build(b: *std.Build) !void {
true
else |err| switch (err) {
error.FileNotFound => false,
else => return err,
};

const emit_bench = b.option(
Expand All @@ -41,25 +40,23 @@ pub fn build(b: *std.Build) !void {
"Install the example binaries to zig-out",
) orelse false;

const c_api_module = b.createModule(.{
.root_source_file = b.path("src/c_api.zig"),
.target = target,
.optimize = optimize,
});

// Static C lib
const static_lib: ?*Step.Compile = lib: {
if (target.result.os.tag == .wasi) break :lib null;

const static_lib = b.addLibrary(.{
.linkage = .static,
.name = "xev",
.root_module = c_api_module,
.root_module = b.createModule(.{
.root_source_file = b.path("src/c_api.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
static_lib.linkLibC();
if (target.result.os.tag == .windows) {
static_lib.linkSystemLibrary("ws2_32");
static_lib.linkSystemLibrary("mswsock");
static_lib.root_module.linkSystemLibrary("ws2_32", .{});
static_lib.root_module.linkSystemLibrary("mswsock", .{});
}
break :lib static_lib;
};
Expand All @@ -72,7 +69,11 @@ pub fn build(b: *std.Build) !void {
const dynamic_lib = b.addLibrary(.{
.linkage = .dynamic,
.name = "xev",
.root_module = c_api_module,
.root_module = b.createModule(.{
.root_source_file = b.path("src/c_api.zig"),
.target = target,
.optimize = optimize,
}),
});
break :lib dynamic_lib;
};
Expand Down Expand Up @@ -119,20 +120,19 @@ pub fn build(b: *std.Build) !void {
"test-filter",
"Filter for test",
);
const test_exe = b.addTest(.{
break :test_exe b.addTest(.{
.name = "xev-test",
.filters = if (test_filter) |filter| &.{filter} else &.{},
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = switch (target.result.os.tag) {
.linux, .macos => true,
else => null,
},
}),
});
switch (target.result.os.tag) {
.linux, .macos => test_exe.linkLibC(),
else => {},
}
break :test_exe test_exe;
};

// "test" Step
Expand Down Expand Up @@ -172,19 +172,24 @@ fn buildBenchmarks(
b: *std.Build,
target: std.Build.ResolvedTarget,
) ![]const *Step.Compile {
const io = b.graph.io;
const alloc = b.allocator;
var steps: std.ArrayList(*Step.Compile) = .empty;
defer steps.deinit(alloc);

var dir = try std.fs.cwd().openDir(try b.build_root.join(
b.allocator,
&.{ "src", "bench" },
), .{ .iterate = true });
defer dir.close();
var dir = try std.Io.Dir.cwd().openDir(
io,
try b.build_root.join(
b.allocator,
&.{ "src", "bench" },
),
.{ .iterate = true },
);
defer dir.close(io);

// Go through and add each as a step
var it = dir.iterate();
while (try it.next()) |entry| {
while (try it.next(io)) |entry| {
// Get the index of the last '.' so we can strip the extension.
const index = std.mem.lastIndexOfScalar(
u8,
Expand Down Expand Up @@ -223,19 +228,24 @@ fn buildExamples(
optimize: std.builtin.OptimizeMode,
c_lib_: ?*Step.Compile,
) ![]const *Step.Compile {
const io = b.graph.io;
const alloc = b.allocator;
var steps: std.ArrayList(*Step.Compile) = .empty;
defer steps.deinit(alloc);

var dir = try std.fs.cwd().openDir(try b.build_root.join(
b.allocator,
&.{"examples"},
), .{ .iterate = true });
defer dir.close();
var dir = try std.Io.Dir.cwd().openDir(
io,
try b.build_root.join(
b.allocator,
&.{"examples"},
),
.{ .iterate = true },
);
defer dir.close(io);

// Go through and add each as a step
var it = dir.iterate();
while (try it.next()) |entry| {
while (try it.next(io)) |entry| {
// Get the index of the last '.' so we can strip the extension.
const index = std.mem.lastIndexOfScalar(
u8,
Expand Down Expand Up @@ -269,11 +279,11 @@ fn buildExamples(
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
exe.linkLibC();
exe.addIncludePath(b.path("include"));
exe.addCSourceFile(.{
exe.root_module.addIncludePath(b.path("include"));
exe.root_module.addCSourceFile(.{
.file = b.path(b.fmt(
"examples/{s}",
.{entry.name},
Expand All @@ -286,7 +296,7 @@ fn buildExamples(
"-D_POSIX_C_SOURCE=199309L",
},
});
exe.linkLibrary(c_lib);
exe.root_module.linkLibrary(c_lib);
break :exe exe;
};

Expand All @@ -298,18 +308,20 @@ fn buildExamples(
}

fn manPages(b: *std.Build) ![]const *Step {
const io = b.graph.io;
const alloc = b.allocator;
var steps: std.ArrayList(*Step) = .empty;
defer steps.deinit(alloc);

var dir = try std.fs.cwd().openDir(try b.build_root.join(
b.allocator,
&.{"docs"},
), .{ .iterate = true });
defer dir.close();
var dir = try std.Io.Dir.cwd().openDir(
io,
try b.build_root.join(b.allocator, &.{"docs"}),
.{ .iterate = true },
);
defer dir.close(io);

var it = dir.iterate();
while (try it.next()) |*entry| {
while (try it.next(io)) |*entry| {
// Filenames must end in "{section}.scd" and sections are
// single numerals.
const base = entry.name[0 .. entry.name.len - 4];
Expand All @@ -321,7 +333,7 @@ fn manPages(b: *std.Build) ![]const *Step {
) });

try steps.append(alloc, &b.addInstallFile(
cmd.captureStdOut(),
cmd.captureStdOut(.{}),
b.fmt("share/man/man{s}/{s}", .{ section, base }),
).step);
}
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = .libxev,
.minimum_zig_version = "0.15.1",
.minimum_zig_version = "0.16.0",
.version = "0.0.0",
.fingerprint = 0x30f7363573edabf3,
.paths = .{""},
Expand Down
1 change: 0 additions & 1 deletion examples/_basic.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const std = @import("std");
const Instant = std.time.Instant;
const xev = @import("xev");

pub fn main() !void {
Expand Down
37 changes: 10 additions & 27 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# Other overlays
(final: prev: rec {
zigpkgs = inputs.zig.packages.${prev.system};
zig = inputs.zig.packages.${prev.system}."0.15.2";
zig = inputs.zig.packages.${prev.system}."0.16.0";

# Our package
libxev = prev.callPackage ./nix/package.nix {};
Expand Down
10 changes: 8 additions & 2 deletions src/ThreadPool.zig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const ThreadPool = @This();
const std = @import("std");
const assert = std.debug.assert;
const Atomic = std.atomic.Value;
const Io = std.Io;

// I know we shouldn't use a global io here, but we are doing this
// during the transition period so libxev is at least usable with Zig
// 0.16 until we do a cleaner transition.
const io = Io.Threaded.global_single_threaded.io();

stack_size: u32,
max_threads: u32,
Expand Down Expand Up @@ -487,7 +493,7 @@ const Event = struct {
// Acquiring to WAITING will make the next notify() or shutdown() wake a sleeping futex thread
// who will either exit on SHUTDOWN or acquire with WAITING again, ensuring all threads are awoken.
// This unfortunately results in the last notify() or shutdown() doing an extra futex wake but that's fine.
std.Thread.Futex.wait(&self.state, WAITING);
io.futexWaitUncancelable(u32, &self.state.raw, WAITING);
state = self.state.load(.monotonic);
acquire_with = WAITING;
}
Expand All @@ -513,7 +519,7 @@ const Event = struct {
// Only wake threads sleeping in futex if the state is WAITING.
// Avoids unnecessary wake ups.
if (state == WAITING) {
std.Thread.Futex.wake(&self.state, wake_threads);
io.futexWake(u32, &self.state.raw, wake_threads);
}
}
};
Expand Down
Loading
Loading