Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ zwasm_module_invoke(mod, "f", NULL, 0, results, 1);
zwasm_module_delete(mod);
```

For configured execution limits and behavior, use `zwasm_config_t`:

- `zwasm_config_set_fuel`, `zwasm_config_set_timeout`, `zwasm_config_set_max_memory`
- `zwasm_config_set_force_interpreter`
- `zwasm_config_set_cancellable` (default: `true`)

When fuel is configured, it applies to module startup (`start`/`_start`) as well as
subsequent invocations. Fuel consumed during startup reduces the remaining budget.

See the [C API chapter](https://clojurewasm.github.io/zwasm/en/c-api.html) in the book for the full API reference.

## Examples
Expand Down
40 changes: 33 additions & 7 deletions book/en/src/c-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ Functions are grouped by domain. All signatures live in `include/zwasm.h`.
|----------|-------------|
| `zwasm_last_error_message()` | Last error as a null-terminated string. Returns `""` if no error. Thread-local. |

### Runtime configuration

| Function | Description |
|----------|-------------|
| `zwasm_config_new()` | Create a runtime config handle. |
| `zwasm_config_delete(config)` | Free a runtime config handle. |
| `zwasm_config_set_allocator(config, alloc_fn, free_fn, ctx)` | Set custom allocator callbacks for runtime bookkeeping memory. |
| `zwasm_config_set_fuel(config, fuel)` | Set instruction fuel limit. |
| `zwasm_config_set_timeout(config, timeout_ms)` | Set wall-clock timeout in milliseconds. |
| `zwasm_config_set_max_memory(config, max_memory_bytes)` | Set linear-memory growth ceiling in bytes. |
| `zwasm_config_set_force_interpreter(config, force_interpreter)` | Disable RegIR/JIT and force interpreter-only execution. |
| `zwasm_config_set_cancellable(config, enabled)` | Enable/disable periodic JIT cancellation checks. |

### Module lifecycle

| Function | Description |
Expand All @@ -160,6 +173,8 @@ Functions are grouped by domain. All signatures live in `include/zwasm.h`.
| `zwasm_module_new_wasi(wasm_ptr, len)` | Create WASI module with default capabilities. |
| `zwasm_module_new_wasi_configured(wasm_ptr, len, config)` | Create WASI module with custom config. |
| `zwasm_module_new_with_imports(wasm_ptr, len, imports)` | Create module with host function imports. |
| `zwasm_module_new_configured(wasm_ptr, len, config)` | Create module with optional runtime config. |
| `zwasm_module_new_wasi_configured2(wasm_ptr, len, wasi_config, config)` | Create WASI module with both WASI config and runtime config. |
| `zwasm_module_delete(module)` | Free all module resources. |
| `zwasm_module_validate(wasm_ptr, len)` | Validate binary without instantiation. |

Expand All @@ -169,6 +184,7 @@ Functions are grouped by domain. All signatures live in `include/zwasm.h`.
|----------|-------------|
| `zwasm_module_invoke(module, name, args, nargs, results, nresults)` | Invoke an exported function by name. |
| `zwasm_module_invoke_start(module)` | Invoke `_start` (WASI entry point). |
| `zwasm_module_cancel(module)` | Request cancellation of a currently running invocation (thread-safe). |

### Export introspection

Expand Down Expand Up @@ -273,26 +289,35 @@ The `env` pointer lets you pass arbitrary context (a struct, file handle, etc.)

## WASI programs

Use the config builder pattern to run WASI programs with custom settings:
Use a `zwasm_wasi_config_t` for argv/env/preopens, and optionally combine it with `zwasm_config_t` for fuel/timeout/memory limits:

```c
/* Create and configure WASI */
zwasm_wasi_config_t *config = zwasm_wasi_config_new();
zwasm_wasi_config_t *wasi_config = zwasm_wasi_config_new();

const char *argv[] = {"myapp", "--verbose"};
zwasm_wasi_config_set_argv(config, 2, argv);
zwasm_wasi_config_set_argv(wasi_config, 2, argv);

zwasm_wasi_config_preopen_dir(wasi_config, "/tmp/data", 9, "/data", 5);

zwasm_wasi_config_preopen_dir(config, "/tmp/data", 9, "/data", 5);
/* Optional runtime config */
zwasm_config_t *config = zwasm_config_new();
zwasm_config_set_fuel(config, 1000000);
zwasm_config_set_timeout(config, 1000);
zwasm_config_set_max_memory(config, 256 * 1024 * 1024);

/* Create module with WASI config */
zwasm_module_t *mod = zwasm_module_new_wasi_configured(wasm_bytes, wasm_len, config);
/* Create module with both configs */
zwasm_module_t *mod = zwasm_module_new_wasi_configured2(
wasm_bytes, wasm_len, wasi_config, config
);

/* Run the program */
zwasm_module_invoke_start(mod);

/* Cleanup */
zwasm_module_delete(mod);
zwasm_wasi_config_delete(config);
zwasm_config_delete(config);
zwasm_wasi_config_delete(wasi_config);
```

For simple WASI programs that only need default capabilities (stdio, clock, random):
Expand All @@ -307,6 +332,7 @@ zwasm_module_delete(mod);

- **Error buffer**: `zwasm_last_error_message()` returns a thread-local buffer. Safe to call from multiple threads.
- **Modules**: A `zwasm_module_t` is **not** thread-safe. Do not invoke functions on the same module from multiple threads concurrently. Create separate module instances per thread instead.
- **Cancellation**: `zwasm_module_cancel()` is the only thread-safe operation and may be called from another thread to interrupt a running invocation.

## Next steps

Expand Down
35 changes: 30 additions & 5 deletions book/en/src/embedding-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,40 @@ for (import_infos) |info| {
}
```

## Resource limits

Control resource usage:
## Resource limits and Config options

In Zig, resource and execution options are grouped in `WasmModule.Config` and passed to `loadWithOptions`.
This allows you to control:

- **fuel**: Instruction count limit (prevents infinite loops)
- **timeout_ms**: Wall-clock timeout (milliseconds)
- **max_memory_bytes**: Maximum linear memory size
- **force_interpreter**: Disable JIT, always use interpreter

Example (Zig):

```zig
// Fuel limit: traps after N instructions
const mod = try WasmModule.loadWithFuel(allocator, wasm_bytes, 1_000_000);
const zwasm = @import("zwasm");
const Config = zwasm.WasmModule.Config;

// Memory limit: via WASI options or direct Vm access
var config = Config{
.fuel = 1_000_000, // Trap after 1M instructions
.timeout_ms = 1000, // 1 second wall-clock timeout
.max_memory_bytes = 16 * 1024 * 1024, // 16MB
.force_interpreter = false,
};
const mod = try WasmModule.loadWithOptions(allocator, wasm_bytes, config);
```

**fuel**: If set, the module will trap with `error.FuelExhausted` after the specified number of instructions. Use this for untrusted or potentially infinite-looping code.

**cancellation**: `mod.cancel()` can be called from another thread to interrupt an in-progress invocation.

**timeout_ms**: If set, execution will be interrupted after the given wall-clock time.

All options are optional; defaults are safe for most use cases. See the C API section for equivalent `zwasm_config_t` usage.

## Error handling

All loading and execution methods return error unions. Key error types:
Expand All @@ -170,6 +193,8 @@ All loading and execution methods return error unions. Key error types:
- **`error.OutOfBoundsMemoryAccess`** — Memory access out of bounds
- **`error.OutOfMemory`** — Allocator failed
- **`error.FuelExhausted`** — Instruction fuel limit hit
- **`error.Canceled`** — Execution canceled by host via `cancel()`
- **`error.TimeoutExceeded`** — Execution interrupted by wall-clock timeout

See [Error Reference](../docs/errors.md) for the complete list.

Expand Down
40 changes: 33 additions & 7 deletions book/ja/src/c-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ cd examples/rust && cargo run
|------|------|
| `zwasm_last_error_message()` | 最後のエラーを null 終端文字列で返す。エラーなしの場合は `""` を返す。スレッドローカル。 |

### ランタイム設定

| 関数 | 説明 |
|------|------|
| `zwasm_config_new()` | ランタイム設定ハンドルを作成。 |
| `zwasm_config_delete(config)` | ランタイム設定ハンドルを解放。 |
| `zwasm_config_set_allocator(config, alloc_fn, free_fn, ctx)` | ランタイム内部管理メモリ向けのカスタムアロケータを設定。 |
| `zwasm_config_set_fuel(config, fuel)` | 命令fuel上限を設定。 |
| `zwasm_config_set_timeout(config, timeout_ms)` | 実時間タイムアウト(ミリ秒)を設定。 |
| `zwasm_config_set_max_memory(config, max_memory_bytes)` | 線形メモリ `memory.grow` の上限(バイト)を設定。 |
| `zwasm_config_set_force_interpreter(config, force_interpreter)` | RegIR/JITを無効化し、インタプリタ実行を強制。 |
| `zwasm_config_set_cancellable(config, enabled)` | JIT実行中のキャンセルチェック有効/無効を設定。 |

### モジュールのライフサイクル

| 関数 | 説明 |
Expand All @@ -160,6 +173,8 @@ cd examples/rust && cargo run
| `zwasm_module_new_wasi(wasm_ptr, len)` | デフォルトケーパビリティで WASI モジュールを作成。 |
| `zwasm_module_new_wasi_configured(wasm_ptr, len, config)` | カスタム設定で WASI モジュールを作成。 |
| `zwasm_module_new_with_imports(wasm_ptr, len, imports)` | ホスト関数インポート付きでモジュールを作成。 |
| `zwasm_module_new_configured(wasm_ptr, len, config)` | ランタイム設定付きでモジュールを作成。 |
| `zwasm_module_new_wasi_configured2(wasm_ptr, len, wasi_config, config)` | WASI設定とランタイム設定の両方を指定してモジュールを作成。 |
| `zwasm_module_delete(module)` | モジュールの全リソースを解放。 |
| `zwasm_module_validate(wasm_ptr, len)` | インスタンス化せずにバイナリを検証。 |

Expand All @@ -169,6 +184,7 @@ cd examples/rust && cargo run
|------|------|
| `zwasm_module_invoke(module, name, args, nargs, results, nresults)` | エクスポート関数を名前で呼び出す。 |
| `zwasm_module_invoke_start(module)` | `_start`(WASI エントリポイント)を呼び出す。 |
| `zwasm_module_cancel(module)` | 実行中呼び出しのキャンセルを要求(スレッドセーフ)。 |

### エクスポートの検査

Expand Down Expand Up @@ -273,26 +289,35 @@ int main(void) {

## WASI プログラム

設定ビルダーパターンを使用して、カスタム設定で WASI プログラムを実行できます:
`zwasm_wasi_config_t` で argv/env/preopen を設定し、必要に応じて `zwasm_config_t` で fuel/timeout/メモリ上限を併用できます:

```c
/* WASI の設定 */
zwasm_wasi_config_t *config = zwasm_wasi_config_new();
zwasm_wasi_config_t *wasi_config = zwasm_wasi_config_new();

const char *argv[] = {"myapp", "--verbose"};
zwasm_wasi_config_set_argv(config, 2, argv);
zwasm_wasi_config_set_argv(wasi_config, 2, argv);

zwasm_wasi_config_preopen_dir(wasi_config, "/tmp/data", 9, "/data", 5);

zwasm_wasi_config_preopen_dir(config, "/tmp/data", 9, "/data", 5);
/* 任意: ランタイム設定 */
zwasm_config_t *config = zwasm_config_new();
zwasm_config_set_fuel(config, 1000000);
zwasm_config_set_timeout(config, 1000);
zwasm_config_set_max_memory(config, 256 * 1024 * 1024);

/* WASI 設定付きでモジュールを作成 */
zwasm_module_t *mod = zwasm_module_new_wasi_configured(wasm_bytes, wasm_len, config);
/* WASI設定 + ランタイム設定でモジュールを作成 */
zwasm_module_t *mod = zwasm_module_new_wasi_configured2(
wasm_bytes, wasm_len, wasi_config, config
);

/* プログラムを実行 */
zwasm_module_invoke_start(mod);

/* クリーンアップ */
zwasm_module_delete(mod);
zwasm_wasi_config_delete(config);
zwasm_config_delete(config);
zwasm_wasi_config_delete(wasi_config);
```

デフォルトケーパビリティ (stdio, clock, random) のみの単純な WASI プログラムの場合:
Expand All @@ -307,6 +332,7 @@ zwasm_module_delete(mod);

- **エラーバッファ**: `zwasm_last_error_message()` はスレッドローカルバッファを返します。複数スレッドからの呼び出しは安全です。
- **モジュール**: `zwasm_module_t` はスレッドセーフ**ではありません**。同一モジュールに対して複数スレッドから同時に関数を呼び出さないでください。スレッドごとに個別のモジュールインスタンスを作成してください。
- **キャンセル**: `zwasm_module_cancel()` は唯一のスレッドセーフな操作であり、他スレッドから実行中の呼び出しを中断できます。

## 次のステップ

Expand Down
34 changes: 29 additions & 5 deletions book/ja/src/embedding-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,39 @@ for (import_infos) |info| {
}
```

## リソース制限

リソース使用量を制御できます:
## リソース制限とConfigオプション

Zigでは、リソース・実行オプションは `WasmModule.Config` にまとまり、`loadWithOptions` で渡します。これにより、以下の制御が可能です:

- **fuel**: 命令数上限(無限ループ防止)
- **timeout_ms**: 実時間タイムアウト(ミリ秒)
- **max_memory_bytes**: 線形メモリ最大サイズ
- **force_interpreter**: JIT無効化(常にインタプリタ)

例(Zig):

```zig
// Fuel limit: traps after N instructions
const mod = try WasmModule.loadWithFuel(allocator, wasm_bytes, 1_000_000);
const zwasm = @import("zwasm");
const Config = zwasm.WasmModule.Config;

// Memory limit: via WASI options or direct Vm access
var config = Config{
.fuel = 1_000_000, // 100万命令でtrap
.timeout_ms = 1000, // 1秒タイムアウト
.max_memory_bytes = 16 * 1024 * 1024, // 16MB
.force_interpreter = false,
};
const mod = try WasmModule.loadWithOptions(allocator, wasm_bytes, config);
```

**fuel**: 設定時、指定命令数で`error.FuelExhausted`としてtrapします。信頼できない/無限ループの可能性があるコードに推奨。

**キャンセル**: 他スレッドから`mod.cancel()`を呼び出すことで、実行中の呼び出しを中断できます。

**timeout_ms**: 設定時、指定実時間経過で自動中断します。

全てのオプションは省略可能で、デフォルトは安全寄りです。C API側では `zwasm_config_t` で同等の設定ができます。

## エラーハンドリング

すべてのロード・実行メソッドはエラーユニオンを返します。主要なエラー型は以下のとおりです:
Expand All @@ -170,6 +192,8 @@ const mod = try WasmModule.loadWithFuel(allocator, wasm_bytes, 1_000_000);
- **`error.OutOfBoundsMemoryAccess`** --- メモリアクセスが範囲外
- **`error.OutOfMemory`** --- アロケータが失敗
- **`error.FuelExhausted`** --- 命令フューエル制限に到達
- **`error.Canceled`** --- ホストから `cancel()` で実行中断
- **`error.TimeoutExceeded`** --- 実時間タイムアウトで中断

完全なリストは [エラーリファレンス](../docs/errors.md) を参照してください。

Expand Down
8 changes: 6 additions & 2 deletions docs/api-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Types and functions listed here are covered by SemVer guarantees.
| `WasmValType` | Enum of Wasm value types (i32, i64, f32, f64, v128, funcref, externref) | v0.1.0 |
| `ExportInfo` | Metadata for an exported function (name, param/result types) | v0.1.0 |
| `ImportEntry` | Maps an import module name to a source | v0.2.0 |
| `WasmModule.Config`| Unified loading configuration | vNEXT |
| `ImportSource` | Union: wasm_module or host_fns | v0.2.0 |
| `HostFnEntry` | A single host function (name, callback, context) | v0.2.0 |
| `HostFn` | Function type: `fn (*anyopaque, usize) anyerror!void` | v0.2.0 |
Expand All @@ -26,15 +27,18 @@ Types and functions listed here are covered by SemVer guarantees.

| Method | Signature | Since |
|--------|-----------|-------|
| `loadWithOptions` | `(Allocator, []const u8, Config) !*WasmModule` | vNEXT |
| `load` | `(Allocator, []const u8) !*WasmModule` | v0.1.0 |
| `loadFromWat` | `(Allocator, []const u8) !*WasmModule` | v0.2.0 |
| `loadWasi` | `(Allocator, []const u8) !*WasmModule` | v0.2.0 |
| `loadWasiWithOptions` | `(Allocator, []const u8, WasiOptions) !*WasmModule` | v0.2.0 |
| `loadWithImports` | `(Allocator, []const u8, []const ImportEntry) !*WasmModule` | v0.2.0 |
| `loadWasiWithImports` | `(Allocator, []const u8, []const ImportEntry, WasiOptions) !*WasmModule` | v0.2.0 |
| `loadWithImports` | `(Allocator, []const u8, ?[]const ImportEntry) !*WasmModule` | v0.2.0 |
| `loadWasiWithImports` | `(Allocator, []const u8, ?[]const ImportEntry, WasiOptions) !*WasmModule` | v0.2.0 |
| `loadWithFuel` | `(Allocator, []const u8, u64) !*WasmModule` | v0.3.0 |
| `deinit` | `(*WasmModule) void` | v0.1.0 |
| `invoke` | `(*WasmModule, []const u8, []u64, []u64) !void` | v0.1.0 |
| `cancel` | `(*WasmModule) void` | vNEXT |
| `invokeInterpreterOnly` | `(*WasmModule, []const u8, []u64, []u64) !void` | vNEXT |
| `memoryRead` | `(*WasmModule, Allocator, u32, u32) ![]const u8` | v0.2.0 |
| `memoryWrite` | `(*WasmModule, u32, []const u8) !void` | v0.2.0 |
| `getExportInfo` | `(*WasmModule, []const u8) ?ExportInfo` | v0.2.0 |
Expand Down
27 changes: 25 additions & 2 deletions docs/embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,29 @@ The custom allocator controls **internal bookkeeping only** (module metadata,
function tables, GC heap, VM state). Wasm linear memory (`memory.grow`) is
separately managed per the Wasm spec.

### Execution Controls (Fuel, Timeout, Cancellation)

`zwasm_config_t` also controls runtime limits and execution behavior:

```c
zwasm_config_t *config = zwasm_config_new();

zwasm_config_set_fuel(config, 1000000);
zwasm_config_set_timeout(config, 5000); // milliseconds
zwasm_config_set_max_memory(config, 64 * 1024 * 1024);
zwasm_config_set_force_interpreter(config, false);

// Default is true. Set false to remove periodic JIT cancel checks
// when you prioritize peak throughput over cancellability.
zwasm_config_set_cancellable(config, true);

zwasm_module_t *mod = zwasm_module_new_configured(wasm_ptr, len, config);
```

Fuel applies to module startup and invocation. If a module has a start function,
it runs under the configured fuel budget, and the remaining fuel is carried into
subsequent invocations.

### WASI + Custom Allocator

```c
Expand Down Expand Up @@ -208,10 +231,10 @@ Key function groups:

| Group | Functions |
|-------|-----------|
| Config | `zwasm_config_new`, `zwasm_config_delete`, `zwasm_config_set_allocator` |
| Config | `zwasm_config_new`, `zwasm_config_delete`, `zwasm_config_set_allocator`, `zwasm_config_set_fuel`, `..._set_timeout`, `..._set_max_memory`, `..._set_force_interpreter`, `..._set_cancellable` |
| Module | `zwasm_module_new`, `zwasm_module_new_configured`, `zwasm_module_delete` |
| WASI | `zwasm_module_new_wasi`, `zwasm_module_new_wasi_configured2` |
| Invoke | `zwasm_module_invoke`, `zwasm_module_invoke_start` |
| Invoke | `zwasm_module_invoke`, `zwasm_module_invoke_start`, `zwasm_module_cancel` |
| Memory | `zwasm_module_memory_data`, `zwasm_module_memory_size`, `_read`, `_write` |
| Exports | `zwasm_module_export_count`, `_name`, `_param_count`, `_result_count` |
| Imports | `zwasm_import_new`, `zwasm_import_add_fn`, `zwasm_import_delete` |
Expand Down
2 changes: 2 additions & 0 deletions docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ The primary runtime error type. Returned from `Vm.invoke()`, `Vm.callFunction()`
| MemoryLimitExceeded | Memory grow exceeded limit |
| TableLimitExceeded | Table grow exceeded limit |
| FuelExhausted | Instruction fuel limit hit |
| Canceled | Execution canceled by host via `cancel()` |
| TimeoutExceeded | Execution interrupted by wall-clock timeout |

### Index errors
| Variant | Meaning |
Expand Down
4 changes: 4 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ zwasm module.wasm --max-memory 67108864 # 64MB ceiling
zwasm module.wasm --fuel 1000000
```

`--fuel` applies to all execution, including module start (`_start`/start function)
and subsequent invoked exports. If startup code consumes fuel, less fuel remains
for later function calls.

### Linking modules

```bash
Expand Down
Loading
Loading