Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,80 @@ jobs:
cd build
ctest --output-on-failure --parallel

# ── GCC 16 Reflection-specific validation ────────────────────────
reflection-linux:
name: Reflection (Linux, GCC 16, C++26)
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Add toolchain PPA
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update

- name: Install dependencies
run: |
sudo apt-get install -y cmake ninja-build gcc-16 g++-16

- name: Configure CMake
env:
CC: gcc-16
CXX: g++-16
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=26 \
-DTHREADSCHEDULE_BUILD_EXAMPLES=OFF \
-DTHREADSCHEDULE_BUILD_TESTS=ON \
-DTHREADSCHEDULE_ENABLE_REFLECTION=ON

- name: Build
run: cmake --build build --parallel

- name: Run reflection-focused tests
run: |
ctest --test-dir build \
--no-tests=error \
--output-on-failure \
--tests-regex 'ReflectionApiTest|RegistryQueryTest\.Reflection'

reflection-modules-linux:
name: Reflection Modules (Linux, GCC 16, C++26)
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Add toolchain PPA
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update

- name: Install dependencies
run: |
sudo apt-get install -y cmake ninja-build gcc-16 g++-16

- name: Configure CMake
env:
CC: gcc-16
CXX: g++-16
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=26 \
-DTHREADSCHEDULE_MODULE=ON \
-DTHREADSCHEDULE_ENABLE_REFLECTION=ON

- name: Build module
run: cmake --build build --parallel

- name: Verify reflection-enabled module artifacts
run: |
echo "Reflection module artifacts:"
find build -name '*.a' -o -name '*.gcm' -o -name '*.pcm' | head -20

# ── C++20 Module build verification ────────────────────────────────
modules-linux:
name: Modules (Linux, C++${{ matrix.cpp_standard }}, ${{ matrix.compiler }})
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ compile_commands.json
.cache/
build/
build_*/
build-*/
install/
build_runtime/
112 changes: 112 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,117 @@
# Changelog

## v2.3.0

> This release adds an opt-in GCC 16/C++26 reflection surface, modernizes
> callable/callback storage paths for newer standard libraries, expands the
> benchmark and reporting tooling, and improves current-thread `ThreadInfo`
> handling for more direct native-thread operations.

### New Features

- **Optional GCC 16+ reflection API** -- when building with C++26,
`THREADSCHEDULE_ENABLE_REFLECTION=ON`, and working `-freflection` support,
the library now exports `threadschedule::reflect::*` helpers for field
metadata, field visitation, compile-time projection, and type/field naming.
Reflection support is now **disabled by default** and only activates on
supported toolchains when explicitly requested. (`reflection.hpp`,
`threadschedule.cppm`, `threadschedule.hpp`, `CMakeLists.txt`)

- **Reflection-backed registry selectors** -- `ThreadRegistry` and
`QueryView` now expose field-oriented helpers such as
`where<registered_thread_fields::componentTag()>(...)`,
`where_if<registered_thread_fields::alive()>(...)`,
`find_by<registered_thread_fields::name()>(...)`,
`contains<...>(...)`, and `project<...>()` when reflection is enabled.
(`thread_registry.hpp`)

- **Feature-gated callable helpers** -- `callable.hpp` now centralizes
modern callable selection with fallback aliases for
`std::move_only_function`, `std::copyable_function`, and `std::function_ref`,
while preserving compatibility on older standard libraries. (`callable.hpp`)

- **Current-thread `ThreadInfo` now prefers the native handle** --
default-constructed `ThreadInfo` binds the current thread's native handle and
uses the more direct pthread/HANDLE-based paths for current-thread name,
affinity, policy, and priority operations, while `ThreadInfo(Tid)` remains
available for explicit TID-bound access. (`thread_wrapper.hpp`,
`scheduler_policy.hpp`)

### Performance

- **Lower-overhead registry projections on reflection builds** -- direct
field-projection and field-filter paths now run under the registry's shared
lock and can skip the older `filter(...).map(...)` layering when callers opt
into the new reflection APIs. This reduces intermediate traversal and avoids
some full-entry transformation work for hot query paths. (`thread_registry.hpp`)

- **More metadata is now promoted at compile time** -- reflection field names
and type display names are now stabilized via `std::define_static_string(...)`
and reused through `consteval` helpers such as `field_names<T>()`, reducing
repeated compile-time reconstruction of the same metadata. (`reflection.hpp`)

- **Improved callback/task-path flexibility on newer standard libraries** --
reusable callback storage can use copyable callable wrappers where available,
and the library now exposes a consistent internal callable abstraction across
pools, registries, and error handling. (`callable.hpp`, `thread_pool.hpp`,
`thread_registry.hpp`, `error_handler.hpp`)

### Benchmarks

- **Expanded callable benchmark coverage** -- new benchmark targets compare
callable overhead across standard-library feature levels, storage sizes, and
workload shapes, including cross-standard callable measurements and
reflection-query comparisons. (`benchmarks/callable_std_benchmarks.cpp`,
`benchmarks/reflection_registry_benchmarks.cpp`,
`benchmarks/threadpool_benchmarks.cpp`, `benchmarks/CMakeLists.txt`)

- **Benchmark report generation and charts** -- new Python/reporting tooling
generates SVG benchmark charts and README-ready summaries for callable,
throughput, workload, and reflection query comparisons. (`run_benchmark_graphs.sh`,
`benchmarks/generate_benchmark_report.py`,
`benchmarks/generate_readme_graphs.py`, `docs/benchmarks/*.svg`,
`benchmarks/README.md`)

### Documentation

- **README updates for reflection and benchmark guidance** -- the top-level
README now documents the reflection opt-in flow, reflection-backed registry
queries, and the newer benchmark surfaces. (`README.md`)

- **New CMake reference entry for reflection** -- the reference now documents
`THREADSCHEDULE_ENABLE_REFLECTION`, its default-off behavior, and the
GCC 16+/C++26 activation path. (`docs/CMAKE_REFERENCE.md`)

### Tests & Benchmarks

- **New reflection unit coverage** -- dedicated tests now validate reflection
metadata for core public structs and reflection-backed registry queries.
(`tests/reflection_test.cpp`, `tests/registry_query_test.cpp`,
`tests/CMakeLists.txt`)

- **New callable regression coverage** -- dedicated tests now validate
`function_ref` behavior and public callback alias usage on the new callable
abstraction paths. (`tests/callable_test.cpp`, `tests/CMakeLists.txt`)

- **Updated `ThreadInfo` regression coverage** -- tests now verify the
default-construction path can still resolve current-thread identity and read
current-thread metadata while the explicit `Tid` constructor continues to
control a remote target thread. (`tests/thread_config_test.cpp`)

### CI / Infrastructure

- **Dedicated GCC 16 reflection CI jobs** -- the main test workflow now
includes explicit `ubuntu-24.04` jobs for reflection-enabled GCC 16/C++26
validation: one job builds and runs the reflection-focused test cases, and a
second job verifies the reflection-enabled module build path. This makes the
new `THREADSCHEDULE_ENABLE_REFLECTION` surface visible in CI instead of
relying only on the generic C++26 matrix entry. (`.github/workflows/tests.yml`)

- **Reflection CI test execution is now hardened** -- the reflection-focused
CTest invocation now errors out if no matching tests are registered, so
accidental discovery/configuration regressions cannot silently pass with
zero executed reflection tests. (`.github/workflows/tests.yml`)

## v2.2.0

> **No intended API/ABI breaking changes.** This release extends thread-control
Expand Down
42 changes: 42 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ option(THREADSCHEDULE_INSTALL "Generate install target" ${THREADSCHEDULE_IS_TOPL
option(THREADSCHEDULE_RUNTIME "Build shared runtime for global registry (non header-only)" OFF)
option(THREADSCHEDULE_MODULE "Build C++20 module target (requires CMake >= 3.28 and C++20+)" OFF)
option(THREADSCHEDULE_BUILD_DOCS "Build API documentation with Doxygen" ${THREADSCHEDULE_IS_TOPLEVEL_PROJECT})
option(THREADSCHEDULE_ENABLE_REFLECTION "Enable GCC 16 C++26 reflection APIs when supported" OFF)

# CPM support (optional, download if building tests or benchmarks)
if(THREADSCHEDULE_BUILD_TESTS OR THREADSCHEDULE_BUILD_BENCHMARKS)
Expand Down Expand Up @@ -119,6 +120,33 @@ endif()
# Platform-specific requirements
find_package(Threads REQUIRED)

set(THREADSCHEDULE_HAS_REFLECTION OFF)
if(THREADSCHEDULE_ENABLE_REFLECTION
AND CMAKE_CXX_STANDARD GREATER_EQUAL 26
AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
include(CheckCXXSourceCompiles)
set(_threadschedule_saved_required_flags "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++26 -freflection")
check_cxx_source_compiles(
"
#include <meta>
using namespace std::meta;
struct probe_type { int value; bool ready; };
consteval bool probe() {
auto fields = std::define_static_array(nonstatic_data_members_of(^^probe_type, access_context::current()));
return fields.size() == 2 && identifier_of(fields[0]) == \"value\";
}
static_assert(probe());
int main() { return 0; }
"
THREADSCHEDULE_REFLECTION_PROBE_OK
)
set(CMAKE_REQUIRED_FLAGS "${_threadschedule_saved_required_flags}")
if(THREADSCHEDULE_REFLECTION_PROBE_OK)
set(THREADSCHEDULE_HAS_REFLECTION ON)
endif()
endif()

# Create the interface library target (header-only API)
add_library(ThreadSchedule INTERFACE)
add_library(ThreadSchedule::ThreadSchedule ALIAS ThreadSchedule)
Expand Down Expand Up @@ -151,6 +179,11 @@ target_include_directories(ThreadSchedule INTERFACE
# Link libraries
target_link_libraries(ThreadSchedule INTERFACE Threads::Threads)

if(THREADSCHEDULE_HAS_REFLECTION)
target_compile_definitions(ThreadSchedule INTERFACE THREADSCHEDULE_HAS_REFLECTION=1)
target_compile_options(ThreadSchedule INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-freflection>)
endif()

# Windows: ensure modern API availability macros
if(WIN32)
target_compile_definitions(ThreadSchedule INTERFACE
Expand Down Expand Up @@ -217,6 +250,10 @@ if(THREADSCHEDULE_RUNTIME)
src/runtime_registry.cpp
)
target_compile_definitions(ThreadScheduleRuntime PRIVATE THREADSCHEDULE_EXPORTS THREADSCHEDULE_RUNTIME)
if(THREADSCHEDULE_HAS_REFLECTION)
target_compile_definitions(ThreadScheduleRuntime PUBLIC THREADSCHEDULE_HAS_REFLECTION=1)
target_compile_options(ThreadScheduleRuntime PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-freflection>)
endif()
# Propagate the THREADSCHEDULE_RUNTIME define to consumers so headers call into the DLL
target_compile_definitions(ThreadScheduleRuntime INTERFACE THREADSCHEDULE_RUNTIME)
target_include_directories(ThreadScheduleRuntime
Expand Down Expand Up @@ -271,6 +308,11 @@ if(THREADSCHEDULE_MODULE)
else()
target_compile_features(ThreadScheduleModule PUBLIC cxx_std_20)
endif()

if(THREADSCHEDULE_HAS_REFLECTION)
target_compile_definitions(ThreadScheduleModule PUBLIC THREADSCHEDULE_HAS_REFLECTION=1)
target_compile_options(ThreadScheduleModule PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-freflection>)
endif()
endif()

# Documentation (Doxygen + Awesome theme)
Expand Down
Loading
Loading