Skip to content

[NativeAOT] Use POSIX primitives for GC bridge processing#12141

Open
simonrozsival wants to merge 6 commits into
mainfrom
dev/simonrozsival/nativeaot-posix-gc-bridge
Open

[NativeAOT] Use POSIX primitives for GC bridge processing#12141
simonrozsival wants to merge 6 commits into
mainfrom
dev/simonrozsival/nativeaot-posix-gc-bridge

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Jul 16, 2026

Copy link
Copy Markdown
Member

Summary

Replace the NativeAOT-reachable GC bridge's C++ threading primitives with POSIX primitives.

This removes the std::thread, std::binary_semaphore, and associated libc++ atomic-wait/thread runtime dependency from this subsystem as part of #12139.

Changes

  • replace the detached std::thread worker with pthread_create() / pthread_detach();
  • replace std::binary_semaphore with sem_t;
  • retry sem_wait() after EINTR;
  • preserve acquire/release synchronization for the shared callback argument with compiler atomics;
  • surface pthread/semaphore failures through the existing abort helpers;
  • document the JavaMarshal one-outstanding-round invariant that makes shared_args an intentional single-slot handoff rather than a queue.

The bridge-processing algorithm and callback lifecycle are unchanged.

Validation

  • git diff --check;
  • Release build of src/native/native-nativeaot.csproj;
  • Release build of src/native/native-clr.csproj;
  • focused concurrency review covering initialization, the one-outstanding-round contract, memory ordering, EINTR, and detached worker behavior;
  • latest head: 12bc25740.

Part of #12139.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Copilot AI review requested due to automatic review settings July 16, 2026 23:21
@simonrozsival simonrozsival added the drop-libcpp Work to remove the libc++ dependency from Android NativeAOT label Jul 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Clarify that JavaMarshal permits only one outstanding bridge round, so shared_args is intentionally a single-slot handoff.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 2 out of 2 changed files in this pull request and generated no new comments.

@simonrozsival simonrozsival added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Jul 17, 2026
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Code Review — ✅ LGTM (with minor suggestions)

Verdict: ✅ LGTM · Issues: 0 ❌ · 0 ⚠️ · 2 💡

This is a clean, well-scoped refactor that swaps the GC bridge's std::thread / std::binary_semaphore / std::atomic primitives for POSIX pthread + sem_t + compiler __atomic builtins, as part of the libc++-removal effort (#12139).

What was verified

  • Correctness of the handoff: publish_shared_args (RELEASE store + sem_post) / wait_for_shared_args (sem_wait + ACQUIRE load) preserve the acquire/release ordering of the original std::atomic. The single-slot design is safe given the documented JavaMarshal "one outstanding round" invariant.
  • EINTR handling: sem_wait is correctly retried in a loop on EINTR (native-rules Postmortem #22). 👍
  • Consistency: pthread and __atomic_* builtins are already established conventions in this codebase (assembly-store.cc, os-bridge.cc, pinvoke-override), so the approach fits in well.
  • Error handling: pthread/semaphore failures are surfaced through the existing abort_unless helpers, consistent with the rest of the host.
  • Include cleanup: removed <atomic>, <thread>, <semaphore>, <shared_mutex>, <unordered_map> — none appear to be used elsewhere in the header. 👍
  • __atomic_* are compiler builtins (not user identifiers), so the reserved-double-underscore rule doesn't apply here.

Suggestions (non-blocking, posted inline)

  1. 💡 Match assembly-store.cc's single-step detached-thread creation and consider naming the worker thread for diagnostics.
  2. 💡 A brief note that the semaphore (not the atomics) is the real synchronization point would aid future readers.

Nice, tightly-focused change with a helpful invariant comment. CI shows no required checks failing at review time.

Generated by Android PR Reviewer for #12141 · 84.2 AIC · ⌖ 13.1 AIC · ⊞ 6.8K
Comment /review to run again

void GCBridge::start_bridge_processing_thread () noexcept
{
pthread_t thread {};
int ret = pthread_create (&thread, nullptr, bridge_processing_thread_entry, nullptr);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 💡 Native C++ — Consider creating the worker already-detached via pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) before pthread_create, matching the sibling pattern in assembly-store.cc (start_writer_locked). The current create-then-pthread_detach sequence works, but a single-step detached creation is consistent with the rest of the CLR host and avoids a separate failure/abort path.

While here, pthread_setname_np (thread, "gc-bridge") would make this worker identifiable in logcat/tombstones and traces — helpful given it runs the GC bridge on every collection.

(Rule: Consistency with repo native patterns)

{
__atomic_store_n (&shared_args, args, __ATOMIC_RELEASE);

int ret = sem_post (&shared_args_semaphore);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 💡 Native C++sem_post/sem_wait already establish a happens-before relationship, so the explicit __ATOMIC_RELEASE/__ATOMIC_ACQUIRE on shared_args are technically redundant for this single-slot handoff (which the header comment nicely documents). Keeping them as belt-and-suspenders is fine, but a one-line note here that the semaphore is the real synchronization point — and the atomics just make the intent explicit — would prevent a future reader from assuming lock-free concurrent access is intended.

(Rule: Documentation of concurrency intent)

@simonrozsival
simonrozsival enabled auto-merge (squash) July 17, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drop-libcpp Work to remove the libc++ dependency from Android NativeAOT ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants