Platform Guide

Overview

The engine core is platform-agnostic; everything OS-specific lives behind the Platform* seam. This guide covers the seam, the shared POSIX core that both production targets build on, the two targets themselves, and the checklist for a new port.

The platform seam

Every platform implements the contract in platform/include/platform.h. A conforming port must provide a working body for all of it — there are no optional symbols:

Area Symbols
Wapp lifecycle PlatformWappLoad / Unload / Start / Stop / Loop / GetState
Registry backend PlatformRegistryRead / Write / Remove / WappLoad
Filesystem PlatformOpenStateDir, PlatformFsRename, PlatformFsMkdir
Network PlatformNetOpen / Connect / Recv / Send / Accept / Shutdown / Close / Free
Clock PlatformClockGetRes / GetTime / NanoSleep
Memory PlatformMemoryStats
Concurrency PlatformMutexNew / Lock / Unlock / Free
Power / process PlatformSetProcessArgs, PlatformRequestShutdown, PlatformRequestReboot

The invariants every platform must honour: a wapp runs on its own thread; PlatformWappStop must interrupt a wapp that is blocked in a host syscall (not merely set a flag and wait); PlatformWappLoop blocks until an explicit shutdown/reboot request and respawns a supervisor that exits on its own; memory stats report heap usage; the registry resolves a wapp image by name.

All targets build inside the standardized container — the host only needs a container runtime. make help lists the targets; append RUNNER=docker to use Docker.

Shared POSIX core

Linux and the NuttX simulator are both POSIX environments, so most of the seam has one implementation they both compile in: platform/posix/. It carries the generic, syscall-backed bodies:

Source Provides
posix/socket.c PlatformNet* — the BSD socket calls (open, connect, recv, send, accept, shutdown, close)
posix/mutex.c PlatformMutex*
posix/clock.c PlatformClockGetRes / GetTime
posix/fs.c PlatformOpenStateDir, PlatformFsRename, PlatformFsMkdir
posix/registry-store.c the filesystem registry store behind PlatformRegistry*
posix/wapps-image.c image load/unload behind PlatformWappLoad / Unload

A target layer (platform/linux/, platform/nuttx/) links those sources and implements only what genuinely differs between the two:

Concern Linux NuttX
Threads + stop pthreads; async pthread_cancel tasks; cooperative SIGUSR2 + WAMR terminate flag
Sleep (PlatformNanoSleep) api/clock-sleep.c api/clock-sleep.c (signal-EINTR quirk)
Secure sockets OpenSSL (api/ssocket.c) none yet
Memory stats mallinfo2 NuttX heap walk
Registry backend glue host directory (api/registry.c) hostfs (api/registry.c)
Entry point wanted-cli main wanted_sim_main (NuttX init task)

platform/dummy/ is the exception: a unit-test stub that implements the whole seam in memory and shares none of the POSIX sources — the model for a target that is not POSIX at all.

Linux

The primary target.

1make build        # engine + CLI with the production sheriff supervisor
2make wsh          # engine with the wsh debug supervisor
  • Threads — pthreads.
  • Stop mechanism — pthread_cancel(ASYNCHRONOUS) interrupts a blocked syscall immediately, so a wapp stuck in a host call is reaped promptly.
  • Registry — a host-filesystem directory (./registry/) scanned for <name>:<version>.wapp images.
  • TLS — OpenSSL-backed secure sockets (T/U socket options).
  • Memory stats — mallinfo2.

CMake options of note: WANTED_PLATFORM (the platform layer), WANTED_SUPERVISOR_IMAGE_PATH (compile-time supervisor image), SECURE_SOCKETS (TLS).

NuttX simulator

A first-class, CI-gated target: the full engine running as a NuttX application on the host-stack simulator. The platform/nuttx/ layer is complete — every Platform* symbol has a working body, with no remaining stubs.

1make nuttx-deps      # init the nuttx + nuttx-apps submodules, link the app package
2make nuttx-build     # configure + build the sim from a clean tree
3make nuttx-selftest  # run the in-WASM selftest suite on the sim
4make nuttx-shell     # boot the sim to an interactive wsh prompt
  • Board config — sim:wanted, a native defconfig in the NuttX fork. The engine runs as the NuttX init task via wanted_sim_main, which chdirs to /data (so ./registry resolves against the sim's hostfs) and powers the board off cleanly when wanted_main returns.
  • Console — raw write(1/2) for output.
  • Stop mechanism — cooperative: PlatformWappStop sets the WAMR terminate flag and sends SIGUSR2 to the worker so a wapp blocked in a host call is interrupted and checks the flag on return. A per-worker interrupted flag bridges clock_nanosleep's success-on-signal quirk.
  • Submodules — third_party/nuttx and third_party/nuttx-apps are shallow submodules pinned to the wanted branch of the mekops forks; make nuttx-deps initialises them (idempotent) and must run once before nuttx-build.

Differences from Linux. No TLS yet. The sim:wanted board is built without a network stack (CONFIG_NET off), so socket() fails and /net sockets are unavailable on the sim — socket paths are exercised on Linux only, and the selftest skips its /net socket check on the sim. The cooperative stop cannot pre-empt a bare native call that never checks EINTR, where Linux's async cancel can.

NuttX on real HW (upcoming)

The planned architecture: wapp images loaded from XIP flash, a LittleFS-backed registry slot table, and mbedTLS for secure sockets. The simulator port is the staging ground — hardware reuses the shared POSIX core and most of the NuttX target layer; the flash registry backend and mbedTLS are the remaining hardware-specific pieces.

Porting to a new platform

  1. Create platform/<name>/. If the target is POSIX-like, link platform/posix/ and implement only the deltas (thread/stop model, memory stats, secure sockets if any, registry-backend glue, entry point); otherwise implement every Platform* symbol from platform.h yourself, with platform/dummy/ as the model for a from-scratch port. Either way, no stubs.
  2. Provide a stop mechanism that interrupts a blocked host syscall, not just a cooperative flag.
  3. Implement a registry backend (filesystem, flash blob, or in-memory) behind PlatformRegistry*.
  4. Wire the build (WANTED_PLATFORM=<name>) and a board/app entry point.

The NuttX port is the reference for a constrained target. Its findings carry over: keep wamrData_t opaque and reach it through the WantedWappTerminate accessor; avoid VLAs; avoid scandir and GNU extensions (use opendir/readdir/qsort); confirm CONFIG_INTERPRETERS_WAMR_THREAD_MGR so wasm_runtime_terminate takes effect, and that thread cleanup does not rely on pthread_cleanup_push.

See also

  • Architecture — where the platform seam sits in the system.
  • Testing Guide — the same suites run on Linux and the NuttX sim.