#include "compat/bionic_semaphore_runtime.h" #include #include #include #include #include #include #include #include #include #include namespace { TEST(BionicSemaphoreRuntimeTest, WaiterReleasedByPost) { alignas(sem_t) std::array guest_storage{}; auto* semaphore = reinterpret_cast(guest_storage.data()); ASSERT_EQ(mocktail_bionic_sem_init(semaphore, 0, 0), 0); std::atomic released{false}; std::thread waiter([&] { EXPECT_EQ(mocktail_bionic_sem_wait(semaphore), 0); released.store(true, std::memory_order_release); }); EXPECT_FALSE(released.load(std::memory_order_acquire)); EXPECT_EQ(mocktail_bionic_sem_post(semaphore), 0); waiter.join(); EXPECT_TRUE(released.load(std::memory_order_acquire)); EXPECT_EQ(mocktail_bionic_sem_destroy(semaphore), 0); } TEST(BionicSemaphoreRuntimeTest, SemPostWakesRawGuestFutexWait) { sem_t guest_storage{}; ASSERT_EQ(mocktail_bionic_sem_init(&guest_storage, 0, 0), 0); std::atomic waiting{false}; std::atomic wait_result{EINVAL}; std::thread waiter([&] { waiting.store(true, std::memory_order_release); EXPECT_EQ(mocktail_bionic_sem_wait(&guest_storage), 0); wait_result.store(0, std::memory_order_release); }); while (!waiting.load(std::memory_order_acquire)) { std::this_thread::yield(); } std::this_thread::sleep_for(std::chrono::milliseconds(20)); auto* count = reinterpret_cast(&guest_storage); const unsigned expected = __atomic_load_n(count, __ATOMIC_RELAXED); std::atomic raw_result{EINVAL}; std::thread raw([&] { raw_result.store( static_cast(::syscall(SYS_futex, count, FUTEX_WAIT_PRIVATE, expected, nullptr, nullptr, 0)), std::memory_order_release); }); std::this_thread::sleep_for(std::chrono::milliseconds(20)); EXPECT_EQ(mocktail_bionic_sem_post(&guest_storage), 0); waiter.join(); raw.join(); EXPECT_EQ(0, wait_result.load(std::memory_order_acquire)); EXPECT_EQ(0, raw_result.load(std::memory_order_acquire)); EXPECT_EQ(mocktail_bionic_sem_destroy(&guest_storage), 0); } TEST(BionicSemaphoreRuntimeTest, RejectsProcessSharedSemaphore) { sem_t guest_storage{}; errno = 0; EXPECT_EQ(mocktail_bionic_sem_init(&guest_storage, 1, 0), -1); EXPECT_EQ(errno, EINVAL); } } // namespace