Skip to content

tdsh run: a script needs ~35 KB of contiguous heap; let ports size the tdsh.h limits #2

Closed

Description

@aquasock

On a port with a small heap, tdsh run needs more contiguous memory than is left once a desktop is open, and the script is skipped. Most of that memory is the per-script copy of the session, whose size comes from limits in tdsh.h that a build cannot override (listed as a known deviation in STANDARDS.md §10). I'd like to make those limits overridable, and I'm happy to send the pull request.

Where

  • TinyTang, a port of TinyDesk Shell to the BL616 (FreeRTOS) on the Sipeed Tang Console 138K
  • TinyDesk Shell v0.1.5 (8456dd1), TinyDesk v0.1.5 (feaf841)
  • Terminal: TinyDesk's Terminal window on HDMI, and the board's console over USB CDC
  • Heap: 124,768 bytes (TLSF, the SDK's allocator); the Bluetooth stack and two connected devices leave about 65 KB of it free

What happens

Opening castlevania.tdsh or phosphor.tdsh from Files (which runs tdsh run "/scripts/castlevania.tdsh" in the Terminal) returns to the Terminal prompt with no output; nothing in the script runs. The same scripts run normally with tdsh run at the console, with no desktop open.

Measurements

From the port's heap readout (a walk of the TLSF pool) and an allocation-failure counter added to the port's allocator, read on the board right after each attempt:

free heap largest free block free outside that block
console, no desktop 64,704 B 40,536 B ~24 KB
desktop open 48,208 B 40,536 B ~7.7 KB

What a tdsh run script allocates, in order:

allocation size
tdsh_script_job_t, which holds a full tdsh_session_t 19,352 B (32-bit) one block
the script task's stack, TDSH_SCRIPT_TASK_STACK 32,768 B requested one block
the runtime: line table, text, … a few KB small, growing

tdsh_session_t is 19,096 B on a 32-bit target, and 18,496 B of that (97%) is vars[TDSH_MAX_VARS]: 64 × (1 + TDSH_VAR_NAME_MAX 32 + TDSH_VAR_VALUE_MAX 256).

With the desktop open, the job and the stack take the 40 KB block, and the few KB outside it run out while the script is loading: the refused request was 1,056 B, tdsh_realloc of the line table at src/core/tdsh_script.c:189, in task tdsh_script. The script returns, which is the right behaviour.

The port already caps worker stacks at 16 KB in its worker_run (a script peaked at 10,728 B of stack, measured with uxTaskGetStackHighWaterMark), which is how the console case fits; with a 32 KB stack it did not fit at the console either. The port also replaced the SDK allocator's hang on a failed allocation, so this is a clean failure rather than a freeze.

Proposal

Wrap the limits in tdsh.h in #ifndef, as STANDARDS.md §3 asks for limits that size buffers ("ports set them from the build system, never by editing the header"), starting with:

  • TDSH_SCRIPT_TASK_STACK
  • TDSH_MAX_VARS, TDSH_VAR_NAME_MAX, TDSH_VAR_VALUE_MAX

with the current values as defaults, so nothing changes for existing ports. A port with a small heap could then build with, for example, -DTDSH_MAX_VARS=32 -DTDSH_VAR_VALUE_MAX=128, which brings the session from about 19 KB to about 5.8 KB per script. A further step could be to not copy the whole variable table for each script, but that changes behaviour and is your call.

I can send the #ifndef change as a pull request with the host tests run, if this direction is OK with you.

Activity

  1. schikani commented on Oct 6, 2026

    @schikani
    Collaborator

    Thanks for digging into this and sharing the measurements! The #ifndef approach sounds good—please go ahead with the PR, keeping the current values as defaults.

    Please document that the overrides must apply consistently to all components using tdsh.h, since they affect the session structure’s layout. Testing with both the defaults and the smaller limits would be useful.

    Let’s keep the variable-copy behaviour unchanged for now. The smaller limits should help with the memory shortage; separately, we should show an error when script loading runs out of memory instead of returning silently.

  2. schikani commented on Oct 7, 2026

    @schikani
    Collaborator

    Done in #4: TDSH_MAX_VARS, TDSH_VAR_NAME_MAX, TDSH_VAR_VALUE_MAX and TDSH_SCRIPT_TASK_STACK can now be set from the build, with the old values as defaults. The error message for scripts that run out of memory while loading will get its own issue. Thanks for the detailed measurements!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions