Skip to content

Concurrency and host architecture refactoring - #871

Merged
tinchodias merged 3 commits into
devfrom
DeferAndSettle
Sep 7, 2026
Merged

Concurrency and host architecture refactoring#871
tinchodias merged 3 commits into
devfrom
DeferAndSettle

Conversation

@tinchodias

Copy link
Copy Markdown
Collaborator

Key highlights:

  • Singleton Hosts (#default instead of #new): Standalone hosts (BlHeadlessHost, BlOSWindowSDL2Host, BlOSSDL3Host, BlMorphicWindowHost) are now singletons accessed via #default. Sending #new now raises an explicit error ('Use #default instead'). This directly affects existing scripts that previously instantiated hosts with #new (e.g. aSpace host: BlHeadlessHost default).
  • Instance-Side BlHost API & BlHostRegistry default: Replaced static class-side host APIs with instance-side host objects managing their own universe, pulse loop, and spaces.
  • Converts Morphic hosts to run in a separate pulse loop process (like SDL2 and SDL3) and adds double-buffering.
  • Introduce BlEventSimulator based on class-side methods of BlSpace.
  • Removal of BlMockedHost (replaced by BlHeadlessHost default): Removed BlMockedHost and package BlocHost-Mock. Rather than expecting manual, explicit #pulse calls from tests, headless testing now runs on a pulse process using BlHeadlessHost default, matching how normal hosts operate. Any external script, test, or baseline referencing BlMockedHost should be updated to BlHeadlessHost default.
  • Event-driven pulse synchronization in BlParallelUniverse.
  • Adds synchronization methods in BlSpace (#deferAndSettle:, #defer:, #deferOrValue:, #settle, #isSettled).
  • Moves eventQueue from BlHostSpace to BlSpace, and clears pending events when a window closes.
  • Uses BlHost as a facade to encapsulate universe (#spaces, #closeSpaces).
  • Adds #denyPulseProcess to guard against blocking calls from inside the pulse process.

Key highlights:
- Singleton Hosts (`#default` instead of `#new`): Standalone hosts (`BlHeadlessHost`, `BlOSWindowSDL2Host`, `BlOSSDL3Host`, `BlMorphicWindowHost`) are now singletons accessed via `#default`. Sending `#new` now raises an explicit error (`'Use #default instead'`). This directly affects existing scripts that previously instantiated hosts with `#new` (e.g. `aSpace host: BlHeadlessHost default`).
- Instance-Side BlHost API & `BlHostRegistry default`: Replaced static class-side host APIs with instance-side host objects managing their own universe, pulse loop, and spaces.
- Converts Morphic hosts to run in a separate pulse loop process (like SDL2 and SDL3) and adds double-buffering.
- Introduce `BlEventSimulator` based on class-side methods of `BlSpace`.
- Removal of `BlMockedHost` (replaced by `BlHeadlessHost default`): Removed `BlMockedHost` and package `BlocHost-Mock`. Rather than expecting manual, explicit `#pulse` calls from tests, headless testing now runs on a pulse process using `BlHeadlessHost default`, matching how normal hosts operate. Any external script, test, or baseline referencing `BlMockedHost` should be updated to `BlHeadlessHost default`.
- Event-driven pulse synchronization in `BlParallelUniverse`.
- Adds synchronization methods in `BlSpace` (`#deferAndSettle:`, `#defer:`, `#deferOrValue:`, `#settle`, `#isSettled`).
- Moves `eventQueue` from `BlHostSpace` to `BlSpace`, and clears pending events when a window closes.
- Uses `BlHost` as a facade to encapsulate `universe` (`#spaces`, `#closeSpaces`).
- Adds `#denyPulseProcess` to guard against blocking calls from inside the pulse process.
@tinchodias

tinchodias commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Extended:

Summary

This PR proposes changes to improve concurrency and process synchronization between external processes (such as the Morphic UI process from the Playground, test runner processes in SUnit/Calypso, or background worker threads) and the Bloc host pulse loop.

Key highlights:

  • Singleton Hosts (#default instead of #new): Standalone hosts (BlHeadlessHost, BlOSWindowSDL2Host, BlOSSDL3Host, BlMorphicWindowHost) are now singletons accessed via #default. Sending #new now raises an explicit error ('Use #default instead'). This directly affects existing scripts that previously instantiated hosts with #new (e.g. aSpace host: BlHeadlessHost default).
  • Instance-Side BlHost API & BlHostRegistry default: Replaced static class-side host APIs with instance-side host objects managing their own universe, pulse loop, and spaces.
  • Converts Morphic hosts to run in a separate pulse loop process (like SDL2 and SDL3) and adds double-buffering.
  • Introduce BlEventSimulator based on class-side methods of BlSpace.
  • Removal of BlMockedHost (replaced by BlHeadlessHost default): Removed BlMockedHost and package BlocHost-Mock. Rather than expecting manual, explicit #pulse calls from tests, headless testing now runs on a pulse process using BlHeadlessHost default, matching how normal hosts operate. Any external script, test, or baseline referencing BlMockedHost should be updated to BlHeadlessHost default.
  • Event-driven pulse synchronization in BlParallelUniverse.
  • Adds synchronization methods in BlSpace (#deferAndSettle:, #defer:, #deferOrValue:, #settle, #isSettled).
  • Moves eventQueue from BlHostSpace to BlSpace, and clears pending events when a window closes.
  • Uses BlHost as a facade to encapsulate universe (#spaces, #closeSpaces).
  • Adds #denyPulseProcess to guard against blocking calls from inside the pulse process.

Key Changes

  1. Singleton Hosts (#default instead of #new) & BlHostRegistry default:

    • Standalone hosts (BlHeadlessHost, BlOSWindowSDL2Host, BlOSSDL3Host, BlMorphicWindowHost) now use the TBlSingletonHost trait and are accessed via MyHost default.
    • Important for scripts: Sending #new to a singleton host class now explicitly raises an Error ('Use #default instead'). Scripts and tests configuring spaces must now write aSpace host: BlHeadlessHost default (or BlOSWindowSDL2Host default) instead of sending #new.
    • Removal of BlMockedHost: Removed BlMockedHost and package BlocHost-Mock. To eliminate manual, explicit #pulse sends from test suites, headless tests now run pulse-synchronized on BlHeadlessHost default. External code or baselines referencing BlMockedHost should use BlHeadlessHost default as the replacement.
    • Converted BlHost subclasses from class-side static methods to instance-side objects holding their universe, pulse loop, and host space lifecycle.
    • Introduced BlHostRegistry default to discover, prioritize, and manage host instances dynamically.
    • Registered BlHostRegistry in SessionManager (startUp: / shutDown:).
    • Added BlHostRegistry >> #closeSpaces and Bloc class >> #closeSpaces to close open spaces across active hosts.
    • Replaced BlSpace >> #ensureWindowOpen and previousVisibleStatus with clean snapshot management in BlParallelUniverse (visibleSpacesOnShutdown).
  2. BlSpace Concurrency & Synchronization APIs:

    • deferAndSettle: aBlock: Runs aBlock on the host pulse loop and waits until subsequent tasks, skin passes, and layouts have settled.
    • defer: aBlock: Enqueues aBlock asynchronously to run on the pulse loop.
    • deferOrValue: aBlock: Runs immediately if already in the pulse process; otherwise defers to the pulse loop.
    • settle: Waits synchronously until deferred actions, tasks, and frame phases are idle. Guarded with #denyPulseProcess.
    • isSettled: Checks if the space and its frame phases are currently idle.
    • settleForDuration: aDuration: Time-bounded settlement waiting.
  3. eventQueue Migration to BlSpace & Clearing Events on Window Close:

    • Moved eventQueue from BlHostSpace directly into BlSpace (BlSpace >> #eventQueue, BlSpace >> #enqueueEvent:), so that events, tasks, layout, and drawing phases are all handled directly on BlSpace.
    • When a host window closes (hostSpaceClose), pending events in eventQueue are cleared (eventQueue removeAll). This prevents old hardware events from being replayed if the space is reopened or moved to another host.
  4. Host as Facade Encapsulating universe (#spaces, #closeSpaces):

    • Uses BlHost as a facade between BlSpace and platform runtime execution (#openSpace:, #closeSpace:, #hasSpace:, #isSettled, #isPulsing, #defer:, #spaces, #closeSpaces).
    • Senders no longer need to access self host universe or self host universe spaces directly.
    • Standardized BlHost >> #spaces and BlHost >> #closeSpaces.
    • Renamed internal host-space management to hostSpaceOpen and hostSpaceClose under #'host space - accessing' to keep space public autocompletion clean.
    • Decoupling BlSpace from the in-image universe also facilitates future work on subprocess/IPC hosts.
  5. Pulse Process Helpers & Deadlock Guard (#denyPulseProcess):

    • Harmonized process terminology across Bloc: pulseProcess, deferOrValue: (replacing older uiProcessDo: and inUIProcessDo:).
    • Added #denyPulseProcess on BlHost (used by BlParallelUniverse and BlEventSimulator). It raises an error if blocking synchronization (settle, waitUntil:) is called from within the pulse loop process itself, avoiding deadlocks.
  6. Morphic Hosts on a Separate Pulse Process (Like SDL2 and SDL3) & Double-Buffering:

    • Converted Morphic hosts so their window spaces run in an independent pulse loop process, matching the behavior of SDL2 and SDL3 hosts.
    • Implemented double-buffering (backBuffer, frontBuffer) in BlAbstractMorphicHostSpace, preventing tearing and blank forms when embedding spaces in Morphic or Spec2 presenters (SpBlSpaceInMorphPresenter, BlDemoPresenter).
    • Calls currentWorld defer: [ self changed ] from BlMorphicSpaceHostMorph >> #form: to wake up the Morphic UI stepping loop from the pulse process.
    • Added synchronous morphicWindow fullBounds in BlMorphicWindowHostSpace >> #show to prevent initial 0@0 extent issues.
    • Cleaned up Morphic window close handling so closing a window does not reopen it on the next pulse.
  7. Guarded Layout & Concurrency Safety (#forceLayout, Text, Export):

    • Guarded BlElement >> #forceLayout against execution on attached elements (signaling an Error directing senders to space settle or space deferAndSettle:).
    • Guarded BlTextElement >> #onPostMeasure: with a local paragraph copy and nil-check against concurrent text release/invalidation.
    • Updated BlElement >> #aeAsForm and BAExporter >> #export to synchronize with the space (space settle) when attached, and force layout synchronously when detached.
  8. Testing Modernization (BlSpaceTestCase, BlEventSimulator, BlParameterizedHostTest):

    • Introduced BlSpaceTestCase as a lightweight base class for fast, headless unit tests with automatic cleanup.
    • Refactored BlParameterizedHostTest to parameterize on host instances (BlHostRegistry default availableHosts).
    • Extracted event simulation into BlEventSimulator in Bloc-Simulation with stateful modifiers and #denyPulseProcess guard.

Related Issues

@tinchodias

Copy link
Copy Markdown
Collaborator Author

BARenderTest's buildVariantsOfRoundedRectangleAndOutskirts fails on mac due to recent change in the libraries versions, but windows libraries are still the old versions:

Mac:

Cairo: 1.18.4
Freetype: 2.13.3
Harfbuzz: 11.0.0

Windows:

Cairo: 1.17.4
Freetype: 2.12.1
Harfbuzz: 5.3.1

Workaround to #872
@tinchodias
tinchodias merged commit d61a9c1 into dev Sep 7, 2026
6 checks passed
@tinchodias
tinchodias deleted the DeferAndSettle branch September 7, 2026 03:18
@tinchodias

Copy link
Copy Markdown
Collaborator Author

This PR introduces a new System Setting for subclasses of BlParameterizedHostTest:
Test hosts
"All available hosts" means running each of the tests in BlHeadlessHost, BlMorphicWindowHost and BlOSWindowSDL2Host, while the other option means running only on BlHeadlessHost, which is faster.

In my image with Bloc, Album and Toplo, this changes from running around 5000 tests to 3500 test.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant