Skip to content

GDAL v3.13.1 + thread-safe GdalBase - #232

Merged
MaxRev-Dev merged 7 commits into
mainfrom
release/v3.13.1
Jun 11, 2026
Merged

GDAL v3.13.1 + thread-safe GdalBase#232
MaxRev-Dev merged 7 commits into
mainfrom
release/v3.13.1

Conversation

@MaxRev-Dev

@MaxRev-Dev MaxRev-Dev commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Bump GDAL to 3.13.1 (shared/GdalCore.opt).
  • Refactor GdalBase initialization to use double-checked locking so concurrent callers no longer race into the native Gdal.AllRegister / Ogr.RegisterAll registration path.
  • Add BinaryLoadingTests.ConfigureAll_IsThreadSafe covering 16 concurrent callers gated by a Barrier.

Implementation notes

  • Public API is unchanged: IsConfigured is now an expression-bodied getter over a volatile bool backing field; lock is a private object.
  • ConfigureGdalDrivers and ConfigureAll both follow the DCL pattern (fast-path read -> lock -> re-check). C# lock is reentrant so ConfigureAll -> ConfigureGdalDrivers does not deadlock.
  • ConfigureGdalData is unchanged - it just forwards to Gdal.SetConfigOption which is already idempotent.

Test plan

  • dotnet build package-build/gdalcore.loader.final.csproj -c Release -> 0 warnings, 0 errors across netstandard2.0/2.1, net461, net6/7/8/9/10
  • dotnet build tests/MaxRev.Gdal.Core.Tests.XUnit/MaxRev.Gdal.Core.Tests.XUnit.csproj -c Release -> 0 errors (only pre-existing NU1603 nuget resolution warnings)
  • CI must produce v3.13.1 native runtime packages, then full XUnit suite (incl. new thread-safety test) on Linux/macOS/Windows

@MaxRev-Dev
MaxRev-Dev marked this pull request as ready for review June 8, 2026 21:29
Apply double-checked locking to ConfigureGdalDrivers and ConfigureAll so
parallel callers no longer race into native AllRegister/RegisterAll. The
public IsConfigured property is preserved; the backing flag is now a
volatile bool guarded by a private lock object.

Add a concurrent-callers test to BinaryLoadingTests that fans 16 threads
through a Barrier and asserts the registered driver count remains stable.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the build configuration to GDAL v3.13.1 and refactors GdalBase initialization to reduce races when multiple callers initialize GDAL concurrently, adding an XUnit test to exercise concurrent ConfigureAll() calls.

Changes:

  • Bump GDAL version to 3.13.1 in shared build options.
  • Add locking + volatile flag to make GdalBase.ConfigureGdalDrivers() / ConfigureAll() safe under concurrent access.
  • Add ConfigureAll_IsThreadSafe test that runs 16 concurrent callers gated by a Barrier.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
shared/GdalCore.opt Updates GDAL_VERSION to 3.13.1 for the native/runtime build pipeline.
compile/GdalConfigureAll.cs Adds locking/volatile state to avoid concurrent native driver registration.
tests/MaxRev.Gdal.Core.Tests.XUnit/BinaryLoadingTests.cs Adds a concurrency test to validate ConfigureAll() under contention.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread compile/GdalConfigureAll.cs
Comment thread tests/MaxRev.Gdal.Core.Tests.XUnit/BinaryLoadingTests.cs
Address PR #232 review feedback:

- ConfigureAll() now gates its fast-path on a dedicated _isFullyConfigured
  flag instead of _isConfigured. _isConfigured is set inside
  ConfigureGdalDrivers() before Proj.Configure() runs, so concurrent callers
  could return on the fast-path while the first thread was still configuring
  PROJ inside the lock - using PROJ before search paths were set.
  _isFullyConfigured is set only after Proj.Configure() completes.

- ConfigureAll_IsThreadSafe test: barrier.SignalAndWait() now uses a 30s
  timeout and throws TimeoutException instead of hanging indefinitely if a
  task dies before reaching the barrier, making failures deterministic.
Async counterpart of GdalCli.Run. Spawns the tool, reads stdout/stderr
concurrently (avoiding the latent pipe-buffer deadlock in the sync path),
awaits exit, and reports output via the existing Action<string> callbacks.

- Supports CancellationToken: on cancellation the tool is terminated
  (TryKill) and OperationCanceledException is surfaced after draining the
  pending reads.
- Cross-framework exit wait: uses Process.WaitForExitAsync on net5.0+, and a
  TaskCompletionSource + Process.Exited fallback on netstandard2.0/2.1 (the
  shipped CLI target) where WaitForExitAsync is unavailable.
- Tests.CLI smoke test now also exercises the async path.
No win-arm64 native runtime is shipped; Windows on ARM64 runs the win-x64
build via emulation. This makes PathInitializer.GetRuntimeNativeDirectory
consistent with GdalCli.GetRuntimeRid, which already returns win-x64 for all
Windows architectures.
The previous comment claimed Windows ARM64 runs the win-x64 build 'via
emulation'. That is misleading: emulation is a per-process decision, and
x64 native libraries load only into an x64 process (including an
x64-emulated process on Windows ARM64), never into a natively-running
ARM64 process. Behavior is unchanged - win-x64 is still the only Windows
native runtime shipped; only the explanation is corrected.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread shared/msbuild/MaxRev.Gdal.CLI.Helpers.cs
Address PR #232 review: the synchronous Run() read stdout to completion
before stderr, which can deadlock if the tool fills its stderr pipe buffer
while Run() is blocked reading stdout. Now starts both ReadToEndAsync reads
before WaitForExit (mirrors RunAsync), so neither pipe can block the tool.
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.

2 participants