From 611cfd851fc1169c3237aec124351358a7149e61 Mon Sep 17 00:00:00 2001 From: "David Geraghty (SEA)" Date: Thu, 21 Nov 2024 19:54:19 -0800 Subject: [PATCH] adjust memory order in Semaphore::signalSlow Summary: `signalSlow()` updates `tokens_` with a relaxed write when the wait list is empty. This won't synchronize with the acquire loads performed by calls to `wait()`. TSAN detects this: D66112566. Reviewed By: yfeldblum Differential Revision: D66114255 fbshipit-source-id: ce6f937b58fe0d004c1d4582db7e2cc3c1bfd6d6 --- folly/fibers/Semaphore.cpp | 2 +- folly/fibers/test/BUCK | 12 ++++++++ folly/fibers/test/SemaphoreTest.cpp | 46 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 folly/fibers/test/SemaphoreTest.cpp diff --git a/folly/fibers/Semaphore.cpp b/folly/fibers/Semaphore.cpp index f8dca57c2d6..f56130b7866 100644 --- a/folly/fibers/Semaphore.cpp +++ b/folly/fibers/Semaphore.cpp @@ -35,7 +35,7 @@ bool Semaphore::signalSlow() { // If the waitlist is now empty, ensure the token count increments // No need for CAS here as we will always be under the mutex CHECK(tokens_.compare_exchange_strong( - testVal, testVal + 1, std::memory_order_relaxed)); + testVal, testVal + 1, std::memory_order_release)); return true; } waiter = &waitList.front(); diff --git a/folly/fibers/test/BUCK b/folly/fibers/test/BUCK index ac88b49df01..e59e4cee070 100644 --- a/folly/fibers/test/BUCK +++ b/folly/fibers/test/BUCK @@ -72,3 +72,15 @@ cpp_binary( "//folly/init:init", ], ) + +cpp_unittest( + name = "semaphore_test", + srcs = ["SemaphoreTest.cpp"], + headers = [], + deps = [ + "//folly/fibers:semaphore", + "//folly/portability:gtest", + "//folly/synchronization:relaxed_atomic", + "//folly/synchronization/detail:sleeper", + ], +) diff --git a/folly/fibers/test/SemaphoreTest.cpp b/folly/fibers/test/SemaphoreTest.cpp new file mode 100644 index 00000000000..785e5175040 --- /dev/null +++ b/folly/fibers/test/SemaphoreTest.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +using namespace folly::fibers; + +TEST(SemaphoreTest, MessagePassing) { + int data = 0; + Semaphore sem{0}; + + // Provides no memory ordering: just used to reproduce conditions for a + // bug caught by TSAN in an earlier version of the implementation. + folly::relaxed_atomic signalled{false}; + + std::thread t{[&]() { + folly::detail::Sleeper sleeper; + while (!signalled) { + sleeper.wait(); + } + sem.wait(); + EXPECT_NE(0, data); + }}; + + data = 1; + sem.signal(); + signalled = true; + + t.join(); +}