Skip to content
Open
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
13 changes: 10 additions & 3 deletions .github/workflows/abi-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ jobs:
fetch-depth: 0
fetch-tags: true

- name: Setup MSVC (Developer Command Prompt)
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1

- name: Install Ninja [Windows]
if: runner.os == 'Windows'
run: choco install ninja --no-progress --yes

- name: Fetch tags (ensure up-to-date)
run: git fetch --tags --force

Expand Down Expand Up @@ -78,7 +86,7 @@ jobs:
if: runner.os == 'Windows'
shell: pwsh
run: |
cmake -B build -G "Visual Studio 17 2022" -A x64 -DTHREADSCHEDULE_RUNTIME=ON -DCMAKE_INSTALL_PREFIX="$env:RUNNER_TEMP/ts-install"
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DTHREADSCHEDULE_RUNTIME=ON -DCMAKE_INSTALL_PREFIX="$env:RUNNER_TEMP/ts-install"
- name: Build (current) [Windows]
if: runner.os == 'Windows'
shell: pwsh
Expand Down Expand Up @@ -110,7 +118,7 @@ jobs:
shell: pwsh
working-directory: integration_tests/runtime_abi_compat
run: |
cmake -B build -G "Visual Studio 17 2022" -A x64 -DTHREADSCHEDULE_RUNTIME=ON -DRUNTIME_ABI_OLD_OFFSET=${{ matrix.offset }} -DCMAKE_PREFIX_PATH="$env:RUNNER_TEMP/ts-install"
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DTHREADSCHEDULE_RUNTIME=ON -DRUNTIME_ABI_OLD_OFFSET=${{ matrix.offset }} -DCMAKE_PREFIX_PATH="$env:RUNNER_TEMP/ts-install"
- name: Build integration test [Windows]
if: runner.os == 'Windows'
shell: pwsh
Expand All @@ -123,4 +131,3 @@ jobs:
run: ctest --test-dir build -C Release --output-on-failure
continue-on-error: ${{ inputs.expected_abi_break == true || steps.major_flag.outputs.changed == 'true' }}


91 changes: 91 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,84 @@
# Changelog

## v2.4.0

> This release adds an explicit stable-ABI subset for shared-runtime / DSO
> boundaries, introduces a migration path with deprecations before hard
> enforcement, and expands ABI-focused regression coverage.

### ABI Stability

- **New opt-in stable ABI subset for runtime boundaries** -- the shared-runtime
build now exposes `threadschedule::abi::*` helpers with opaque
`registry_handle`, POD-style `thread_info_view`, stable status codes, and a
dedicated `abi::AutoRegisterCurrentThread` path for cross-DSO integration.
(`abi.hpp`, `runtime_registry.cpp`)

- **Compile-time ABI markers and export validation** -- the new
`threadschedule::abi::is_abi_stable_v<T>` trait and
`THREADSCHEDULE_VALIDATE_STABLE_ABI_EXPORT(...)` macro let library and
downstream code mark and enforce signatures that are safe to export across a
stable ABI boundary. (`abi.hpp`)

- **Stable-ABI build modes for migration and enforcement** -- CMake now
provides `THREADSCHEDULE_STABLE_ABI=ON` for migration builds and
`THREADSCHEDULE_STABLE_ABI_STRICT=ON` for hard enforcement. In runtime mode,
the strict path rejects ABI-unsafe entry points such as
`registry()`, `set_external_registry(ThreadRegistry*)`, and the legacy
`AutoRegisterCurrentThread` constructors at compile time. (`CMakeLists.txt`,
`thread_registry.hpp`)

### Compatibility

- **Deprecation-first migration path for legacy runtime APIs** -- when
`THREADSCHEDULE_STABLE_ABI=ON` is enabled without strict mode, the existing
runtime-facing C++ helpers remain available but are marked deprecated with
guidance toward `threadschedule::abi::*`. This keeps default builds
source-compatible while making ABI-unsafe usage visible before it becomes a
hard error. (`export.hpp`, `thread_registry.hpp`)

- **Runtime internals now route through non-deprecated helpers** -- internal
registry access was split into dedicated detail helpers so ThreadSchedule's
own headers and runtime implementation do not trip the new deprecation path
during normal compilation. (`thread_registry.hpp`, `runtime_registry.cpp`,
`chaos.hpp`)

### Tests

- **New stable-ABI regression coverage** -- added dedicated tests for the new
ABI surface plus compile-time checks that confirm:
stable handles are accepted, `ThreadRegistry*` exports are rejected, and
runtime `registry()` usage transitions from deprecation in migration mode to
hard failure in strict mode. (`tests/abi_test.cpp`, `tests/CMakeLists.txt`)

- **Cross-standard runtime ABI coverage was strengthened** -- the integration
test now explicitly mixes an older C++17-built dependency with C++23-built
current components to keep the mixed-standard runtime scenario visible in CI
and local release validation. (`integration_tests/runtime_abi_compat/*`)

## v2.3.1

> This release focuses on ABI hardening for mixed-standard consumers of the
> shared runtime.

### ABI / Runtime Fixes

- **`threadschedule::expected` is now always the library-owned type** -- the
public `expected` alias no longer flips over to `std::expected` in C++23+.
This stabilizes exported signatures across consumers compiled with different
language modes and avoids cross-DSO ABI mismatches when an intermediate
library exposes ThreadSchedule result types. (`expected.hpp`)

- **Runtime visibility and consumer defines were tightened** -- the runtime
target now consistently exports default-visible symbols and propagates the
`THREADSCHEDULE_RUNTIME` define so consumers call into the shared runtime
instead of accidentally instantiating a separate header-only registry.
(`thread_registry.hpp`, `CMakeLists.txt`)

- **Packaging/tooling fixes for runtime consumers** -- Conan/CMake packaging
paths were adjusted so runtime-enabled consumers resolve the intended build
configuration more reliably. (`conanfile.py`, `CMakeLists.txt`)

## v2.3.0

> This release adds an opt-in GCC 16/C++26 reflection surface, modernizes
Expand Down Expand Up @@ -484,6 +563,18 @@ auto futures = pool.submit_range(tasks.begin(), tasks.end());
auto futures = pool.submit_batch(tasks.begin(), tasks.end());
```

## v1.4.3

- Docs: clarified scheduled-task storage and dispatch-order edge cases in
`scheduled_pool.hpp`, especially around queueing semantics and execution
ordering guarantees for scheduled workloads.

## v1.4.2

- Docs: expanded and restructured documentation across multiple public headers
to better explain thread wrappers, registries, pools, and scheduling-related
APIs without changing library behaviour.

## v1.4.1

- Fix: `*WrapperReg` types (`ThreadWrapperReg`, `JThreadWrapperReg`,
Expand Down
23 changes: 22 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,16 @@ option(THREADSCHEDULE_BUILD_TESTS "Build tests" OFF)
option(THREADSCHEDULE_BUILD_BENCHMARKS "Build benchmarks" OFF)
option(THREADSCHEDULE_INSTALL "Generate install target" ${THREADSCHEDULE_IS_TOPLEVEL_PROJECT})
option(THREADSCHEDULE_RUNTIME "Build shared runtime for global registry (non header-only)" ON)
option(THREADSCHEDULE_STABLE_ABI "Expose the stable ABI subset helpers" OFF)
option(THREADSCHEDULE_STABLE_ABI_STRICT "Reject non-stable runtime ABI usage at compile time" 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)

if(THREADSCHEDULE_STABLE_ABI_STRICT AND NOT THREADSCHEDULE_STABLE_ABI)
set(THREADSCHEDULE_STABLE_ABI ON)
endif()

# CPM support (optional, download if building tests or benchmarks)
if(THREADSCHEDULE_BUILD_TESTS OR THREADSCHEDULE_BUILD_BENCHMARKS)
# Download CPM.cmake if not already available
Expand Down Expand Up @@ -176,6 +182,14 @@ target_include_directories(ThreadSchedule INTERFACE
$<INSTALL_INTERFACE:include>
)

if(THREADSCHEDULE_STABLE_ABI)
target_compile_definitions(ThreadSchedule INTERFACE THREADSCHEDULE_STABLE_ABI=1)
endif()

if(THREADSCHEDULE_STABLE_ABI_STRICT)
target_compile_definitions(ThreadSchedule INTERFACE THREADSCHEDULE_STABLE_ABI_STRICT=1)
endif()

# Link libraries
target_link_libraries(ThreadSchedule INTERFACE Threads::Threads)

Expand Down Expand Up @@ -249,13 +263,20 @@ if(THREADSCHEDULE_RUNTIME)
add_library(ThreadScheduleRuntime SHARED
src/runtime_registry.cpp
)
target_compile_definitions(ThreadScheduleRuntime PRIVATE THREADSCHEDULE_EXPORTS THREADSCHEDULE_RUNTIME)
target_compile_definitions(ThreadScheduleRuntime PRIVATE THREADSCHEDULE_EXPORTS THREADSCHEDULE_RUNTIME
THREADSCHEDULE_INTERNAL_RUNTIME_BUILD=1)
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)
if(THREADSCHEDULE_STABLE_ABI)
target_compile_definitions(ThreadScheduleRuntime PUBLIC THREADSCHEDULE_STABLE_ABI=1)
endif()
if(THREADSCHEDULE_STABLE_ABI_STRICT)
target_compile_definitions(ThreadScheduleRuntime PUBLIC THREADSCHEDULE_STABLE_ABI_STRICT=1)
endif()
target_include_directories(ThreadScheduleRuntime
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ or with optional **shared runtime** for multi-DSO applications.
feature detection and optimization
- **C++20 Modules**: Optional `import threadschedule;` support (C++20+)
- **Header-Only or Shared Runtime**: Choose based on your needs
- **Stable ABI Subset**: `threadschedule::abi::*` helpers for runtime-backed
DSO/plugin boundaries across mixed language modes
- **Enhanced Wrappers**: Extend `std::thread`, `std::jthread`, and `pthread`
with powerful features
- **Non-owning Views**: Zero-overhead views to configure existing threads or
Expand Down Expand Up @@ -102,7 +104,7 @@ when upgrading from v1.x.
- **[Integration Guide](docs/INTEGRATION.md)** - CMake, Conan, FetchContent,
system installation
- **[Thread Registry Guide](docs/REGISTRY.md)** - Process-wide thread control
and multi-DSO patterns
and multi-DSO / stable-ABI patterns
- **[Scheduled Tasks Guide](docs/SCHEDULED_TASKS.md)** - Timer and periodic task
scheduling
- **[Error Handling Guide](docs/ERROR_HANDLING.md)** - Exception handling with
Expand Down Expand Up @@ -415,8 +417,17 @@ int main() {
```

**For multi-DSO applications:** Use the shared runtime option
(`THREADSCHEDULE_RUNTIME=ON`) to ensure a single process-wide registry. See
[docs/REGISTRY.md](docs/REGISTRY.md) for detailed patterns.
(`THREADSCHEDULE_RUNTIME=ON`) to ensure a single process-wide registry.

If your app or plugin ABI crosses shared-library boundaries, prefer the stable
ABI subset in `threadschedule::abi::*` instead of exporting
`ThreadRegistry`, `RegisteredThreadInfo`, or `AutoRegisterCurrentThread`
directly in your own ABI. Enabling `THREADSCHEDULE_STABLE_ABI=ON` adds
deprecation warnings for runtime-backed APIs that are unsafe to expose across
those boundaries, including mixed builds such as one DSO compiled as C++17 and
another as C++23, and `THREADSCHEDULE_STABLE_ABI_STRICT=ON` turns those uses
into compile errors. See [docs/REGISTRY.md](docs/REGISTRY.md) and
[docs/CMAKE_REFERENCE.md](docs/CMAKE_REFERENCE.md) for the migration details.

Notes:

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.0
2.4.0
53 changes: 46 additions & 7 deletions docs/CMAKE_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
| `THREADSCHEDULE_BUILD_TESTS` | BOOL | OFF | Build unit tests |
| `THREADSCHEDULE_BUILD_BENCHMARKS` | BOOL | OFF | Build benchmarks (downloads Google Benchmark) |
| `THREADSCHEDULE_RUNTIME` | BOOL | OFF | Build shared runtime library for process-wide registry |
| `THREADSCHEDULE_STABLE_ABI` | BOOL | OFF | Expose the stable ABI subset and deprecate runtime-backed APIs that are unsafe across DSO boundaries |
| `THREADSCHEDULE_STABLE_ABI_STRICT` | BOOL | OFF | Reject ABI-unsafe runtime API usage at compile time; implies `THREADSCHEDULE_STABLE_ABI` |
| `THREADSCHEDULE_ENABLE_REFLECTION` | BOOL | OFF | Enable GCC 16+ C++26 reflection APIs and reflection-backed registry queries when supported |
| `THREADSCHEDULE_INSTALL` | BOOL | ON (main project)<br>OFF (subdirectory) | Generate install targets |

Expand Down Expand Up @@ -115,6 +117,20 @@ target_link_libraries(my_app PRIVATE

**Result**: A shared runtime library (`libthreadschedule.so` / `threadschedule.dll`) is built. All components share a single process-wide registry instance.

### With Shared Runtime and Stable ABI Checks
```cmake
set(THREADSCHEDULE_RUNTIME ON)
set(THREADSCHEDULE_STABLE_ABI ON)
# or: set(THREADSCHEDULE_STABLE_ABI_STRICT ON)
add_subdirectory(external/ThreadSchedule)
```

**Result**: The shared runtime exports the `threadschedule::abi::*` helper
surface for DSO boundaries. In migration mode, legacy runtime APIs such as
`registry()` and `AutoRegisterCurrentThread` emit deprecation warnings. In
strict mode, those runtime-backed APIs become compile-time errors outside the
runtime implementation itself.

### Development Build (All Features)
```cmake
set(THREADSCHEDULE_BUILD_EXAMPLES ON)
Expand Down Expand Up @@ -167,7 +183,8 @@ Optional shared runtime target for process-wide registry. Properties:
- **Type**: SHARED library (DLL/SO)
- **Availability**: Only when `THREADSCHEDULE_RUNTIME=ON`
- **Include directories**: `include/`
- **Exports**: `registry()` and `set_external_registry()` functions
- **Exports**: `registry()` / `set_external_registry()` plus the
`threadschedule::abi::*` runtime helpers
- **Use case**: Multi-DSO applications requiring single registry instance

### Usage
Expand All @@ -184,6 +201,15 @@ target_link_libraries(your_target PRIVATE

**Note**: When using the runtime library, all DSOs (libraries and executables) in your application must link against `ThreadSchedule::Runtime` to share the same registry instance.

**ABI guidance**:

- Use `threadschedule::abi::*` for plugin/DSO ABI boundaries.
- Treat `registry()`, `set_external_registry(ThreadRegistry*)`, and
`AutoRegisterCurrentThread` as migration-only runtime APIs once
`THREADSCHEDULE_STABLE_ABI` is enabled.
- Use `THREADSCHEDULE_VALIDATE_STABLE_ABI_EXPORT(...)` in exported headers to
static-assert that boundary signatures only use stable ABI types.

## Platform-Specific Behavior

### Linux
Expand Down Expand Up @@ -301,6 +327,19 @@ endif()
1. Use `THREADSCHEDULE_RUNTIME=ON` to build a shared runtime (recommended for multi-DSO)
2. Explicitly inject the registry into each DSO via `set_external_registry()`

### Deprecation Warnings for `registry()` in Runtime Mode
**Symptom**: Enabling `THREADSCHEDULE_STABLE_ABI=ON` produces deprecation
warnings for `registry()`, `set_external_registry(ThreadRegistry*)`, or
`AutoRegisterCurrentThread`.

**Cause**: Those C++ runtime entrypoints are still usable inside a single build,
but they are not part of the stable ThreadSchedule ABI subset for exported
shared-library boundaries.

**Solution**: Keep them for internal-only code during migration, but move any
exported plugin/DSO boundary to `threadschedule::abi::*`. When the migration is
complete, switch to `THREADSCHEDULE_STABLE_ABI_STRICT=ON`.

## Advanced Configuration

### Custom Compiler Flags (Top-Level Project Only)
Expand Down Expand Up @@ -354,11 +393,9 @@ FetchContent_MakeAvailable(ThreadSchedule)
```

### Conan
See [conanfile.py](../conanfile.py) for Conan package definition.

```bash
conan create . --build=missing
```
ThreadSchedule does not currently ship a maintained in-tree Conan recipe.
Use FetchContent/CPM directly, or keep a project-local Conan recipe that pulls
the tagged Git release you want to consume.

## Best Practices

Expand All @@ -369,7 +406,9 @@ conan create . --build=missing
5. **Pin to specific version** (tag) in production
6. **Test with your target C++ standard** before deploying
7. **For multi-DSO applications**: Use `THREADSCHEDULE_RUNTIME=ON` to ensure single registry
8. **On Windows with runtime**: Copy DLLs to executable directory or use install(RUNTIME_DEPENDENCY_SET)
8. **For exported plugin/DSO ABIs**: Enable `THREADSCHEDULE_STABLE_ABI=ON` early, and move public registry-facing boundaries to `threadschedule::abi::*`
9. **Validate exported signatures**: Use `THREADSCHEDULE_VALIDATE_STABLE_ABI_EXPORT(...)` in public headers for registry-related ABI boundaries
10. **On Windows with runtime**: Copy DLLs to executable directory or use install(RUNTIME_DEPENDENCY_SET)

## Example Project Structure

Expand Down
Loading
Loading