Fixed two critical race conditions that prevented multi-threaded module execution: ## Bug #1: ThreadedModuleSystem::registerModule() race condition **Symptom:** Deadlock on first processModules() call **Root Cause:** Worker thread started before being added to workers vector **Fix:** Add worker to vector BEFORE spawning thread (src/ThreadedModuleSystem.cpp:102-108) Before: - Create worker → Start thread → Add to vector (RACE!) - Thread accesses workers[index] before push_back completes After: - Create worker → Add to vector → Start thread (SAFE) - Thread guaranteed to find worker in vector ## Bug #2: stillhammer::createLogger() race condition **Symptom:** Deadlock when multiple threads create loggers simultaneously **Root Cause:** Check-then-register pattern without mutex protection **Fix:** Added static mutex around spdlog::get() + register_logger() (external/StillHammer/logger/src/Logger.cpp:94-96) Before: - Thread 1: check → create → register - Thread 2: check → create → register (RACE on spdlog registry!) After: - Mutex protects entire check-then-register critical section ## Validation & Testing Added comprehensive test suite: - test_threaded_module_system.cpp (6 unit tests) - test_threaded_stress.cpp (5 stress tests: 50 modules × 1000 frames) - test_logger_threadsafe.cpp (concurrent logger creation) - benchmark_threaded_vs_sequential.cpp (performance comparison) - docs/THREADED_MODULE_SYSTEM_VALIDATION.md (full validation report) All tests passing (100%): - ThreadedModuleSystem: ✅ 0.15s - ThreadedStress: ✅ 7.64s - LoggerThreadSafe: ✅ 0.13s ## Impact ThreadedModuleSystem now PRODUCTION READY: - Thread-safe module registration - Stable parallel execution (validated with 50,000+ operations) - Hot-reload working (100 cycles tested) - Logger thread-safe for concurrent module initialization Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
6.2 KiB
6.2 KiB
GroveEngine - Claude Code Context
Project Overview
GroveEngine is a C++17 hot-reload module system for game engines. It supports dynamic loading/unloading of modules (.so) with state preservation during hot-reload.
Documentation
For developers using GroveEngine:
- DEVELOPER_GUIDE.md - Complete guide to building applications with GroveEngine (modules, IIO topics, examples)
- USER_GUIDE.md - Core module system, hot-reload, IIO communication basics
Module-specific:
- BgfxRenderer README - 2D rendering module (sprites, text, tilemap, particles)
- InputModule README - Input handling (mouse, keyboard, gamepad)
- UIModule README - User interface system overview
UIModule Documentation (⚠️ READ BEFORE WORKING ON UI):
- UI Widgets - Widget properties, JSON configuration, custom widgets
- UI Topics - IIO topics reference and usage patterns
- UI Architecture - Threading model, limitations, design principles
- UI Rendering - Retained mode rendering architecture
Module Systems
| System | Status | Description | Use Case |
|---|---|---|---|
| SequentialModuleSystem | ✅ Production Ready | Single-threaded, one module at a time | Debug, testing |
| ThreadedModuleSystem | ✅ Phase 2 Complete | One thread per module (parallel execution) | 2-8 modules, ≤30 FPS |
| ThreadPoolModuleSystem | 🚧 Planned (Phase 3) | Shared worker pool, work stealing | High performance (>30 FPS) |
| ClusterModuleSystem | 🚧 Planned (Phase 4) | Distributed across machines | MMO scale |
Available Modules
| Module | Status | Description | Build Flag |
|---|---|---|---|
| BgfxRenderer | ✅ Phase 7-8 Complete | 2D rendering (sprites, text, tilemap, particles) | -DGROVE_BUILD_BGFX_RENDERER=ON |
| UIModule | ✅ Phase 7 Complete | UI widgets (buttons, panels, scrolling, tooltips) | -DGROVE_BUILD_UI_MODULE=ON |
| InputModule | ✅ Production Ready | Input handling (mouse, keyboard, SDL backend) | -DGROVE_BUILD_INPUT_MODULE=ON |
Integration: All modules communicate via IIO topics. See DEVELOPER_GUIDE.md for complete IIO topics reference.
Build & Test
# Build core only
cmake -B build && cmake --build build -j4
# Build with all modules
cmake -B build -DGROVE_BUILD_BGFX_RENDERER=ON -DGROVE_BUILD_UI_MODULE=ON -DGROVE_BUILD_INPUT_MODULE=ON
cmake --build build -j4
# Run all tests (23+ tests)
cd build && ctest --output-on-failure
# Run visual tests (IMPORTANT: always run from project root for correct asset paths)
./build/tests/test_ui_showcase # UI showcase with all widgets
./build/tests/test_renderer_showcase # Renderer showcase (sprites, text, particles)
# Build with ThreadSanitizer
cmake -DGROVE_ENABLE_TSAN=ON -B build-tsan
cmake --build build-tsan -j4
Architecture
Key Components
- ModuleLoader: Handles dlopen/dlclose of .so modules with hot-reload support
- SequentialModuleSystem: Single-threaded module execution for testing
- IntraIOManager: Inter-module communication with pub/sub routing
- TopicTree: O(k) topic matching with wildcard support
Thread Safety Patterns
See docs/coding_guidelines.md for detailed synchronization guidelines.
DO:
// Multiple mutexes - use scoped_lock (deadlock-free)
std::scoped_lock lock(mutex1, mutex2);
// Read-heavy data - use shared_mutex
std::shared_lock readLock(sharedMutex); // concurrent reads
std::unique_lock writeLock(sharedMutex); // exclusive write
DON'T:
// NEVER nest lock_guard - causes deadlock
std::lock_guard lock1(mutex1);
std::lock_guard lock2(mutex2); // DEADLOCK RISK
ModuleLoader Usage
- Each
ModuleLoaderinstance manages ONE module lifecycle - Don't reuse loader for multiple independent modules (causes SEGFAULT)
reload()safely handles state extraction and library reloadload(path, name, isReload=true)for hot-reload with cache bypass
Known Issues
- TankModule.h linter bug: A linter sometimes merges lines 35-36. If build fails with "logger not declared", check this file.
Test Categories
| Test # | Name | Duration | Description |
|---|---|---|---|
| 1-10 | scenario_* | ~0.01s | Basic scenarios |
| 11 | ProductionHotReload | ~12s | Full hot-reload cycle |
| 12 | ChaosMonkey | ~41s | Stress testing |
| 13 | StressTest | ~180s | Heavy load |
| 15 | MemoryLeakHunter | ~135s | 200 reload cycles |
| 19 | CrossSystemIntegration | ~4s | Multi-system test |
Module Architecture Quick Reference
BgfxRenderer
- RHI Layer: Abstracts bgfx calls (
RHIDevice.h,BgfxDevice.cpp) - RenderGraph: Topological sort with Kahn's algorithm for pass ordering
- CommandBuffer: Records commands, executed by device at frame end
- IIO Topics:
render:sprite,render:text,render:tilemap,render:particle,render:camera,render:clear,render:debug/*
UIModule
- UIRenderer: Publishes render commands to BgfxRenderer via IIO (layer 1000+)
- Widgets: UIButton, UIPanel, UILabel, UICheckbox, UISlider, UITextInput, UIProgressBar, UIImage, UIScrollPanel, UITooltip
- IIO Topics: Consumes
input:*,ui:set_text,ui:set_visible; publishesui:click,ui:action,ui:value_changed, etc. - ⚠️ Before modifying UI code: Read UI Architecture for threading model, UI Widgets for widget properties, UI Topics for IIO patterns
InputModule
- Backends: SDLBackend (mouse, keyboard, gamepad Phase 2)
- Thread-safe: Event buffering with lock-free design
- IIO Topics:
input:mouse:*,input:keyboard:*,input:gamepad:*
Debugging Tools
# ThreadSanitizer (detects data races, deadlocks)
cmake -DGROVE_ENABLE_TSAN=ON -B build-tsan
# Helgrind (alternative deadlock detector)
cmake -DGROVE_ENABLE_HELGRIND=ON -B build
make helgrind