blob: ac32b1a74e37b18b0cc19b6418083e1e0501ed1e [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 LIB_CONCURRENT_SEQLOCK_PAYLOAD_H_
#define LIB_CONCURRENT_SEQLOCK_PAYLOAD_H_
#include <lib/concurrent/common.h>
#include <lib/concurrent/copy.h>
namespace concurrent {
template <typename T, typename SeqLockType>
class SeqLockPayload : protected WellDefinedCopyable<T> {
public:
// The sync options we use for this payload are specified for us based on the
// lock type we plan to use this payload with.
static constexpr SyncOpt kCopySyncOpt = SeqLockType::kCopyWrapperSyncOpt;
// Forwarding constructor for our payload, and an explicitly default destructor.
template <typename... Args>
SeqLockPayload(Args&&... args) : WellDefinedCopyable<T>(std::forward<Args>(args)...) {
// The payload sync option selected by the lock should always be AcqRelOps,
// or None (in the case where the lock is using fences). Assert this at
// compile time.
static_assert((kCopySyncOpt == SyncOpt::AcqRelOps) || (kCopySyncOpt == SyncOpt::None));
}
~SeqLockPayload() = default;
// No copy, no move
SeqLockPayload(const SeqLockPayload<T, SeqLockType>&) = delete;
SeqLockPayload(SeqLockPayload<T, SeqLockType>&&) = delete;
SeqLockPayload<T, SeqLockType>& operator=(const SeqLockPayload<T, SeqLockType>&) = delete;
SeqLockPayload<T, SeqLockType>& operator=(SeqLockPayload<T, SeqLockType>&&) = delete;
// Specific versions of Read/Update which always use the sync-opt dictated to
// us by our associated lock type.
void Read(T& dst) const { WellDefinedCopyable<T>::template Read<kCopySyncOpt>(dst); }
void Update(const T& src) { WellDefinedCopyable<T>::template Update<kCopySyncOpt>(src); }
// Gain R/W access to the payload in order to perform an in-place update of
// the contents fence-to-fence synchronization to protect the payload. All
// stores to the payload accessed via this reference should be done using
// relaxed atomic stores.
T& BeginInPlaceUpdate() {
static_assert(SeqLockType::kSyncOpt == SyncOpt::Fence,
"In-place updates can only be performed when using fence synchronization");
return WellDefinedCopyable<T>::instance_;
}
// Finally, manually expose the |unsynchronized_get| from our base class.
using WellDefinedCopyable<T>::unsynchronized_get;
};
} // namespace concurrent
#endif // LIB_CONCURRENT_SEQLOCK_PAYLOAD_H_