blob: 98d03f1bcfab5c5dde62933bbfaf93d410c972e7 [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_COMMON_H_
#define LIB_CONCURRENT_COMMON_H_
#include <stdint.h>
#include <zircon/assert.h>
#include <memory>
namespace concurrent {
// An enumeration of various synchronization options to use when performing
// memory transfer operations with WellDefinedCopy(To|From).
//
// :: AcqRelOps ::
// Use either memory_order_acquire (CopyFrom) or memory_order_release (CopyTo)
// on every atomic load/store operation during the transfer to/from the shared
// buffer.
//
// :: Fence ::
// Use either a memory_order_acquire thread fence (CopyFrom) after the transfer
// operation, or a memory_order_release (CopyTo) thread fence before the
// operation, and memory_order_relaxed for each of the atomic load/store
// operations during the transfer.
//
// :: None ::
// Simply use memory_order_relaxed for each of the atomic load/store
// operations during the transfer. Do not actually introduce any
// explicit synchronization behavior.
//
// WARNING: Use cases for this transfer mode tend to unusual. Users will almost
// always want some form of synchronization to take place during their
// transfers. One example of where it may be appropriate to use SyncOpt::None
// might be a situation where users are attempting to observe the state of more
// than one object while inside of a sequence lock read transaction, and the
// user has decided that it is better to use a thread fence than to use acquire
// semantics on each element transferred. Such a sequence might look something
// like this:
//
// Foo foo1, foo2;
// Bar bar1, bar2;
// ...
// WellDefinedCopyFrom<SyncOpt::None, alignof(Foo)>(&foo1, &src_foo1, sizeof(foo1));
// WellDefinedCopyFrom<SyncOpt::None, alignof(Foo)>(&foo2, &src_foo2, sizeof(foo2));
// WellDefinedCopyFrom<SyncOpt::None, alignof(Foo)>(&bar1, &src_bar1, sizeof(bar1));
// WellDefinedCopyFrom<SyncOpt::Fence, alignof(Foo)>(&bar2, &src_bar2, sizeof(bar2));
//
// Note that it is the _last_ transfer operation which includes the fence. In
// the case of a CopyTo operation (when publishing data) it would be the _first_
// operation which included the fence, not the last.
enum class SyncOpt { AcqRelOps, Fence, None };
// Define tag types and constexpr instances of them which allow us to parameter
// based template deduction. Mostly, this is about working around some of C++'s
// otherwise painful syntax. It allows us to say:
//
// WellDefinedCopyable<Foo> wrapped_foo;
// Foo foo;
// wrapped_foo.CopyFrom(foo, SyncOpt_Fence); // This
// wrapped_foo.template CopyFrom<SyncOpt::Fence>(foo); // Instead of this
//
// Without this, having to put the `template` keyword after the `.` but before
// the `<>`'s is just a sad and painful fact of C++ template lyfe.
template <SyncOpt>
struct SyncOptType {};
constexpr SyncOptType<SyncOpt::AcqRelOps> SyncOpt_AcqRelOps;
constexpr SyncOptType<SyncOpt::Fence> SyncOpt_Fence;
constexpr SyncOptType<SyncOpt::None> SyncOpt_None;
namespace internal {
constexpr size_t kMaxTransferGranularity = sizeof(uint64_t);
enum class CopyDir { To, From };
enum class MaxTransferAligned { No, Yes };
} // namespace internal
} // namespace concurrent
#endif // LIB_CONCURRENT_COMMON_H_