Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
Serene Runtime

The Serene runtime is a static library linked into code produced by a Serene compiler. It provides the runtime facilities that a program needs, such as the in-memory object model (values, symbols, namespaces), the persistent data structures, the cooperative fiber scheduler, a memory manager, the FFI subsystem, and a JIT engine among other things.

While the runtime is meant to be used with Serene, nothing stops you from using it with other compilers or even generic programs (for example, I used the runtime with my wayland compositor).

How to build the runtime

The runtime builds with Meson and a C23 compiler (Clang or GCC). A Nix flake pins every dependency, so the easiest path is:

nix build '.#runtime' # To build the stand alone runtime
# or
nix develop ./runtime # drops you into a shell with the toolchain + deps
meson setup build runtime
meson compile -C build

Without Nix you need, a C23 toolchain with the following dependencies:

  • pthreads (on Posix)
  • LLVM 20 (if you DO NOT want the standalone build)

Serene build vs Standalone build

The with-serene feature (enabled by default) controls the Serene language layer: the value model, ABI, namespaces and keywords, and the JIT (and with it the LLVM dependency).

# full runtime (default): generic layer + Serene layer + LLVM
meson setup build runtime
# substrate only: memory manager, fibers, data structures. No value model, no LLVM.
meson setup build runtime -Dwith-serene=disabled

Install

meson setup build runtime --prefix=/usr/local # add -Dwith-serene=disabled for generic layer only
meson install -C build # sudo for a system prefix

This installs the static library, the public headers under $prefix/include/serene/, and a serene.runtime.pc pkg-config file.

Using the runtime in your project

Find the runtime through pkg-config. The serene.runtime.pc file carries the include path, the transitive libraries, and the right -DSRN_WITH_SERENE define so your code sees the same struct layout the library was built with. The public headers use C23 attributes, so compile your code as C23.

A minimal program that runs one fiber (works against a substrate-only build):

#include <stdio.h>
#include <serene/runtime.h>
static int ok; // a fiber result must be non-null
static srn_fiber_result_t say_hello(srn_context_t *ctx, void *arg) {
(void)ctx;
(void)arg;
printf("hello from a fiber\n");
return &ok;
}
int main(void) {
srn_scheduler_t *sched = engine->scheduler;
(void)srn_fiber_make(ctx, sched, say_hello, NULL, 0);
srn_sched_run(sched, 1);
srn_engine_shutdown(engine); // tears down the scheduler before the context
}
static int ok
Definition 01_hello.c:36
static srn_fiber_result_t say_hello(srn_context_t *ctx, void *arg)
Definition 01_hello.c:38
int main(void)
Definition 01_hello.c:45
srn_context_t * srn_context_make(srn_engine_t *engine)
Make an empty context, by allocating a new memory block.
Definition context.c:38
int srn_context_release(srn_context_t *ctx)
Definition context.c:63
srn_mm_t * srn_mm_init()
Initialize the memory manager, this function will panic on error.
Definition default.c:294
void srn_mm_shutdown(srn_mm_t *mm)
Shut down the memory manager and release the resources.
Definition default.c:325
srn_engine_t * srn_engine_make(srn_mm_t *mm)
Definition engine.c:92
void srn_engine_shutdown(srn_engine_t *engine)
Definition engine.c:123
srn_fiber_t * srn_fiber_make(srn_context_t *ctx, srn_scheduler_t *sched, srn_fiber_entry_t entry, void *arg, size_t stack_size)
Create a fiber that will run entry(ctx, arg).
Definition fiber.c:169
void * srn_fiber_result_t
Definition fiber.h:117
void srn_sched_run(srn_scheduler_t *sched, int nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:784
Engine is a structure to own the long living and main pieces of the compiler.
Definition engine.h:49
srn_scheduler_t * scheduler
The fiber scheduler, set by srn_sched_init.
Definition engine.h:67
Main memory manager structure that will own all the allocated blocks and data.
Definition interface.h:112

Build it with whatever compiler you use:

cc -std=c23 $(pkg-config --cflags serene.runtime) hello.c \
$(pkg-config --libs serene.runtime) -o hello

Ready-to-copy templates for Make, Meson, and CMake live in examples/usage/, and runnable fiber demos in examples/fibers/ (configure the runtime with -Dwith-examples=enabled to build them).

License

The runtime library — the sources compiled into libserene.runtime and the public headers under serene/ — is licensed under the GNU LGPL v3, so you can link it into programs under other licenses. The runtime's tests, examples, and build tooling, and the rest of the Serene project, are under the GNU GPL v3. Each file states its license in its header; the full texts are in [LICENSE](LICENSE).

Browse the API

  • Functions — a flat, alphabetical index of every runtime function. Most of the API is free functions (srn_*), so this is usually the fastest way in.
  • Data Structures — every struct, union, enum, and typedef.
  • Files — browse by header. Public headers live under serene/rt/; the serene, rt, and jit folders expand to the full tree.

Core object model

Persistent data structures

Concurrency: fibers

  • fiber.h — stackful, cooperative fibers that yield, suspend, or finish (srn_fiber_make, srn_fiber_yield, srn_fiber_suspend).
  • The M:N, work-stealing scheduler lives in rt/fiber/scheduler.c, with the per-OS-thread worker in fiber/thread.h and the context switch under rt/fiber/arch/.

Memory, FFI, and JIT

TODOs

  • Fix the comments to be in markdown
  • Make the compiler warn/errors more strict