> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boxlite.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Memory, JSON & Threading

> C SDK memory management, JSON utilities, and threading

## Memory Management

### Rules

1. **All allocated strings must be freed**
   * `boxlite_box_id()` -> `boxlite_free_string()`
   * `boxlite_list_info()` -> `boxlite_free_string()`
   * Info/metrics JSON -> `boxlite_free_string()`

2. **Error structs must be freed**
   * `CBoxliteError` -> `boxlite_error_free()`

3. **Results must be freed**
   * `CBoxliteExecResult` -> `boxlite_result_free()`

4. **All cleanup functions are NULL-safe**

### Functions

#### boxlite\_free\_string

Free a string allocated by BoxLite.

```c theme={null}
void boxlite_free_string(char* str);
```

<Note>
  Use this for any string returned by BoxLite API functions such as `boxlite_box_id()`, `boxlite_list_info()`, `boxlite_get_info()`, `boxlite_box_info()`, `boxlite_runtime_metrics()`, and `boxlite_box_metrics()`. Safe to call with NULL.
</Note>

#### boxlite\_error\_free

Free error struct (message only - struct itself is stack-allocated).

```c theme={null}
void boxlite_error_free(CBoxliteError* error);
```

Safe to call with NULL.

#### boxlite\_result\_free

Free an execution result.

```c theme={null}
void boxlite_result_free(CBoxliteExecResult* result);
```

Safe to call with NULL.

#### boxlite\_simple\_free

Free a simple box (auto-stops and removes).

```c theme={null}
void boxlite_simple_free(CBoxliteSimple* box);
```

Safe to call with NULL.

#### boxlite\_runtime\_free

Free a runtime instance.

```c theme={null}
void boxlite_runtime_free(CBoxliteRuntime* runtime);
```

Safe to call with NULL. Automatically frees all boxes.

### Memory Ownership Summary

| Returned By                             | Free With                       |
| --------------------------------------- | ------------------------------- |
| `boxlite_box_id()`                      | `boxlite_free_string()`         |
| `boxlite_list_info()` (out\_json)       | `boxlite_free_string()`         |
| `boxlite_get_info()` (out\_json)        | `boxlite_free_string()`         |
| `boxlite_box_info()` (out\_json)        | `boxlite_free_string()`         |
| `boxlite_runtime_metrics()` (out\_json) | `boxlite_free_string()`         |
| `boxlite_box_metrics()` (out\_json)     | `boxlite_free_string()`         |
| `boxlite_simple_run()` (out\_result)    | `boxlite_result_free()`         |
| `CBoxliteError` (from any function)     | `boxlite_error_free()`          |
| `boxlite_version()`                     | Do **not** free (static string) |

## JSON Schema Reference

### BoxOptions Schema

```json theme={null}
{
  "rootfs": {"Image": "alpine:3.19"},
  "cpus": 2,
  "memory_mib": 512,
  "disk_size_gb": 10,
  "working_dir": "/workspace",
  "env": [["KEY", "value"], ["ANOTHER", "value"]],
  "volumes": [
    {
      "host_path": "/host/data",
      "guest_path": "/data",
      "read_only": false
    }
  ],
  "network": "Isolated",
  "ports": [
    {
      "host_port": 8080,
      "guest_port": 80,
      "protocol": "Tcp"
    }
  ],
  "auto_remove": true
}
```

### Required Fields

All BoxOptions JSON **must include** these fields:

```json theme={null}
{
  "rootfs": {"Image": "..."},
  "env": [],
  "volumes": [],
  "network": "Isolated",
  "ports": []
}
```

<Warning>
  Omitting any of the required fields will result in a JSON parsing error. Always include `rootfs`, `env`, `volumes`, `network`, and `ports` even if they are empty.
</Warning>

### Field Reference

| Field          | Type    | Default  | Description                                   |
| -------------- | ------- | -------- | --------------------------------------------- |
| `rootfs`       | object  | Required | Root filesystem source                        |
| `cpus`         | integer | 2        | Number of CPUs                                |
| `memory_mib`   | integer | 512      | Memory in MiB                                 |
| `disk_size_gb` | integer | null     | Disk size in GB                               |
| `working_dir`  | string  | null     | Working directory                             |
| `env`          | array   | Required | Environment variables as `[key, value]` pairs |
| `volumes`      | array   | Required | Volume mounts                                 |
| `network`      | string  | Required | Network mode: `"Isolated"`                    |
| `ports`        | array   | Required | Port mappings                                 |
| `auto_remove`  | boolean | true     | Remove box when stopped                       |

### RootfsSpec

```json theme={null}
{"Image": "python:3.11-slim"}
```

or

```json theme={null}
{"RootfsPath": "/path/to/rootfs"}
```

### VolumeSpec

```json theme={null}
{
  "host_path": "/absolute/path/on/host",
  "guest_path": "/path/in/guest",
  "read_only": false
}
```

### PortSpec

```json theme={null}
{
  "host_port": 8080,
  "guest_port": 80,
  "protocol": "Tcp"
}
```

### Building JSON in C

Since C has no native JSON support, here are common approaches for constructing BoxOptions JSON:

#### String Concatenation

```c theme={null}
const char* options = "{"
    "\"rootfs\":{\"Image\":\"alpine:3.19\"},"
    "\"env\":[],"
    "\"volumes\":[],"
    "\"network\":\"Isolated\","
    "\"ports\":[]"
"}";
```

#### Using snprintf for Dynamic Values

```c theme={null}
char options[1024];
snprintf(options, sizeof(options),
    "{"
    "\"rootfs\":{\"Image\":\"%s\"},"
    "\"cpus\":%d,"
    "\"memory_mib\":%d,"
    "\"env\":[],"
    "\"volumes\":[],"
    "\"network\":\"Isolated\","
    "\"ports\":[]"
    "}",
    image_name, num_cpus, memory_mib
);
```

#### With Environment Variables

```c theme={null}
char options[2048];
snprintf(options, sizeof(options),
    "{"
    "\"rootfs\":{\"Image\":\"python:3.11-slim\"},"
    "\"env\":[[\"API_KEY\",\"%s\"],[\"DEBUG\",\"1\"]],"
    "\"volumes\":[],"
    "\"network\":\"Isolated\","
    "\"ports\":[]"
    "}",
    api_key
);
```

#### With Volumes and Ports

```c theme={null}
const char* options = "{"
    "\"rootfs\":{\"Image\":\"nginx:alpine\"},"
    "\"env\":[],"
    "\"volumes\":[{\"host_path\":\"/var/www\",\"guest_path\":\"/usr/share/nginx/html\",\"read_only\":true}],"
    "\"network\":\"Isolated\","
    "\"ports\":[{\"host_port\":8080,\"guest_port\":80,\"protocol\":\"Tcp\"}]"
"}";
```

## Thread Safety

| Component         | Thread Safety                                     |
| ----------------- | ------------------------------------------------- |
| `CBoxliteRuntime` | Thread-safe                                       |
| `CBoxHandle`      | **NOT** thread-safe - do not share across threads |
| `CBoxliteSimple`  | **NOT** thread-safe - do not share across threads |
| Callbacks         | Invoked on the calling thread                     |

<Tip>
  The safe pattern is: share a single `CBoxliteRuntime` across threads, but have each thread create and manage its own box handles.
</Tip>

### Safe Multi-threaded Usage

```c theme={null}
// CORRECT: Share runtime, create per-thread boxes
void* thread_func(void* arg) {
    CBoxliteRuntime* runtime = (CBoxliteRuntime*)arg;
    CBoxliteError error = {0};
    CBoxHandle* box = NULL;

    const char* options = "{"
        "\"rootfs\":{\"Image\":\"alpine:3.19\"},"
        "\"env\":[],\"volumes\":[],\"network\":\"Isolated\",\"ports\":[]"
    "}";

    // Each thread creates its own box
    boxlite_create_box(runtime, options, &box, &error);
    // Use box in this thread only
    boxlite_stop_box(box, &error);
    return NULL;
}

CBoxliteRuntime* runtime;
CBoxliteError error = {0};
boxlite_runtime_new(NULL, NULL, &runtime, &error);

pthread_t threads[4];
for (int i = 0; i < 4; i++) {
    pthread_create(&threads[i], NULL, thread_func, runtime);
}

for (int i = 0; i < 4; i++) {
    pthread_join(threads[i], NULL);
}

boxlite_runtime_free(runtime);
```

### Callback Threading

Callbacks passed to `boxlite_execute` are always invoked on the calling thread. This means:

* You do not need to synchronize within the callback itself
* The callback blocks the execution until it returns
* Heavy processing in callbacks will slow down command execution

```c theme={null}
// Callback runs on the same thread that called boxlite_execute
void output_handler(const char* text, int is_stderr, void* data) {
    // Safe to access thread-local data
    // Safe to write to thread-local buffers
    FILE* stream = is_stderr ? stderr : stdout;
    fprintf(stream, "%s", text);
}
```
