blob: a7174719cc95b7bb35c44f6d6bc8961e1489d97d [file] [log] [blame]
// Copyright 2021 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 LIB_CONCURRENT_SEQLOCK_H_
#define LIB_CONCURRENT_SEQLOCK_H_
#include <lib/concurrent/common.h>
#include <lib/concurrent/seqlock_payload.h>
#include <zircon/compiler.h>
#include <zircon/time.h>
#include <atomic>
namespace concurrent {
namespace internal {
template <typename Osal, SyncOpt _kSyncOpt = SyncOpt::AcqRelOps>
class __TA_CAPABILITY("mutex") SeqLock {
public:
static constexpr SyncOpt kSyncOpt = _kSyncOpt;
static constexpr SyncOpt kCopyWrapperSyncOpt =
(kSyncOpt == SyncOpt::AcqRelOps) ? SyncOpt::AcqRelOps : SyncOpt::None;
using SequenceNumber = uint32_t;
class ReadTransactionToken {
public:
ReadTransactionToken() : seq_num_(1) {}
SequenceNumber seq_num() const { return seq_num_; }
private:
friend class SeqLock;
explicit ReadTransactionToken(SequenceNumber num) : seq_num_(num) {}
SequenceNumber seq_num_;
};
SeqLock() {
static_assert((kSyncOpt == SyncOpt::AcqRelOps) || (kSyncOpt == SyncOpt::Fence),
"The synchronization options chosen for a SeqLock must be "
"either Acquire/Release, or Fence");
}
~SeqLock() = default;
// No copy, no move
SeqLock(const SeqLock&) = delete;
SeqLock(SeqLock&&) = delete;
SeqLock& operator=(const SeqLock&) = delete;
SeqLock& operator=(SeqLock&&);
// Provide read access to the current seq_num state. Mostly for testing.
SequenceNumber seq_num(std::memory_order order = std::memory_order_relaxed) const {
return seq_num_.load(order);
}
// Read Transactions (eg; "locking" for read)
ReadTransactionToken BeginReadTransaction() __TA_ACQUIRE_SHARED();
bool TryBeginReadTransaction(ReadTransactionToken& out_token, zx_duration_t timeout = 0)
__TA_TRY_ACQUIRE_SHARED(true);
bool TryBeginReadTransactionDeadline(ReadTransactionToken& out_token, zx_time_t deadline)
__TA_TRY_ACQUIRE_SHARED(true);
bool EndReadTransaction(ReadTransactionToken token) __TA_RELEASE_SHARED();
// Exclusive locking.
void Acquire() __TA_ACQUIRE();
bool TryAcquire(zx_duration_t timeout = 0) __TA_TRY_ACQUIRE(true);
bool TryAcquireDeadline(zx_time_t deadline) __TA_TRY_ACQUIRE(true);
void Release() __TA_RELEASE();
private:
std::atomic<SequenceNumber> seq_num_{0};
};
} // namespace internal
#if defined(__Fuchsia__) && !defined(_KERNEL)
////////////////////////
// Fuchsia User Mode
////////////////////////
namespace internal {
struct FuchsiaUserModeOsal;
}
template <SyncOpt kSyncOpt = SyncOpt::AcqRelOps>
using SeqLock = internal::SeqLock<internal::FuchsiaUserModeOsal, kSyncOpt>;
#else
////////////////////////
// POSIX fallback
////////////////////////
namespace internal {
struct PosixUserModeOsal;
}
template <SyncOpt kSyncOpt = SyncOpt::AcqRelOps>
using SeqLock = internal::SeqLock<internal::PosixUserModeOsal, kSyncOpt>;
#endif
} // namespace concurrent
#endif // LIB_CONCURRENT_SEQLOCK_H_