blob: 24f041aeda896b0ec0bef485f3e48cb394e09090 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_TESTS_MICROBENCHMARKS_SIMPLE_LATCH_H_
#define SRC_TESTS_MICROBENCHMARKS_SIMPLE_LATCH_H_
#include <sys/syscall.h>
#include <unistd.h>
#include <atomic>
#include <linux/futex.h>
#include "lib/syslog/cpp/macros.h"
// A wrapper for the futex system call, that only supports FUTEX_WAIT and
// FUTEX_WAKE, without timeout.
inline long SimpleFutex(std::atomic<uint32_t>* uaddr, int futex_op, uint32_t val) {
return syscall(SYS_futex, reinterpret_cast<uint32_t*>(uaddr), futex_op, val, NULL, NULL, 0);
}
// A class similar to std::latch that works across processes.
// std::latch is not guaranteed to work across processes.
class SimpleLatch {
public:
SimpleLatch(size_t expected) : pending_(expected), done_(0) { FX_CHECK(expected > 0); }
// Decrement the counter atomically, in a non-blocking manner.
void CountDown() {
if (pending_.fetch_sub(1) == 1) {
done_ = 1;
long res = SimpleFutex(&done_, FUTEX_WAKE, INT_MAX);
FX_CHECK(res >= 0);
}
}
// Blocks until the counter reaches 0.
void Wait() {
while (done_ == 0) {
long res = SimpleFutex(&done_, FUTEX_WAIT, 0);
FX_CHECK(res == 0 || (res == -1 && errno == EAGAIN));
}
FX_CHECK(pending_ == 0);
}
SimpleLatch(const SimpleLatch&) = delete;
SimpleLatch& operator=(const SimpleLatch&) = delete;
private:
std::atomic<size_t> pending_;
std::atomic<uint32_t> done_;
};
#endif // SRC_TESTS_MICROBENCHMARKS_SIMPLE_LATCH_H_