You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Spawning and Managing Child Processes with `lws_spawn`
2
+
3
+
The `lws_spawn` API provides a robust, platform-agnostic way to create and manage child processes directly from your C application, fully integrated with the libwebsockets event loop.
4
+
5
+
## Overview
6
+
7
+
The `lws_spawn` API is designed to securely run external executables as child processes. Its key features include:
8
+
9
+
***Event-Loop Integration**: The child process lifecycle is managed without blocking the main lws event loop.
10
+
***Standard I/O Redirection**: The child's `stdin`, `stdout`, and `stderr` are automatically redirected to pipes. These pipes are represented as standard `struct lws` connection instances (`wsi`), allowing you to interact with the child process using familiar lws protocol callbacks.
11
+
***Automatic Lifecycle Management**: Lws handles waiting for and "reaping" the terminated child process, providing a callback with its exit status and resource accounting information.
12
+
***Security**: Provides options for setting a `chroot()` jail and the working directory for the child process.
13
+
***Timeout Management**: An optional timeout can be specified to automatically kill a child process that runs for too long.
14
+
***Linux Cgroup Containment**: On Linux, spawned processes can be automatically placed into a new, dedicated cgroup for resource control and isolation. The cgroup is automatically removed when the process is reaped.
15
+
16
+
## Core API Usage
17
+
18
+
The primary entrypoint for this API is `lws_spawn_piped()`. It takes a single argument: a pointer to a `struct lws_spawn_piped_info` which you populate to describe the child process you want to create.
19
+
20
+
Key members of `struct lws_spawn_piped_info`:
21
+
22
+
-`exec_array`: A `NULL`-terminated array of strings for the executable path and its arguments (equivalent to `argv`).
23
+
-`env_array`: A `NULL`-terminated array of strings for the child's environment variables (e.g., `{"VAR1=VALUE1", "VAR2=VALUE2", NULL}`).
24
+
-`vh`: The `lws_vhost` the new stdio `wsi` should be associated with.
25
+
-`protocol_name`: The name of the lws protocol that will handle events for the stdio `wsi`. This is **mandatory** for proper cleanup.
26
+
-`reap_cb`: A **mandatory** callback function of type `lsp_cb_t` that lws will call after the child process has terminated and been reaped.
27
+
-`opaque`: A user pointer that will be passed to your `reap_cb` and will also be available on the stdio `wsi` via `lws_get_opaque_user_data()`.
28
+
-`timeout_us`: Optional timeout in microseconds. If the process runs longer than this, it will be sent a `SIGTERM`.
29
+
30
+
### Lifecycle and Cleanup
31
+
32
+
Proper cleanup is essential. When the child process exits, its stdio pipes are closed by the operating system. This generates a `LWS_CALLBACK_RAW_FILE_CLOSE` event on each of the three stdio `wsi`.
33
+
34
+
Your protocol handler **must** implement a case for this reason and call `lws_spawn_stdwsi_closed()`:
When lws has been notified that all three stdio `wsi` have closed, it will proceed to reap the child process and invoke your `reap_cb`.
54
+
55
+
## Linux Cgroup Support
56
+
57
+
On Linux, `lws_spawn` can automatically create a transient cgroup v2 for each spawned process, providing resource isolation. The cgroup is automatically removed when the process is reaped.
58
+
59
+
### Permissions and One-Time Setup
60
+
61
+
By default, creating new cgroups in `/sys/fs/cgroup/` requires `root` privileges. A non-root user will get a "Permission Denied" error.
62
+
63
+
The recommended solution is to have an administrator (or a CI setup script) perform a **one-time setup** to delegate control of a subdirectory to the user running the lws application:
64
+
65
+
```sh
66
+
# Run these commands as root once
67
+
sudo mkdir -p /sys/fs/cgroup/lws
68
+
sudo chown myuser:mygroup /sys/fs/cgroup/lws
69
+
echo "+cpu +memory +pids +io" | sudo tee /sys/fs/cgroup/lws/cgroup.subtree_control
70
+
```
71
+
72
+
For applications that start as `root` and then drop privileges, lws provides a helper function to perform this setup programmatically: `int lws_spawn_cgroup_admin_init(const char *toplevel_name, const char *owner_or_NULL, const char *group_or_NULL);`. Call this function once at startup while your process still has root privileges. The cgroup directory will take on the ownership and group given in the args, NULL means to skip the change. If `toplevel_name` is NULL, it defaults to the builtin one "lws" as the toplevel token. It returns success (0) if the toplevel entry already existed as well as if successfully created.
73
+
74
+
Typically it will called by a daemon during init while it is still root, and configured to prepare the cgroup dir ownership for the less-privileged user / group it subsequently runs under.
75
+
76
+
### API Usage
77
+
78
+
To enable cgroup containment for a spawned process, set the following members in your `struct lws_spawn_piped_info`:
79
+
80
+
-`cgroup_name_suffix`: A string that will be used to name the cgroup directory. For example, a suffix of `"lws/my-task"` will create a cgroup at `/sys/fs/cgroup/lws/my-task`. This must be unique for concurrent spawns.
81
+
82
+
-`p_cgroup_ret`: An optional pointer to an `int`. If provided, lws will write `0` to this integer on successful cgroup creation, and `1` on failure.
83
+
84
+
If cgroup creation fails (e.g., due to permissions), `lws_spawn_piped()` will **not** fail. It will log a warning and proceed to spawn the process without cgroup containment. Use `p_cgroup_ret` to confirm the outcome.
85
+
86
+
## Example
87
+
88
+
For a complete, working example that demonstrates these concepts, including cgroup setup and verification, please refer to the API test located at:
0 commit comments