tardy (def: delaying or delayed beyond the right or expected time; late.) is an asynchronous runtime for writing applications and services in Zig. Most of the code for this project originated in zzz, a performance oriented networking framework.
- tardy utilizes the latest Asynchronous APIs while minimizing allocations.
- tardy natively supports Linux, Mac, BSD, and Windows.
- tardy is configurable, allowing you to optimize the runtime for your specific use-case.
tardy is a thread-local, I/O driven runtime for Zig, providing the core implementation for asynchronous libraries and services.
- Per-thread Runtime isolation for minimal contention
- Native async I/O (io_uring, epoll, kqueue, poll, etc.)
- Asynchronous
Sockets andFiles. - Coroutines (internally called Frames).
Compatible Zig Version: 0.15.2
Latest Release: 0.3.0
zig fetch --save git+https://github.com/tardy-org/tardy#v0.3.0
You can then add the dependency in your build.zig file:
const tardy = b.dependency("tardy", .{
.target = target,
.optimize = optimize,
}).module("tardy");
exe_mod.addImport("tardy", tardy);-
NOTE: by default build/install step uses
-Dexample=none, meaning it wont build any examples -
List available examples
zig build --help- Build/run a specific example
zig build -Dexample=[nameOfExample]zig build run -Dexample=[nameOfExample]- Build all examples
zig build -Dexample=allA basic multi-threaded TCP echo server.
const std = @import("std");
const AcceptResult = @import("tardy").AcceptResult;
const Cross = @import("tardy").Cross;
const Pool = @import("tardy").Pool;
const RecvResult = @import("tardy").RecvResult;
const Runtime = @import("tardy").Runtime;
const SendResult = @import("tardy").SendResult;
const Socket = @import("tardy").Socket;
const Task = @import("tardy").Task;
const Timer = @import("tardy").Timer;
const Tardy = @import("tardy").Tardy(.auto);
const log = std.log.scoped(.@"tardy/example/echo");
fn echo_frame(rt: *Runtime, server: *const Socket) !void {
const socket = try server.accept(rt);
defer socket.close_blocking();
var sock_reader = socket.reader(rt, &.{});
const sock_r = &sock_reader.interface;
var sock_writer = socket.writer(rt, &.{});
const sock_w = &sock_writer.interface;
defer sock_w.flush() catch unreachable;
log.debug(
"{d} - accepted socket [{f}]",
.{ std.time.milliTimestamp(), socket.addr },
);
// spawn off a new frame.
try rt.spawn(.{ rt, server }, echo_frame, 1024 * 16);
var buffer: [501]u8 = undefined;
while (true) {
const recv_length = sock_r.readSliceShort(&buffer) catch |e| {
log.err("Failed to recv on socket | {t}", .{e});
break;
};
if (recv_length == 0) return;
sock_w.writeAll(buffer[0..recv_length]) catch |e| {
log.err("Failed to send on socket | {t}", .{e});
break;
};
log.debug("Echoed: {s}", .{buffer[0..recv_length]});
}
}
pub fn main() !void {
var gpa: std.heap.DebugAllocator(.{}) = .init;
const allocator = gpa.allocator();
defer _ = gpa.deinit();
var tardy: Tardy = try .init(allocator, .{
.threading = .single,
.pooling = .static,
.size_tasks_initial = 256,
.size_aio_reap_max = 256,
});
defer tardy.deinit();
const host = "0.0.0.0";
const port = 9862;
const server: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } });
try server.bind();
try server.listen(1024);
try tardy.entry(
&server,
struct {
fn start(rt: *Runtime, tcp_server: *const Socket) !void {
try rt.spawn(.{ rt, tcp_server }, echo_frame, 1024 * 16);
}
}.start,
);
}There exist a lot more examples, highlighting a variety of use cases and features here. For an example of tardy in use, you can check out any of the projects in the ecosystem.
- zzz: a framework for writing performant and reliable networked services.
- secsock: Async TLS for the Tardy Socket.
We use Nix Flakes for managing the development environment. Nix Flakes provide a reproducible, declarative approach to managing dependencies and development tools.
- Install Nix
sh <(curl -L https://nixos.org/nix/install) --daemon- Enable Flake support in your Nix config (
~/.config/nix/nix.conf):experimental-features = nix-command flakes
- Clone this repository:
git clone https://github.com/tardy-org/tardy.git
cd tardy- Enter the development environment:
nix developThis will provide you with a shell that contains all of the necessary tools and dependencies for development.
Once you are inside of the development shell, you can update the development dependencies by:
- Modifying the
flake.nix - Running
nix flake update - Committing both the
flake.nixand theflake.lock
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in tardy by you, shall be licensed as MPL2.0, without any additional terms or conditions.