Skip to content

sync: fix ordering in Once and ManyTimes -- store count after f() completes#27490

Merged
JalonSolov merged 4 commits into
vlang:masterfrom
quaesitor-scientiam:master
Jun 22, 2026
Merged

sync: fix ordering in Once and ManyTimes -- store count after f() completes#27490
JalonSolov merged 4 commits into
vlang:masterfrom
quaesitor-scientiam:master

Conversation

@quaesitor-scientiam

@quaesitor-scientiam quaesitor-scientiam commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Both sync.Once and sync.ManyTimes had the same ordering bug: do_slow incremented count (or set done) before calling f(), so a concurrent goroutine could observe the updated count on the atomic fast path in do() and return while f() was still executing.

  • Commit 1 — Once: move done = 1 store to after f() returns
  • Commit 2 — ManyTimes: move stdatomic.store_u64 to after f() returns

Fixes: #27489

Test plan

  • test_once_ordering / test_once_with_param_ordering in vlib/sync/once_test.v and once_with_param_test.v
  • test_many_times_ordering added to vlib/sync/many_times_test.v — a concurrency ordering test: a slow f() signals on a channel then sleeps 50 ms before setting a value; a second concurrent do() must not return until f() has completed
  • All existing tests in vlib/sync/ pass
  • vfmt clean on all changed files

🧙 Built with WOZCODE

quaesitor-scientiam and others added 2 commits June 18, 2026 12:35
…efore

Previously do_slow/do_slow_with_param set count=1 before calling f(),
so a concurrent goroutine could observe count==1 on the fast path and
return from do() while f() was still executing. This broke the
fundamental Once guarantee that when do() returns, f() side effects
are visible.

Fix: move the stdatomic.store_u64 to after f() returns, matching the
ordering used by Go sync.Once. Concurrent callers that arrive while
f() is running now correctly block on the mutex until f() completes.

Adds a test that would fail with the old ordering: the second
do_with_param call must not return until slow_init has set its value.

Fixes vlang#27456.

Co-Authored-By: WOZCODE <contact@withwoz.com>
…before

The same ordering bug fixed in sync.Once (see vlang#27456): `do_slow`
was incrementing `count` before calling `f()`, so a concurrent goroutine
could observe `count >= times` on the atomic fast path and return from
`do` while `f()` was still executing.

Move `stdatomic.store_u64` to after `f()` so that `count` is only
incremented once the work is complete.  Adds a concurrency ordering test
analogous to `test_once_with_param_ordering` in `once_with_param_test.v`.

Co-Authored-By: WOZCODE <contact@withwoz.com>
@quaesitor-scientiam quaesitor-scientiam changed the title sync: fix Once ordering -- store done flag after f() completes, not before sync: fix ordering in Once and ManyTimes -- store count after f() completes Jun 18, 2026
@JalonSolov

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 206d7f0c32

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@JalonSolov

Copy link
Copy Markdown
Collaborator

Bouncing to pick up latest changes at master...

@JalonSolov JalonSolov closed this Jun 19, 2026
@JalonSolov JalonSolov reopened this Jun 19, 2026
@quaesitor-scientiam

Copy link
Copy Markdown
Contributor Author

Confirmed CIs failures not related to this PR

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.

sync: ManyTimes.do_slow stores count before calling f(), same ordering race as Once (#27456)

2 participants