https://github.com/state-machines/libstatemachines
A freestanding, dependency-free finite state machine runtime in C11.
https://github.com/state-machines/libstatemachines
c c11 embedded finite-state-machine freestanding fsm hsm kernel state-machine zero-allocation
Last synced: 9 days ago
JSON representation
A freestanding, dependency-free finite state machine runtime in C11.
- Host: GitHub
- URL: https://github.com/state-machines/libstatemachines
- Owner: state-machines
- License: bsd-2-clause
- Created: 2026-05-10T09:30:47.000Z (2 months ago)
- Default Branch: master
- Last Pushed: 2026-06-22T18:40:03.000Z (29 days ago)
- Last Synced: 2026-06-22T20:12:33.381Z (29 days ago)
- Topics: c, c11, embedded, finite-state-machine, freestanding, fsm, hsm, kernel, state-machine, zero-allocation
- Language: C
- Size: 37.1 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# libstatemachines
A freestanding, dependency-free finite state machine runtime in C11.
Schemas are plain data: you describe states, events, guards, and actions as
static tables, hand them to the runtime, and dispatch events. The library does
no allocation and pulls in nothing beyond the standard C headers.
## Features
- **Zero dependencies, zero allocation.** No libc requirement beyond freestanding
headers; all storage is caller-provided.
- **Flat and hierarchical machines.** Nested states with `initial_child` descent
and ancestor-aware matching (`state_machine_is_in`).
- **Deterministic selection.** Transitions are evaluated in declaration order;
guards short-circuit; the first match wins.
- **Rich dispatch diagnostics.** `state_machine_dispatch_ex` reports the outcome,
the transition taken, which guard failed, and how many transitions were tested.
- **Schema validation.** `state_machine_init` fully validates a schema before use
and fails closed (`EINVAL`) on malformed input.
- **Frozen ABI.** Struct layouts are pinned with static assertions on LP64/LLP64
targets; `state_machine_abi_version()` exposes the runtime ABI at load time.
- **Portable C11.** Standard headers only (``, ``,
``, ``); no platform-specific dependencies.
## Build
```sh
make # build/libstate_machine.a
make test # build + run smoke tests, conformance corpus, and example
make example # build + run the reference consumer
make clean
```
Override the toolchain as usual:
```sh
make CC=clang
```
The library builds under `-std=c11 -Wall -Wextra -Wpedantic -Werror` with
`-Wconversion` and `-Wshadow` enabled.
## Usage
```c
#include "state_machine.h"
/* Describe the machine as static data (see examples/ for a full schema). */
extern const state_machine_def_t my_def;
int main(void)
{
state_machine_t m = STATE_MACHINE_INITIALIZER;
if (state_machine_init(&m, &my_def, /*userdata=*/NULL) != 0)
return 1;
state_machine_result_t r;
state_machine_dispatch_ex(&m, EV_START, /*payload=*/NULL, &r);
if (r.outcome == STATE_MACHINE_OUTCOME_ACCEPTED)
printf("now in: %s\n", state_machine_state_name(&my_def, r.to));
else
printf("rejected: %s\n", state_machine_outcome_name(r.outcome));
state_machine_destroy(&m);
return 0;
}
```
Dispatch outcomes:
| Outcome | Meaning |
| --- | --- |
| `ACCEPTED` | A transition fired; state changed (or self-transitioned). |
| `INVALID_ARG` | Null/invalid arguments; the instance is untouched. |
| `NO_TRANSITION` | No transition matched the event in the current state. |
| `GUARD_FAILED` | A transition matched but every candidate guard returned false. |
| `REENTRY` | Dispatch was called re-entrantly on the same instance. |
A worked example - a circuit breaker built on top of the runtime - lives in
[`examples/circuit_breaker`](examples/circuit_breaker).
## Testing
`make test` runs the smoke suite (flat machines, hierarchical machines, action
dispatch, and invalid-schema rejection), the JSON-driven conformance corpus
under `test/conformance/`, and the reference example. CI runs the same against
both GCC and Clang.
## License
BSD-2-Clause. See [LICENSE](LICENSE).