Skip to content

Live load_level between large worlds deadlocks: worker wedges on a full Ed channel during clone init #55

Description

@dsrw

Switching levels at runtime (eval 'load_level \"world2\"' while a 617-unit world was loaded) hard-wedged Enu. The window froze and never recovered; two sample captures ~30s apart show the worker thread parked on the same condition variable the entire time.

Worker thread (100% of samples, both captures):

worker_thread
  run_deferred
    change_loaded_level (serializers)
      load_level → load_units
        code= → change_code → load_script → ctx.run (VM)
          rawExecute → new_instance (host_bridge)
            Build.clone → Build.init → init_unit
              defaults (EdValue init)
                subscriptions.send → send_or_buffer → channelSend
                  pthread_cond_wait   <-- parked forever

It's mid-load of the new world, running a spawner script; cloning an instance sends the clone's Ed field defaults to subscribers, and the receiving context's channel is full. Nothing drains it, so the load never completes.

Main thread (~90% of samples): Main::iteration → VisualServerWrapMT::sync → cond_wait, with the render thread busy in RasterizerCanvasGLES3 polygon drawing (UI/canvas redraw). Frames are progressing, but whatever should be ticking the receiving Ed context during a live level switch isn't running — the worker stayed blocked on the identical channelSend across both captures, so this is a wedge, not slow drain.

Repro context:

  • world1 loaded (58 root builds + 556 spawner instances = 617 units)
  • eval 'load_level "world2"' (world2: 81 scripts, several spawners)
  • Enu froze during the switch; force-quit required

Likely the same failure family as the take1 demo collapse (scripts erroring, extreme slowdown under heavy load until restart): Ed channel backpressure with a stalled consumer. A bounded channel send from the worker with no guaranteed drainer during change_loaded_level deadlocks; options include ticking the main/receiving ctx during level switch, making the send fail/buffer instead of blocking, or draining before running spawner scripts.

Full samples captured (main + worker + render stacks) — available on request.

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