Repository navigation
Wine No JobSystem Breakthrough
Audience: Programmers
Thread Context: This is fundamentally a thread-creation problem. Every new Windows thread under Wine + gVisor rolls the dice on Wine's gs.base race. The fix eliminates the last engine-controlled thread (the JobSystem worker) so the engine runs single-threaded and JobSystem dispatches fall back to inline execution on the main thread.
Platform/Backend Scope: Linux + MinGW-cross PE binary, run under Wine 9.0 inside gVisor, rendering via Lavapipe (CPU Vulkan). This is fallback tier 1 in the Wine Role and Fallback Tiers ladder.
Running the MinGW-cross-compiled SparkEngine.exe under Wine inside gVisor was failing on essentially every run because new threads faulted on Wine's gs.base race before the LD_PRELOAD shim could repair them. Adding a -no-jobsystem flag eliminated the last engine-spawned thread, and combined with auto-enabling the gVisor shim and suppressing Wine's crash debugger, the bare tools/wine-run.sh … SparkEngine.exe -test-frames N invocation reached 4/5 (80%) RC=0 end-to-end runs. The previous baseline was 0%.
Even with -threads 1 -no-subprocess -minimal-init, the engine still spawned one JobSystem worker thread via Spark::EngineSetup::InitializeJobSystem(1) inside InitHeadlessEngineContext. On gVisor, every new Windows thread races Wine's gs.base setup — if the thread faults before the shim's arch_prctl interception or /proc/self/maps TEB discovery catches it, Wine's SEH dispatcher sees an invalid frame (call_stack_handlers invalid frame) or a stack overflow, and the process dies.
With one worker thread, the observed failure was a second TID faulting with EXCEPTION_ACCESS_VIOLATION immediately after the main thread's Timer construction, before InitHeadlessEngineContext completed. The shim only got one repair cycle on the main thread; the worker lost the race.
A new -no-jobsystem flag (g_noJobSystem global) parsed from the command line in both the Linux and Windows entry points. When set, it skips InitializeJobSystem() entirely. Code paths that call JobSystem::Get().Dispatch(...) fall back to inline main-thread execution because JobSystem::IsInitialized() returns false.
Files changed:
-
SparkEngine/Source/Core/SparkEngine.cpp—g_noJobSystemglobal -
SparkEngine/Source/Core/SparkEngineWindows.cpp— parse flag + guardInitializeJobSystem -
SparkEngine/Source/Core/SparkEngineLinux.cpp— parse flag + guardInitializeJobSystem
(All three files confirmed to still reference the no-jobsystem flag as of 2026-06-08.)
-
Auto-flag
-no-jobsystem— appended to theSparkEngine.exeauto-flag block alongside-headless,-threads 1,-no-subprocess,-minimal-init. All five are added automatically; opt out withSPARK_WINE_NO_AUTO_FLAGS=1. -
gVisor shim auto-activation — changed from opt-in (
SPARK_WINE_GVISOR_SHIM=1) to auto-detect: the shim loads whenevertools/gvisor-wine-shim.soexists. Opt out withSPARK_WINE_GVISOR_SHIM=0. The shim is strictly additive where Wine's native SEH already works. -
Crash-debugger disable — appends
AeDebug Auto=0to the Wine prefix'ssystem.regso unhandled faults callExitProcessinstead of spawningwinedbg(which itself loses the gs.base race and hangs forever on gVisor). -
Cleanup trap —
trap cleanup_wineserver EXIT INT TERMkills the wineserver on script exit so orphans don't hold the prefix lock.
5-run reliability sweep (gVisor / Wine 9.0 / Lavapipe):
Run 1: RC=0 lines=72 full shutdown ✓ Timer destructor ✓
Run 2: RC=0 lines=64 full shutdown ✓ Timer destructor ✓
Run 3: RC=1 lines=17 early fault (shim lost race on Wine-internal thread)
Run 4: RC=0 lines=63 full shutdown ✓ Timer destructor ✓
Run 5: RC=0 lines=68 full shutdown ✓ Timer destructor ✓
4/5 = 80% success rate. Baseline without -no-jobsystem: 0% — every run crashed at the worker thread before the main loop.
Wine-internal threads the LD_PRELOAD shim can't control:
- Wine timer thread (spawned by ntdll during PE-loader init)
- Wine service threads (part of early DLL init)
These fault before the shim's sigaction trampoline is installed for them, so the gs.base race is unprotected. Fully closing the gap needs one of:
- Upstream Wine fix (wine-mirror/wine #61/#63 merged into stock Wine)
- Upstream gVisor fix (proper
arch_prctl ARCH_SET_GSemulation) - Further shim evolution — intercept
clone/clone3to pre-set gs.base on new threads before they execute any code
# Bare invocation — all flags auto-appended, shim auto-loaded:
tools/wine-run.sh build/linux-mingw-release/bin/SparkEngine.exe -test-frames 20
# Equivalent explicit invocation:
SPARK_WINE_GVISOR_SHIM=1 tools/wine-run.sh \
build/linux-mingw-release/bin/SparkEngine.exe \
-test-frames 20 -threads 1 -no-subprocess -minimal-init -no-jobsystem \
-window-size 800x600-
Original entry date: 2026-04-16 (
wine-no-jobsystem-breakthrough-2026-04-16.md, type: Issue + Pattern) - Verified against codebase 2026-06-08.
- Status bullets:
-
Still accurate. The
no-jobsystemflag is referenced in all three entry-point files (SparkEngine.cpp,SparkEngineWindows.cpp,SparkEngineLinux.cpp). - The 80% success figure and remaining Wine-internal-thread failure mode are environment-dependent (Wine 9.0 / gVisor / Lavapipe) and not re-benchmarked here.
-
tools/wine-run.shandtools/gvisor-wine-shim.cremain the relevant script and shim.
-
Still accurate. The
- Wine Role and Fallback Tiers — the full fallback ladder this run sits in (tier 1)
- GPU/CPU Separation Plan — NullRHIDevice / software-render context
Published from 2b03dc797148. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Platform Certification
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Fuzz Policy and Parser Security
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Crash Reporting
- Golden Image Testing
- Utilities
- Testing
- Fuzz Policy and Parser Security
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers