• Stars
    star
    1,589
  • Rank 29,435 (Top 0.6 %)
  • Language
    Zig
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

libxev is a cross-platform, high-performance event loop that provides abstractions for non-blocking IO, timers, events, and more and works on Linux (io_uring or epoll), macOS (kqueue), and Wasm + WASI. Available as both a Zig and C API.

libxev

libxev is a cross-platform event loop. libxev provides a unified event loop abstraction for non-blocking IO, timers, signals, events, and more that works on macOS, Windows, Linux, and WebAssembly (browser and WASI). It is written in Zig but exports a C-compatible API (which further makes it compatible with any language out there that can communicate with C APIs).

Project Status: 🐲 Unstable, alpha-ish quality. The feature list is quite good across multiple platforms, but there are plenty of missing features. The project hasn't been well tested in real-world environments and there are lots of low-hanging fruit for performance optimization. I'm not promising any API compatibility at this point, either. If you want a production ready, high quality, generalized event loop implementation check out libuv, libev, etc.

Why a new event loop library? A few reasons. One, I think Zig lacks a generalized event loop comparable to libuv in features ("generalized" being a key word here). Two, I wanted to build a library like this around the design patterns of io_uring, even mimicking its style on top of other OS primitives ( credit to this awesome blog post). Three, I wanted an event loop library that could build to WebAssembly (both WASI and freestanding) and that didn't really fit well into the goals of API style of existing libraries without bringing in something super heavy like Emscripten. The motivation for this library primarily though is scratching my own itch!

Features

Cross-platform. Linux (io_uring and epoll), macOS (kqueue), WebAssembly + WASI (poll_oneoff, threaded and non-threaded runtimes). (Windows support is planned and coming soon)

Proactor API. Work is submitted to the libxev event loop and the caller is notified of work completion, as opposed to work readiness.

Zero runtime allocations. This helps make runtime performance more predictable and makes libxev well suited for embedded environments.

Timers, TCP, UDP, Files, Processes. High-level platform-agnostic APIs for interacting with timers, TCP/UDP sockets, files, processes, and more. For platforms that don't support async IO, the file operations are automatically scheduled to a thread pool.

Generic Thread Pool (Optional). You can create a generic thread pool, configure its resource utilization, and use this to perform custom background tasks. The thread pool is used by some backends to do non-blocking tasks that don't have reliable non-blocking APIs (such as local file operations with kqueue). The thread pool can be shared across multiple threads and event loops to optimize resource utilization.

Low-level and High-Level API. The high-level API is platform-agnostic but has some opinionated behavior and limited flexibility. The high-level API is recommended but the low-level API is always an available escape hatch. The low-level API is platform-specific and provides a mechanism for libxev users to squeeze out maximum performance. The low-level API is just enough abstraction above the OS interface to make it easier to use without sacrificing noticable performance.

Tree Shaking (Zig). This is a feature of Zig, but substantially benefits libraries such as libxev. Zig will only include function calls and features that you actually use. If you don't use a particular kind of high-level watcher (such as UDP sockets), then the functionality related to that abstraction is not compiled into your final binary at all. This lets libxev support optional "nice-to-have" functionality that may be considered "bloat" in some cases, but the end user doesn't have to pay for it.

Dependency-free. libxev has no dependencies other than the built-in OS APIs at runtime. The C library depends on libc. This makes it very easy to cross-compile.

Roadmap

There are plenty of missing features that I still want to add:

  • Pipe high-level API
  • Signal handlers
  • Filesystem events
  • Windows backend
  • Freestanding WebAssembly support via an external event loop (i.e. the browser)

And more...

Performance

There is plenty of room for performance improvements, and I want to be fully clear that I haven't done a lot of optimization work. Still, performance is looking good. I've tried to port many of libuv benchmarks to use the libxev API.

I won't post specific benchmark results until I have a better environment to run them in. As a very broad generalization, you shouldn't notice a slowdown using libxev compared to other 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!

Example

The example below shows an identical program written in Zig and in C that uses libxev to run a single 5s timer. This is almost silly how simple it is but is meant to just convey the overall feel of the library rather than a practical use case.

Zig C
const xev = @import("xev");

pub fn main() !void {
    var loop = try xev.Loop.init(.{});
    defer loop.deinit();

    const w = try xev.Timer.init();
    defer w.deinit();

    // 5s timer
    var c: xev.Completion = undefined;
    w.run(&loop, &c, 5000, void, null, &timerCallback);

    try loop.run(.until_done);
}

fn timerCallback(
    userdata: ?*void,
    loop: *xev.Loop,
    c: *xev.Completion,
    result: xev.Timer.RunError!void,
) xev.CallbackAction {
   _ = userdata;
   _ = loop;
   _ = c;
   _ = result catch unreachable;
   return .disarm;
}
#include <stddef.h>
#include <stdio.h>
#include <xev.h>

xev_cb_action timerCallback(xev_loop* loop, xev_completion* c, int result, void *userdata) {
    return XEV_DISARM;
}

int main(void) {
    xev_loop loop;
    if (xev_loop_init(&loop) != 0) {
        printf("xev_loop_init failure\n");
        return 1;
    }

    xev_watcher w;
    if (xev_timer_init(&w) != 0) {
        printf("xev_timer_init failure\n");
        return 1;
    }

    xev_completion c;
    xev_timer_run(&w, &loop, &c, 5000, NULL, &timerCallback);

    xev_loop_run(&loop, XEV_RUN_UNTIL_DONE);

    xev_timer_deinit(&w);
    xev_loop_deinit(&loop);
    return 0;
}

Installation (Zig)

These instructions are for Zig downstream users only. If you are using the C API to libxev, see the "Build" section.

This package works with the Zig package manager introduced in Zig 0.11. Create a build.zig.zon file like this:

.{
    .name = "my-project",
    .version = "0.0.0",
    .dependencies = .{
        .libxev = .{
            .url = "https://github.com/mitchellh/libxev/archive/<git-ref-here>.tar.gz",
            .hash = "12208070233b17de6be05e32af096a6760682b48598323234824def41789e993432c",
        },
    },
}

And in your build.zig:

const xev = b.dependency("libxev", .{ .target = target, .optimize = optimize });
exe.addModule("xev", xev.module("xev"));

Documentation

🚧 Documentation is a work-in-progress. 🚧

Currently, documentation is available in three forms: man pages, examples, and code comments. In the future, I plan on writing detailed guides and API documentation in website form, but that isn't currently available.

Man Pages

The man pages are relatively detailed! xev(7) will give you a good overview of the entire library. xev-zig(7) and xev-c(7) will provide overviews of the Zig and C API, respectively. From there, API-specifc man pages such as xev_loop_init(3) are available. This is the best documentation currently.

There are multiple ways to browse the man pages. The most immediately friendly is to just browse the raw man page sources in the docs/ directory in your web browser. The man page source is a markdown-like syntax so it renders okay in your browser via GitHub.

Another approach is to run zig build -Dman-pages and the man pages will be available in zig-out. This requires scdoc to be installed (this is available in most package managers). Once you've built the man pages, you can render them by path:

$ man zig-out/share/man/man7/xev.7

And the final approach is to install libxev via your favorite package manager (if and when available), which should hopefully put your man pages into your man path, so you can just do man 7 xev.

Examples

There are examples available in the examples/ folder. The examples are available in both C and Zig, and you can tell which one is which using the file extension.

To build an example, use the following:

$ zig build -Dexample-name=_basic.zig
...
$ zig-out/bin/example-basic
...

The -Dexample-name value should be the filename including the extension.

Code Comments

The Zig code is well commented. If you're comfortable reading code comments you can find a lot of insight within them. The source is in the src/ directory.

Build

Build requires the installation of the latest Zig nightly. libxev has no other build dependencies.

Once installed, zig build install on its own will build the full library and output a FHS-compatible directory in zig-out. You can customize the output directory with the --prefix flag.

Tests

libxev has a large and growing test suite. To run the tests for the current platform:

$ zig build test
...

This will run all the tests for all the supported features for the current host platform. For example, on Linux this will run both the full io_uring and epoll test suite.

You can build and run tests for other platforms by cross-compiling the test executable, copying it to a target machine and executing it. For example, the below shows how to cross-compile and build the tests for macOS from Linux:

$ zig build -Dtarget=aarch64-macos -Dinstall-tests
...

$ file zig-out/bin/xev-test
zig-out/bin/xev-test: Mach-O 64-bit arm64 executable

WASI is a special-case. You can run tests for WASI if you have wasmtime installed:

$ zig build test -Dtarget=wasm32-wasi -Dwasmtime
...

More Repositories

1

mapstructure

Go library for decoding generic map values into native Go structures and vice versa.
Go
7,685
star
2

gox

A dead simple, no frills Go cross compile tool
Go
4,594
star
3

vagrant-aws

Use Vagrant to manage your EC2 and VPC instances.
Ruby
2,609
star
4

nixos-config

My NixOS configurations.
Nix
1,791
star
5

cli

A Go library for implementing command-line interfaces.
Go
1,724
star
6

gon

Sign, notarize, and package macOS CLI tools and applications written in any language. Available as both a CLI and a Go library.
Go
1,461
star
7

go-ps

Find, list, and inspect processes from Go (golang).
Go
1,449
star
8

go-homedir

Go library for detecting and expanding the user's home directory without cgo.
Go
1,390
star
9

go-server-timing

Go (golang) library for creating and consuming HTTP Server-Timing headers
Go
861
star
10

hashstructure

Get hash values for arbitrary values in Go (golang).
Go
745
star
11

goamz

Golang Amazon Library
Go
673
star
12

golicense

Scan and analyze OSS dependencies and licenses from compiled Go binaries
Go
666
star
13

ioprogress

Go (golang) package for progress bars around io.Reader/Writers.
Go
502
star
14

go-mruby

Go (golang) bindings to mruby.
Go
468
star
15

panicwrap

panicwrap is a Go library for catching and handling panics in Go applications.
Go
443
star
16

advent-2021-sql

Advent of Code 2021 using SQL (PostgreSQL-flavored)
PLpgSQL
436
star
17

boot2docker-vagrant-box

Packer scripts to build a Vagrant-compatible boot2docker box.
Smarty
425
star
18

copystructure

Go (golang) library for deep copying values in Go.
Go
345
star
19

vagrant-google

Vagrant provider for GCE.
Ruby
334
star
20

go-glint

Component-based UI-framework for command-line tools. Easily create highly dynamic CLI interfaces using shared, easily testable components.
Go
311
star
21

go-vnc

VNC client and server library for Go.
Go
283
star
22

colorstring

Go (golang) library for colorizing strings for terminal output.
Go
276
star
23

reflectwalk

reflectwalk is a Go library for "walking" complex structures, similar to walking a filesystem.
Go
274
star
24

virtualbox

[ABANDONED] Create and modify virtual machines in VirtualBox using pure ruby.
Ruby
244
star
25

vagrant-rackspace

Use Vagrant to manage Rackspace Cloud instances.
Ruby
234
star
26

protoc-gen-go-json

Protobuf compiler plugin to generate Go JSON Marshal/Unmarshal implementations for messages using jsonpb.
Go
225
star
27

pointerstructure

Go library for addressing and reading/writing a specific value within any Go structure using a string syntax.
Go
214
star
28

zig-overlay

Nix flake for the Zig compiler.
Nix
195
star
29

zig-js

Access the JS host environment from Zig compiled to WebAssembly.
Zig
178
star
30

dotfiles

My personal dotfiles.
Batchfile
176
star
31

protostructure

Encode and decode Go (golang) struct types via protocol buffers.
Go
172
star
32

consulstructure

Decode Consul data into Go (Golang) structures and watch for updates
Go
172
star
33

packer-ubuntu-12.04-docker

Packer template that builds images that are Docker-ready on Ubuntu 12.04.
Shell
157
star
34

zig-libgc

Zig-friendly library for interfacing with libgc (bdwgc) -- the Boehm-Demers-Weiser conservative garbage collector
Zig
156
star
35

zig-objc

Objective-C runtime bindings for Zig (Zig calling ObjC).
Zig
153
star
36

libflightplan

A library for reading and writing flight plans in various formats. Available as both a C and Zig library.
Zig
153
star
37

terraform-provider-multispace

Terraform Provider for cascading runs across multiple workspaces.
Go
147
star
38

multistep

multistep is a Go library for building up complex actions using discrete steps.
Go
146
star
39

go-z3

Go (golang) bindings to the Z3 SMT Solver
Go
138
star
40

go-sat

SAT solver written in Go (golang).
Go
136
star
41

go-wordwrap

A Go (golang) library for wrapping words in a string.
Go
107
star
42

vim-misc

My Vim configuration files.
Vim Script
99
star
43

middleware

Generalized middleware implementation for Ruby.
Ruby
94
star
44

go-fs

Filesystem library for Go, implementing FAT filesystems so far.
Go
88
star
45

zig-graph

Directed graph data structure for Zig
Zig
86
star
46

go-grpc-net-conn

Turn any gRPC stream into a Go `net.Conn` implementation.
Go
80
star
47

zig-libxml2

libxml2 built using Zig build system
Zig
76
star
48

lightcloud

Library for accessing Plurk's LightCloud distributed key-value store for Ruby
Ruby
75
star
49

tree-sitter-hcl

A tree-sitter grammar for HCL (HashiCorp Configuration Language), used by projects such as Terraform.
C
69
star
50

go-linereader

Golang package that reads lines from an io.Reader and puts them onto a channel.
Go
66
star
51

veewee-to-packer

A tool for converting Veewee templates into Packer templates.
Ruby
65
star
52

tree-sitter-proto

A tree-sitter grammar for protocol buffer files (proto3).
C
63
star
53

vagrant-rake

A Vagrant plugin to execute `rake` commands from the host in the VM
Ruby
62
star
54

libvirt-rb

[ABANDONED] A ruby client library providing an interface to libvirt via FFI.
Ruby
59
star
55

go-testing-interface

Go (golang) library to expose *testing.T as an interface.
Go
58
star
56

patchstructure

Go library for representing and applying patches to modify existing Go structures
Go
55
star
57

squire

Go
55
star
58

go-libucl

Bindings to libucl from Go (golang).
Go
54
star
59

go-finger

Finger protocol library
Go
54
star
60

go-bnet

Go (golang) client for the Battle.net API
Go
52
star
61

libssh2-ruby

libssh2 bindings for Ruby
Ruby
47
star
62

iochan

A Go library for turning `io.Reader` into channels.
Go
43
star
63

prefixedio

Golang library that demultiplexes line-oriented data from an io.Reader into multiple io.Readers based on a prefix.
Go
42
star
64

flask-nix-example

Dockerfile
36
star
65

tlaplus-radix-tree

TLA+ modules, specifications, and models for Radix trees.
TLA
33
star
66

caststructure

A Go library that provides functions for downcasting types, composing values dynamically, and more.
Go
32
star
67

virtuoso

Dead simple virtual machine management over many hypervisors.
Ruby
30
star
68

hash_ring

Consistent hashing in Ruby. Ported from Amir Sailhefendic's hash_ring python library.
Ruby
28
star
69

terraform-aws-dynamic-keys

Terraform module that dynamically generates a public/private keypair.
HCL
26
star
70

go-spdx

Golang library for listing and looking up licenses using SPDX IDs.
Go
23
star
71

ruburple

A ruby interface to libpurple. Copied for git.
C
20
star
72

iorpc

Golang io interfaces across an RPC connection.
Go
18
star
73

fusion-m1-514-repro

Makefile
17
star
74

zig-build-macos-sdk

macOS SDK package for Zig build.
C
15
star
75

omniconfig

Flexible configuration for your Ruby applications and libraries.
Ruby
14
star
76

zig-libuv

Zig bindings for libuv. Also a build script to build libuv from scratch using only Zig (for easy cross-compilation, integration with Zig, etc.).
Zig
13
star
77

terraform-aws-fastai

Terraform module to create Fast.ai course instance.
HCL
12
star
78

radar

Easily report errors in your libraries and applications any way you want!
Ruby
12
star
79

zig-build-libxml2

The libxml2 library built and packaged for the Zig build system. These are not Zig language bindings to the library.
C
11
star
80

tiad-demo

Demo for The Incredible Automation Day in Paris.
Shell
10
star
81

waypoint-helm

WIP
Smarty
9
star
82

boto-route53

Route53 API built on top of Boto
Python
8
star
83

fogli

An efficient, simple, and intuitive Facebook Open Graph library
Ruby
8
star
84

minitest-mark

Proof of concept minitest extension to add test marking.
Ruby
7
star
85

vagrant-downloads

The Vagrant downloads website.
Ruby
7
star
86

minitest-parallel

Proof of concept to run your minitest tests in parallel.
Ruby
6
star
87

goconf

This is a copy of http://code.google.com/p/goconf/
Go
6
star
88

packer-go-bootcamp

Packer templates for the Go Bootcamp images.
Shell
6
star
89

larubyconf-vagrant-examples

Examples of using Vagrant from LARubyConf
Ruby
6
star
90

xidl

Parses XIDL files into Ruby objects.
Ruby
5
star
91

bintray-download-site

Simple Rack app for creating easy downloads for your Bintray packages.
Ruby
5
star
92

terraform-aws-vpc

Temporary, testing something, ignore this.
HCL
5
star
93

minitest-speed

Proof of concept speed tests using minitest.
Ruby
5
star
94

zig-build-xcode-frameworks

Exposing hexops/xcode-frameworks to the Zig package manager to work around some bugs.
Zig
5
star
95

homebrew-gon

Homebrew Tap for Gon (github.com/mitchellh/gon)
Ruby
4
star
96

osext

Copy of https://bitbucket.org/kardianos/osext
Go
4
star
97

minitest-funcarg

Proof of concept showing funcargs (style of DI) in minitest.
Ruby
4
star
98

lifeguard-random

Data source plugin for Lifeguard that generates random numbers.
Shell
4
star
99

go-bootcamp-remotecmds

My solution for the remotecmds problem for the Go Bootcamp I'm helping to instruct.
Go
4
star
100

lifeguard-graphite

Data source plugin for Lifeguard to query data from Graphite.
Shell
4
star