Asynchronous I/O runtime for Lilush, built on epoll. Provides coroutine-based concurrency with timers, UDP/TCP sockets, cancellation tokens, and structured task combinators.
| Name | Signature |
|---|---|
set_logger | set_logger(logger) |
own | own(resource) -> resource |
defer | defer(fn) |
disown | disown(resource) -> resource |
spawn | spawn(fn, opts) -> task |
await | await(task) -> result, err |
sleep | sleep(seconds, cancel) -> true, err |
cancel_token | cancel_token() -> token |
race | race(fns) -> results, err |
all | all(fns) -> results, err |
on_signal | on_signal(signum, handler) -> true, err |
stop | stop() |
udp | udp() -> socket, err |
tls_identity | tls_identity(cert_path, key_path, hostname) -> identity, err |
tcp | tcp() -> socket, err |
connect | connect(addr, port, opts) -> socket, err |
listen | listen(addr, port, opts) -> listener, err |
exec | exec(path, args, opts) -> proc, err |
task_name | task_name(name) -> name |
stats | stats() -> stats |
task_tree | task_tree() -> tasks |
task_dump | task_dump() -> tasks |
enable_dump_signal | enable_dump_signal(format) |
run | run(fn) -> result, err |
set_logger(
logger)
Inject a structured logger for LEV error reporting
Sets a std.logger instance to receive LEV error messages (cleanup
errors, detached task errors). The logger persists across run() calls.
Pass nil to revert to stderr.
own(
resource) ->resource
Register a resource for auto-close when the current task completes
Registers resource for automatic cleanup when the current coroutine
finishes (success or error). The resource must have a close() method.
Returns the resource for chaining: local sock = lev.own(lev.connect(...)).
No-op outside lev.run() or from non-spawned coroutines.
defer(
fn)
Register an arbitrary cleanup function for the current task
Registers fn to run when the current coroutine finishes (success or
error). Cleanups run in LIFO order, like Go's defer. Errors in cleanup
functions are logged via log_error and don't prevent other cleanups from running.
No-op outside lev.run() or from non-spawned coroutines.
disown(
resource) ->resource
Remove a resource from auto-close tracking
Removes resource from the current task's cleanup list (identity
comparison). Use for ownership transfer between coroutines. Returns
the resource for chaining. No-op if the resource is not tracked.
spawn(
fn,opts) ->task
Spawn a new concurrent task
Spawns fn as a new coroutine that runs concurrently within the
current lev.run() event loop. Returns a task handle that can be
passed to await().
Options:
detached (boolean): If true, errors are logged when the task
completes and the task is typically not awaited.
await(
task) ->result,err
Wait for a spawned task to complete
Yields the current coroutine until the given task finishes. Returns
the task's return values on success, or nil, err on error.
sleep(
seconds,cancel) ->true,err
Suspend the current coroutine for a duration
Yields the current coroutine and resumes it after the given number
of seconds (fractional seconds supported). Returns true on
normal completion, or nil, "cancelled" if a cancel token fires
before the timer expires.
cancel_token() ->
token
Create a cancellation token
Returns a cancel token that can be passed to sleep(), connect(),
accept(), and other blocking operations to enable cooperative
cancellation. Call token:cancel() to interrupt all registered waiters.
race(
fns) ->results,err
Run functions concurrently, return first result
Spawns each function in the list. When the first one finishes (success or error), cancels the rest and returns that result. Each function receives a cancel token as its first argument.
all(
fns) ->results,err
Run functions concurrently, wait for all to complete
Spawns each function and waits for all to complete. Returns a list
of result tables (each {values...}). If any task errors, cancels
the rest and returns nil, err immediately.
on_signal(
signum,handler) ->true,err
Register a signal handler
Registers a callback to be invoked when the specified signal is
delivered. Must be called within lev.run(). The handler receives
the signal number as its argument.
stop()
Force-stop the event loop
Sets the loop's running flag to false, causing lev.run() to exit
on the next iteration regardless of active coroutines. Intended for
use in signal handlers to implement graceful shutdown with a deadline.
Must be called within lev.run().
udp() ->
socket,err
Create a non-blocking UDP socket
Returns a wrapped UDP socket that integrates with the event loop.
The recvfrom method yields the current coroutine until data
arrives, with optional timeout and cancellation support.
tls_identity(
cert_path,key_path,hostname) ->identity,err
Parse a cert+key PEM pair into a reusable TLS identity
Parses the PEM certificate chain and private key from files into
a Lua userdata that can be passed to starttls() via the identity
config field. The identity is parsed once and reused across connections,
avoiding per-connection file I/O and PEM parsing overhead.
The optional hostname is stored for SNI matching.
tcp() ->
socket,err
Create a non-blocking TCP socket
Returns a wrapped TCP socket that integrates with the event loop.
Provides send, recv, recv_exactly, recv_until methods
with async I/O via wait_readable/wait_writable. Supports TLS
upgrade via starttls.
connect(
addr,port,opts) ->socket,err
Connect to a remote TCP server
Creates a TCP socket, connects to addr:port, and optionally
performs a TLS handshake. Returns a wrapped TCP socket on success.
Options:
timeout (number): connection timeout in seconds
tls (table): if present, perform TLS after connecting (passed to starttls)
cancel (token): cancel token; propagated to TLS handshake if tls.cancel is not set
listen(
addr,port,opts) ->listener,err
Create a bound listening TCP socket
Creates and binds a TCP listener socket. Returns a listener object
with an accept method that yields until a client connects.
accept takes a timeout (number) or an options table
{ timeout = N, cancel = token }.
Options:
reuseport (boolean): enable SO_REUSEPORT
backlog (number): listen backlog (default 128)
exec(
path,args,opts) ->proc,err
Execute an external command asynchronously
Spawns an external command as a child process with non-blocking pipe I/O
and pidfd-based exit notification. Returns a process handle with async
send, recv, recv_stderr, read_all, wait, and kill methods.
Options:
cwd (string): working directory for child
env (table): array of "KEY=VALUE" strings, replaces child environment
stderr_to_stdout (boolean): merge stderr into stdout stream
task_name(
name) ->name
Set or get the current task's name
With an argument, sets the name of the current task and returns it.
Without an argument, returns the current task's name (or nil).
No-op outside lev.run().
stats() ->
stats
Get fast loop stats snapshot
Returns a table with loop counters: active_coros, registered_fds,
timer_count, ready_count (from C core), and task_count (Lua-side
count of entries in the task registry). Returns nil outside lev.run().
task_tree() ->
tasks
Get structured task list
Returns a sorted array of task info tables, each with fields:
id, name, status, detached, parent_id, co_status.
Sorted by id for stable output. Returns nil outside lev.run().
task_dump() ->
tasks
Get detailed task dump with tracebacks
Like task_tree() but adds a traceback field for suspended coroutines,
showing the exact yield point. Has meaningful overhead -- use for debugging,
not monitoring. Returns nil outside lev.run().
enable_dump_signal(
format)
Enable SIGUSR1 task dump handler
Registers a SIGUSR1 handler that calls task_dump() and outputs the
result. Supports "text" (default) and "json" formats. Uses the
injected logger if set, otherwise stderr. Safe because signal handlers
in LEV run via signalfd dispatch (not async-signal context).
run(
fn) ->result,err
Run the event loop with a main function
Creates an event loop, spawns fn as the main coroutine, and runs
the loop until all tasks complete. Returns the main task's results
or nil, err if the main task errored.
Nested lev.run() calls are not allowed.