*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
-#include "folly/AtomicStruct.h"
-#include "folly/Baton.h"
-#include "folly/IndexedMemPool.h"
-#include "folly/Likely.h"
-#include "folly/detail/CacheLocality.h"
+#include <folly/AtomicStruct.h>
+#include <folly/Baton.h>
+#include <folly/CachelinePadded.h>
+#include <folly/IndexedMemPool.h>
+#include <folly/Likely.h>
-template <template<typename> class Atom = std::atomic,
- class BatonType = Baton<Atom>>
+template <
+ template <typename> class Atom = std::atomic,
+ class BatonType = Baton<Atom>>
/// The exception thrown when wait()ing on an isShutdown() LifoSem
struct ShutdownSemError : public std::runtime_error {
explicit ShutdownSemError(const std::string& msg);
/// The exception thrown when wait()ing on an isShutdown() LifoSem
struct ShutdownSemError : public std::runtime_error {
explicit ShutdownSemError(const std::string& msg);
/// LifoSemRawNode is the actual pooled storage that backs LifoSemNode
/// for user-specified Handoff types. This is done so that we can have
/// a large static IndexedMemPool of nodes, instead of per-type pools
/// LifoSemRawNode is the actual pooled storage that backs LifoSemNode
/// for user-specified Handoff types. This is done so that we can have
/// a large static IndexedMemPool of nodes, instead of per-type pools
typedef folly::IndexedMemPool<LifoSemRawNode<Atom>,32,200,Atom> Pool;
/// Storage for all of the waiter nodes for LifoSem-s that use Atom
typedef folly::IndexedMemPool<LifoSemRawNode<Atom>,32,200,Atom> Pool;
/// Storage for all of the waiter nodes for LifoSem-s that use Atom
};
/// Use this macro to declare the static storage that backs the raw nodes
/// for the specified atomic type
};
/// Use this macro to declare the static storage that backs the raw nodes
/// for the specified atomic type
-#define LIFOSEM_DECLARE_POOL(Atom, capacity) \
- template<> \
- folly::detail::LifoSemRawNode<Atom>::Pool \
- folly::detail::LifoSemRawNode<Atom>::pool((capacity));
+#define LIFOSEM_DECLARE_POOL(Atom, capacity) \
+ namespace folly { \
+ namespace detail { \
+ template <> \
+ LifoSemRawNode<Atom>::Pool& LifoSemRawNode<Atom>::pool() { \
+ static Pool* instance = new Pool((capacity)); \
+ return *instance; \
+ } \
+ } \
+ }
/// Handoff is a type not bigger than a void* that knows how to perform a
/// single post() -> wait() communication. It must have a post() method.
/// If it has a wait() method then LifoSemBase's wait() implementation
/// will work out of the box, otherwise you will need to specialize
/// LifoSemBase::wait accordingly.
/// Handoff is a type not bigger than a void* that knows how to perform a
/// single post() -> wait() communication. It must have a post() method.
/// If it has a wait() method then LifoSemBase's wait() implementation
/// will work out of the box, otherwise you will need to specialize
/// LifoSemBase::wait accordingly.
struct LifoSemNode : public LifoSemRawNode<Atom> {
static_assert(sizeof(Handoff) <= sizeof(LifoSemRawNode<Atom>::raw),
struct LifoSemNode : public LifoSemRawNode<Atom> {
static_assert(sizeof(Handoff) <= sizeof(LifoSemRawNode<Atom>::raw),
struct LifoSemNodeRecycler {
void operator()(LifoSemNode<Handoff,Atom>* elem) const {
elem->destroy();
struct LifoSemNodeRecycler {
void operator()(LifoSemNode<Handoff,Atom>* elem) const {
elem->destroy();
- auto idx = LifoSemRawNode<Atom>::pool.locateElem(elem);
- LifoSemRawNode<Atom>::pool.recycleIndex(idx);
+ auto idx = LifoSemRawNode<Atom>::pool().locateElem(elem);
+ LifoSemRawNode<Atom>::pool().recycleIndex(idx);
///
/// The Handoff type is responsible for arranging one wakeup notification.
/// See LifoSemNode for more information on how to make your own.
///
/// The Handoff type is responsible for arranging one wakeup notification.
/// See LifoSemNode for more information on how to make your own.
-template <typename Handoff,
- template<typename> class Atom = std::atomic>
-struct LifoSemBase : boost::noncopyable {
+template <typename Handoff, template <typename> class Atom = std::atomic>
+struct LifoSemBase {
- explicit LifoSemBase(uint32_t initialValue = 0)
- : head_(LifoSemHead::fresh(initialValue)) {}
+ constexpr explicit LifoSemBase(uint32_t initialValue = 0)
+ : head_(LifoSemHead::fresh(initialValue)) {}
+
+ LifoSemBase(LifoSemBase const&) = delete;
+ LifoSemBase& operator=(LifoSemBase const&) = delete;
// successful pop, wake up the waiter and move on. The next
// field is used to convey that this wakeup didn't consume a value
node.setShutdownNotice();
// successful pop, wake up the waiter and move on. The next
// field is used to convey that this wakeup didn't consume a value
node.setShutdownNotice();
// this is actually linearizable, but we don't promise that because
// we may want to add striping in the future to help under heavy
// contention
// this is actually linearizable, but we don't promise that because
// we may want to add striping in the future to help under heavy
// contention
/// Returns a node that can be passed to decrOrLink
template <typename... Args>
UniquePtr allocateNode(Args&&... args) {
/// Returns a node that can be passed to decrOrLink
template <typename... Args>
UniquePtr allocateNode(Args&&... args) {
if (idx != 0) {
auto& node = idxToNode(idx);
node.clearShutdownNotice();
try {
node.init(std::forward<Args>(args)...);
} catch (...) {
if (idx != 0) {
auto& node = idxToNode(idx);
node.clearShutdownNotice();
try {
node.init(std::forward<Args>(args)...);
} catch (...) {
-
- folly::AtomicStruct<LifoSemHead,Atom> head_
- FOLLY_ALIGN_TO_AVOID_FALSE_SHARING;
-
- char padding_[folly::detail::CacheLocality::kFalseSharingRange -
- sizeof(LifoSemHead)];
-
+ CachelinePadded<folly::AtomicStruct<LifoSemHead, Atom>> head_;
return *static_cast<LifoSemNode<Handoff, Atom>*>(raw);
}
static uint32_t nodeToIdx(const LifoSemNode<Handoff, Atom>& node) {
return *static_cast<LifoSemNode<Handoff, Atom>*>(raw);
}
static uint32_t nodeToIdx(const LifoSemNode<Handoff, Atom>& node) {
if (!head.isNodeIdx() && head.value() > 0) {
// decr
auto delta = std::min(n, head.value());
if (!head.isNodeIdx() && head.value() > 0) {
// decr
auto delta = std::min(n, head.value());