Initial Commit - Lesson 31 (Commit #1)
This commit is contained in:
200
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/freelist.cpp
vendored
Normal file
200
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/freelist.cpp
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// ©2014 Cameron Desrochers
|
||||
|
||||
#include "relacy/relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
template <typename N>
|
||||
struct FreeListNode
|
||||
{
|
||||
FreeListNode() : freeListRefs(0), freeListNext(nullptr) { }
|
||||
|
||||
std::atomic<std::uint32_t> freeListRefs;
|
||||
std::atomic<N*> freeListNext;
|
||||
};
|
||||
|
||||
// A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention,
|
||||
// but simple and correct (assuming nodes are never freed until after the free list is destroyed),
|
||||
// and fairly speedy under low contention.
|
||||
template<typename N> // N must inherit FreeListNode or have the same fields (and initialization)
|
||||
struct FreeList
|
||||
{
|
||||
FreeList() : freeListHead(nullptr) { }
|
||||
|
||||
inline void add(N* node)
|
||||
{
|
||||
// We know that the should-be-on-freelist bit is 0 at this point, so it's safe to
|
||||
// set it using a fetch_add
|
||||
if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) {
|
||||
// Oh look! We were the last ones referencing this node, and we know
|
||||
// we want to add it to the free list, so let's do it!
|
||||
add_knowing_refcount_is_zero(node);
|
||||
}
|
||||
}
|
||||
|
||||
inline N* try_get()
|
||||
{
|
||||
auto head = freeListHead.load(std::memory_order_acquire);
|
||||
while (head != nullptr) {
|
||||
auto prevHead = head;
|
||||
auto refs = head->freeListRefs.load(std::memory_order_relaxed);
|
||||
if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1,
|
||||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||||
head = freeListHead.load(std::memory_order_acquire);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Good, reference count has been incremented (it wasn't at zero), which means
|
||||
// we can read the next and not worry about it changing between now and the time
|
||||
// we do the CAS
|
||||
auto next = head->freeListNext.load(std::memory_order_relaxed);
|
||||
if (freeListHead.compare_exchange_strong(head, next,
|
||||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||||
// Yay, got the node. This means it was on the list, which means
|
||||
// shouldBeOnFreeList must be false no matter the refcount (because
|
||||
// nobody else knows it's been taken off yet, it can't have been put back on).
|
||||
RL_ASSERT((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0);
|
||||
|
||||
// Decrease refcount twice, once for our ref, and once for the list's ref
|
||||
head->freeListRefs.fetch_add(-2, std::memory_order_release);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
// OK, the head must have changed on us, but we still need to decrease the refcount we
|
||||
// increased.
|
||||
// Note that we don't need to release any memory effects, but we do need to ensure that the reference
|
||||
// count decrement happens-after the CAS on the head.
|
||||
refs = prevHead->freeListRefs.fetch_add(-1, std::memory_order_acq_rel);
|
||||
if (refs == SHOULD_BE_ON_FREELIST + 1) {
|
||||
add_knowing_refcount_is_zero(prevHead);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes)
|
||||
N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); }
|
||||
|
||||
private:
|
||||
inline void add_knowing_refcount_is_zero(N* node)
|
||||
{
|
||||
// Since the refcount is zero, and nobody can increase it once it's zero (except us, and we
|
||||
// run only one copy of this method per node at a time, i.e. the single thread case), then we
|
||||
// know we can safely change the next pointer of the node; however, once the refcount is back
|
||||
// above zero, then other threads could increase it (happens under heavy contention, when the
|
||||
// refcount goes to zero in between a load and a refcount increment of a node in try_get, then
|
||||
// back up to something non-zero, then the refcount increment is done by the other thread) --
|
||||
// so, if the CAS to add the node to the actual list fails, decrease the refcount and leave
|
||||
// the add operation to the next thread who puts the refcount back at zero (which could be us,
|
||||
// hence the loop).
|
||||
auto head = freeListHead.load(std::memory_order_relaxed);
|
||||
while (true) {
|
||||
node->freeListNext.store(head, std::memory_order_relaxed);
|
||||
node->freeListRefs.store(1, std::memory_order_release);
|
||||
if (!freeListHead.compare_exchange_strong(head, node,
|
||||
std::memory_order_release, std::memory_order_relaxed)) {
|
||||
// Hmm, the add failed, but we can only try again when the refcount goes back to zero
|
||||
if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const std::uint32_t REFS_MASK = 0x7FFFFFFF;
|
||||
static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;
|
||||
|
||||
// Implemented like a stack, but where node order doesn't matter (nodes are
|
||||
// inserted out of order under contention)
|
||||
std::atomic<N*> freeListHead;
|
||||
};
|
||||
|
||||
|
||||
struct TestNode : FreeListNode<TestNode>
|
||||
{
|
||||
int value;
|
||||
TestNode() { }
|
||||
explicit TestNode(int value) : value(value) { }
|
||||
};
|
||||
|
||||
struct basic_test : rl::test_suite<basic_test, 2>
|
||||
{
|
||||
FreeList<TestNode> freeList;
|
||||
TestNode initialNodes[2];
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
TestNode* node = &initialNodes[tid];
|
||||
node->value = tid;
|
||||
freeList.add(node);
|
||||
|
||||
node = freeList.try_get();
|
||||
if (node != nullptr) {
|
||||
freeList.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct full_test : rl::test_suite<full_test, 4>
|
||||
{
|
||||
FreeList<TestNode> freeList;
|
||||
TestNode initialNodes[6];
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
TestNode* node;
|
||||
int myNodeCount = tid >= 4 ? 2 : 1;
|
||||
for (int i = 0; i != myNodeCount; ++i) {
|
||||
node = &initialNodes[tid + (tid >= 5 ? 1 : 0) + i];
|
||||
node->value = tid;
|
||||
freeList.add(node);
|
||||
}
|
||||
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
node = freeList.try_get();
|
||||
if (node != nullptr) {
|
||||
freeList.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params params;
|
||||
//params.search_type = rl::sched_full;
|
||||
//params.iteration_count = 100000000;
|
||||
params.search_type = rl::sched_random;
|
||||
params.iteration_count = 1000000;
|
||||
rl::simulate<basic_test>(params);
|
||||
rl::simulate<full_test>(params);
|
||||
|
||||
return 0;
|
||||
}
|
||||
722
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/integrated.cpp
vendored
Normal file
722
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/integrated.cpp
vendored
Normal file
@@ -0,0 +1,722 @@
|
||||
// ©2015 Cameron Desrochers
|
||||
|
||||
// Tests various parts of the queue using the actual
|
||||
// full implementation itself, instead of isolated
|
||||
// components. This is much slower, but provides much
|
||||
// better coverage too.
|
||||
|
||||
#define MCDBGQ_USE_RELACY
|
||||
#include "../../concurrentqueue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace moodycamel;
|
||||
|
||||
struct SmallConstantTraits : public ConcurrentQueueDefaultTraits
|
||||
{
|
||||
static const size_t BLOCK_SIZE = 2;
|
||||
static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 2;
|
||||
static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 2;
|
||||
static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 1;
|
||||
static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 2;
|
||||
};
|
||||
|
||||
struct MediumConstantTraits : public ConcurrentQueueDefaultTraits
|
||||
{
|
||||
static const size_t BLOCK_SIZE = 4;
|
||||
static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 2;
|
||||
static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 4;
|
||||
static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 2;
|
||||
static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 4;
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
static int& ctorCount() { static int c; return c; }
|
||||
static int& dtorCount() { static int c; return c; }
|
||||
static void reset() { ctorCount() = 0; dtorCount() = 0; }
|
||||
|
||||
Foo()
|
||||
: id(-2)
|
||||
{
|
||||
++ctorCount();
|
||||
}
|
||||
|
||||
Foo(int id)
|
||||
: id(id)
|
||||
{
|
||||
++ctorCount();
|
||||
}
|
||||
|
||||
Foo(Foo const& o)
|
||||
: id(o.id)
|
||||
{
|
||||
++ctorCount();
|
||||
}
|
||||
|
||||
~Foo()
|
||||
{
|
||||
RL_ASSERT(id != -1);
|
||||
++dtorCount();
|
||||
id = -1;
|
||||
}
|
||||
|
||||
public:
|
||||
int id;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct enqueue_explicit_one : rl::test_suite<enqueue_explicit_one, 2>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
ProducerToken t(q);
|
||||
q.enqueue(t, tid);
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int tid0, tid1;
|
||||
RL_ASSERT(q.try_dequeue(tid0));
|
||||
RL_ASSERT(tid0 == 0 || tid0 == 1);
|
||||
RL_ASSERT(q.try_dequeue(tid1));
|
||||
RL_ASSERT(tid1 == 0 || tid1 == 1);
|
||||
RL_ASSERT(tid0 != tid1);
|
||||
RL_ASSERT(!q.try_dequeue(tid0));
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct enqueue_explicit_many : rl::test_suite<enqueue_explicit_many, 3>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
ProducerToken t(q);
|
||||
for (int i = 0; i != 5; ++i) {
|
||||
q.enqueue(t, tid * 10 + i);
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
for (int i = 0; i != 15; ++i) {
|
||||
RL_ASSERT(q.try_dequeue(item));
|
||||
}
|
||||
RL_ASSERT(!q.try_dequeue(item));
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This one caught a bug with the memory ordering in the core dequeue algorithm
|
||||
struct dequeue_some_explicit : rl::test_suite<dequeue_some_explicit, 3>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid <= 1) {
|
||||
int item;
|
||||
ConsumerToken t(q);
|
||||
for (int i = 0; i != 5; ++i) {
|
||||
q.try_dequeue(t, item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ProducerToken t(q);
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
q.enqueue(t, tid * 10 + i);
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Causes blocks to be reused
|
||||
struct recycle_blocks_explicit : rl::test_suite<recycle_blocks_explicit, 3>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(8, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid == 0) {
|
||||
ProducerToken t(q);
|
||||
for (int i = 0; i != 8; ++i) {
|
||||
q.enqueue(t, i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int item;
|
||||
ConsumerToken t(q);
|
||||
for (int i = 0; i != 6; ++i) {
|
||||
if (q.try_dequeue(t, item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Causes the explicit producer's block index to expand
|
||||
struct expand_block_index_explicit : rl::test_suite<expand_block_index_explicit, 4>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(12, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid == 0) {
|
||||
ProducerToken t(q);
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
q.enqueue(t, i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int item;
|
||||
ConsumerToken t(q);
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
if (q.try_dequeue(t, item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Tests that implicit producers work at a very basic level
|
||||
struct enqueue_implicit_one : rl::test_suite<enqueue_implicit_one, 2>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
q.enqueue(tid);
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int tid0, tid1;
|
||||
RL_ASSERT(q.try_dequeue(tid0));
|
||||
RL_ASSERT(tid0 == 0 || tid0 == 1);
|
||||
RL_ASSERT(q.try_dequeue(tid1));
|
||||
RL_ASSERT(tid1 == 0 || tid1 == 1);
|
||||
RL_ASSERT(tid0 != tid1);
|
||||
RL_ASSERT(!q.try_dequeue(tid0));
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Tests implicit producer at a simple level
|
||||
struct implicit_simple : rl::test_suite<implicit_simple, 3>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(5, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid == 0) {
|
||||
for (int i = 0; i != 5; ++i) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int item;
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
if (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Tests multiple implicit producers being created (stresses the implicit producer hash map)
|
||||
struct many_implicit_producers : rl::test_suite<many_implicit_producers, 6>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(18, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
q.enqueue(tid * 3 + 0);
|
||||
q.enqueue(tid * 3 + 1);
|
||||
q.enqueue(tid * 3 + 2);
|
||||
|
||||
int item;
|
||||
for (int i = 0; i != 2; ++i) {
|
||||
if (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Tests multiple implicit producers being created (stresses the implicit producer hash map)
|
||||
struct implicit_producer_reuse : rl::test_suite<implicit_producer_reuse, 9>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(9, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
q.enqueue(tid);
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Tests implicit producer block recycling
|
||||
struct implicit_block_reuse : rl::test_suite<implicit_block_reuse, 4>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(28, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
for (int i = 0; i != 7; ++i) {
|
||||
q.enqueue(tid * 7 + i);
|
||||
}
|
||||
|
||||
int item;
|
||||
ConsumerToken t(q);
|
||||
for (int i = 0; i != 7; ++i) {
|
||||
if (q.try_dequeue(t, item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Tests consumption from mixed producers
|
||||
struct mixed : rl::test_suite<mixed, 4>
|
||||
{
|
||||
ConcurrentQueue<int, SmallConstantTraits> q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(28, false);
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid <= 1) {
|
||||
for (int i = 0; i != 7; ++i) {
|
||||
q.enqueue(tid * 7 + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ProducerToken t(q);
|
||||
for (int i = 0; i != 7; ++i) {
|
||||
q.enqueue(t, tid * 7 + i);
|
||||
}
|
||||
}
|
||||
|
||||
int item;
|
||||
if (tid & 1) {
|
||||
for (int i = 0; i != 4; ++i) {
|
||||
if (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ConsumerToken t(q);
|
||||
for (int i = 0; i != 4; ++i) {
|
||||
if (q.try_dequeue(t, item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int item;
|
||||
while (q.try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item]);
|
||||
seen[item] = true;
|
||||
}
|
||||
for (auto s : seen) {
|
||||
RL_ASSERT(s);
|
||||
}
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Test leftovers are being properly destroyed
|
||||
struct leftovers_destroyed_explicit : rl::test_suite<leftovers_destroyed_explicit, 3>
|
||||
{
|
||||
ConcurrentQueue<Foo, MediumConstantTraits>* q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(rl::rand(32), false);
|
||||
|
||||
q = new ConcurrentQueue<Foo, MediumConstantTraits>();
|
||||
Foo::reset();
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid == 0) {
|
||||
ProducerToken t(*q);
|
||||
for (int i = 0; i != (int)seen.size(); ++i) {
|
||||
q->enqueue(t, Foo(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
Foo item;
|
||||
ConsumerToken t(*q);
|
||||
for (int i = rl::rand(17); i > 0; --i) {
|
||||
if (q->try_dequeue(t, item)) {
|
||||
RL_ASSERT(!seen[item.id]);
|
||||
seen[item.id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int seenCount = 0;
|
||||
{
|
||||
for (auto s : seen) {
|
||||
if (s) {
|
||||
++seenCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RL_ASSERT(Foo::ctorCount() == seen.size() * 2 + 2);
|
||||
RL_ASSERT(Foo::dtorCount() == seen.size() + seenCount + 2);
|
||||
delete q;
|
||||
|
||||
RL_ASSERT(Foo::ctorCount() == seen.size() * 2 + 2);
|
||||
RL_ASSERT(Foo::ctorCount() == Foo::dtorCount());
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// implicit
|
||||
struct leftovers_destroyed_implicit : rl::test_suite<leftovers_destroyed_implicit, 3>
|
||||
{
|
||||
ConcurrentQueue<Foo, MediumConstantTraits>* q;
|
||||
std::vector<bool> seen;
|
||||
|
||||
void before()
|
||||
{
|
||||
seen.resize(rl::rand(32), false);
|
||||
|
||||
q = new ConcurrentQueue<Foo, MediumConstantTraits>();
|
||||
Foo::reset();
|
||||
}
|
||||
|
||||
void thread(unsigned int tid)
|
||||
{
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_start();
|
||||
|
||||
if (tid == 0) {
|
||||
for (int i = 0; i != (int)seen.size(); ++i) {
|
||||
q->enqueue(Foo(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
Foo item;
|
||||
for (int i = rl::rand(17); i > 0; --i) {
|
||||
if (q->try_dequeue(item)) {
|
||||
RL_ASSERT(!seen[item.id]);
|
||||
seen[item.id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RelacyThreadExitNotifier::notify_relacy_thread_exit();
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
int seenCount = 0;
|
||||
{
|
||||
for (auto s : seen) {
|
||||
if (s) {
|
||||
++seenCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RL_ASSERT(Foo::ctorCount() == seen.size() * 2 + 2);
|
||||
RL_ASSERT(Foo::dtorCount() == seen.size() + seenCount + 2);
|
||||
delete q;
|
||||
|
||||
RL_ASSERT(Foo::ctorCount() == seen.size() * 2 + 2);
|
||||
RL_ASSERT(Foo::ctorCount() == Foo::dtorCount());
|
||||
}
|
||||
|
||||
void invariant()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename TTest>
|
||||
void simulate(int iterations)
|
||||
{
|
||||
// Note: There's no point using the full search params
|
||||
// Even with the simple enqueue_explicit_one test, it
|
||||
// would take a few millenia to complete(!)
|
||||
//rl::test_params fullParams;
|
||||
//fullParams.search_type = rl::sched_full;
|
||||
|
||||
rl::test_params randomParams;
|
||||
randomParams.search_type = rl::sched_random;
|
||||
randomParams.iteration_count = iterations;
|
||||
rl::simulate<TTest>(randomParams);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
simulate<enqueue_explicit_one>(1000000);
|
||||
simulate<enqueue_explicit_many>(1000000);
|
||||
simulate<dequeue_some_explicit>(1000000);
|
||||
simulate<recycle_blocks_explicit>(1000000);
|
||||
simulate<expand_block_index_explicit>(1000000);
|
||||
simulate<enqueue_implicit_one>(1000000);
|
||||
simulate<implicit_simple>(1000000);
|
||||
simulate<many_implicit_producers>(500000);
|
||||
simulate<implicit_producer_reuse>(1000000);
|
||||
simulate<implicit_block_reuse>(1000000);
|
||||
simulate<mixed>(1000000);
|
||||
simulate<leftovers_destroyed_explicit>(1000000);
|
||||
simulate<leftovers_destroyed_implicit>(1000000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/makefile
vendored
Normal file
29
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/makefile
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# ©2014-2015 Cameron Desrochers
|
||||
|
||||
include ../../build/makefile.inc
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
PLATFORM_OPTS = -static
|
||||
else
|
||||
PLATFORM_OPTS = -lrt
|
||||
endif
|
||||
|
||||
OPTS = -Wno-int-to-pointer-cast -pthread $(PLATFORM_OPTS) -O3 -g
|
||||
|
||||
default: freelist$(EXT) spmchash$(EXT) integrated$(EXT)
|
||||
|
||||
freelist$(EXT): makefile freelist.cpp
|
||||
g++ -std=c++11 -fpermissive $(OPTS) freelist.cpp -o freelist$(EXT)
|
||||
|
||||
spmchash$(EXT): makefile spmchash.cpp
|
||||
g++ -std=c++11 -fpermissive $(OPTS) spmchash.cpp -o spmchash$(EXT)
|
||||
|
||||
integrated$(EXT): makefile integrated.cpp ../../concurrentqueue.h relacy_shims.h
|
||||
g++ -std=c++11 -fpermissive $(OPTS) -Irelacy -I. integrated.cpp -o integrated$(EXT)
|
||||
|
||||
#run: freelist$(EXT)
|
||||
# ./freelist$(EXT)
|
||||
#run: spmchash$(EXT)
|
||||
# ./spmchash$(EXT)
|
||||
run: integrated$(EXT)
|
||||
./integrated$(EXT)
|
||||
25
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/CHANGES
vendored
Normal file
25
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/CHANGES
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Version 2.4
|
||||
Features:
|
||||
+ Support for futex(FUTEX_WAIT/FUTEX_WAKE)
|
||||
+ Linux/Darwin performance improved (2.5x for Linux, 7x for Darwin)
|
||||
Fixes:
|
||||
+ Fixed a bunch of issues with WaitForMultipleObjects()/SignalObjectAndWait()
|
||||
+ Fixed rare spurious memory leak reports related to test progress reporting
|
||||
|
||||
Version 2.3
|
||||
Features:
|
||||
+ Support for FlushProcessWriteBuffers()
|
||||
|
||||
Version 2.2
|
||||
Features:
|
||||
+ Support for pthread_mutex_timedlock()
|
||||
+ Support for ETIMEDOUT, EINTR in pthread_cond_timedwait()/pthread_cond_wait()
|
||||
+ rl::hash_ptr(p, sz) function which provides deterministic hashing of pointers
|
||||
Fixes:
|
||||
+ Win32 mutex is now recursive
|
||||
+ Compilation issue on MSVC x64 when RL_DEBUGBREAK_ON_ASSERT/RL_DEBUGBREAK_ON_FAILURE defined
|
||||
+ Fixed OOM crash when execution history is very large
|
||||
+ Fixed rare crash during iteration count estimation in context bound scheduler
|
||||
+ Fixed bug in pthread_rwlock/SRWLOCK that at most 2 readers may acquire it simultaneously
|
||||
+ Fixed bug regarding false race detection when simulation runs for very long time (int overflow)
|
||||
|
||||
19
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/LICENSE
vendored
Normal file
19
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Relacy Race Detector
|
||||
Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
- The name of the owner may not be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE OWNER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/VERSION
vendored
Normal file
1
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/VERSION
vendored
Normal file
@@ -0,0 +1 @@
|
||||
acc09bbe65a1837a08912774c7fed178547514e6
|
||||
@@ -0,0 +1,195 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_cli.hpp"
|
||||
|
||||
|
||||
using rl::nvar;
|
||||
using rl::nvolatile;
|
||||
using rl::mutex;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ws_deque
|
||||
{
|
||||
public:
|
||||
ws_deque()
|
||||
{
|
||||
m_mask($) = initial_size - 1;
|
||||
m_headIndex($) = 0;
|
||||
m_tailIndex($) = 0;
|
||||
m_array($) = new nvar<T> [initial_size];
|
||||
m_arraySize($) = initial_size;
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return m_headIndex($) >= m_tailIndex($);
|
||||
}
|
||||
|
||||
size_t Count()
|
||||
{
|
||||
return m_tailIndex($) - m_headIndex($);
|
||||
}
|
||||
|
||||
void push(T item)
|
||||
{
|
||||
size_t tail = m_tailIndex($);
|
||||
if (tail <= m_headIndex($) + m_mask($))
|
||||
{
|
||||
m_array($)[tail & m_mask($)]($) = item;
|
||||
m_tailIndex($) = tail + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
size_t head = m_headIndex($);
|
||||
size_t count = Count();
|
||||
if (count >= m_mask($))
|
||||
{
|
||||
size_t arraySize = m_arraySize($);
|
||||
size_t mask = m_mask($);
|
||||
nvar<T>* newArray = new nvar<T> [arraySize * 2];
|
||||
nvar<T>* arr = m_array($);
|
||||
for (size_t i = 0; i != count; ++i)
|
||||
newArray[i]($) = arr[(i + head) & mask]($);
|
||||
m_array($) = newArray;
|
||||
m_arraySize($) = arraySize * 2;
|
||||
m_headIndex($) = 0;
|
||||
m_tailIndex($) = count;
|
||||
tail = count;
|
||||
m_mask($) = (mask * 2) | 1;
|
||||
}
|
||||
m_array($)[tail & m_mask($)]($) = item;
|
||||
m_tailIndex($) = tail + 1;
|
||||
m_foreignLock.unlock($);
|
||||
}
|
||||
}
|
||||
|
||||
bool pop(T& item)
|
||||
{
|
||||
size_t tail = m_tailIndex($);
|
||||
if (tail == 0)
|
||||
return false;
|
||||
tail -= 1;
|
||||
rl::Interlocked::Exchange(m_tailIndex, tail, $);
|
||||
if (m_headIndex($) <= tail)
|
||||
{
|
||||
item = m_array($)[tail & m_mask($)]($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
if (m_headIndex($) <= tail)
|
||||
{
|
||||
item = m_array($)[tail & m_mask($)]($);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tailIndex($) = tail + 1;
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool steal(T& item)
|
||||
{
|
||||
if (false == m_foreignLock.try_lock($))
|
||||
return false;
|
||||
size_t head = m_headIndex($);
|
||||
rl::Interlocked::Exchange(m_headIndex, head + 1, $);
|
||||
if (head < m_tailIndex($))
|
||||
{
|
||||
item = m_array($)[head & m_mask($)]($);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_headIndex($) = head;
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t const initial_size = 2;
|
||||
nvar<nvar<T>*> m_array;
|
||||
nvar<size_t> m_mask;
|
||||
nvar<size_t> m_arraySize;
|
||||
nvolatile<size_t> m_headIndex;
|
||||
nvolatile<size_t> m_tailIndex;
|
||||
mutex m_foreignLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ws_deque_test : rl::test_suite<ws_deque_test, 2>
|
||||
{
|
||||
ws_deque<int> q;
|
||||
bool state [2];
|
||||
|
||||
void before()
|
||||
{
|
||||
state[0] = true;
|
||||
state[1] = true;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
RL_ASSERT(state[0] == false);
|
||||
RL_ASSERT(state[1] == false);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
q.push(1);
|
||||
q.push(2);
|
||||
|
||||
int item = 0;
|
||||
bool res = q.pop(item);
|
||||
RL_ASSERT(res && item == 2);
|
||||
RL_ASSERT(state[1]);
|
||||
state[1] = false;
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
RL_ASSERT(res == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int item = 0;
|
||||
bool res = q.steal(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(item == 1);
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<ws_deque_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="cli_ws_deque"
|
||||
ProjectGUID="{967F376B-BDBF-4AC8-9325-371CC8ABD8FD}"
|
||||
RootNamespace="cli_ws_deque"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\cli_ws_deque.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
|
||||
|
||||
181
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/condvar/condvar.cpp
vendored
Normal file
181
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/condvar/condvar.cpp
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
// THE TEST IS EXPECTED TO FAIL WITH "DEADLOCK"
|
||||
|
||||
class CondVar
|
||||
{
|
||||
public:
|
||||
CondVar();
|
||||
~CondVar();
|
||||
void Enter();
|
||||
void Wait();
|
||||
void Release();
|
||||
void ReleaseAll();
|
||||
void Leave();
|
||||
|
||||
private:
|
||||
std::atomic<int> m_lMutex;
|
||||
std::atomic<unsigned> m_dwWaitingForSignal;
|
||||
HANDLE m_xhEvtEnter;
|
||||
HANDLE m_xhSemRelease;
|
||||
};
|
||||
|
||||
CondVar::CondVar()
|
||||
: m_xhEvtEnter(CreateEvent(0, 0, 0, 0))
|
||||
, m_xhSemRelease(CreateSemaphore(0, 0, 0x7FFFFFFF, 0))
|
||||
{
|
||||
m_lMutex.store(0, std::memory_order_relaxed);
|
||||
m_dwWaitingForSignal.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
CondVar::~CondVar()
|
||||
{
|
||||
CloseHandle(m_xhEvtEnter);
|
||||
CloseHandle(m_xhSemRelease);
|
||||
}
|
||||
|
||||
void CondVar::Enter()
|
||||
{
|
||||
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
|
||||
for (;;)
|
||||
{
|
||||
if( lMutex >= 0 )
|
||||
{
|
||||
if (m_lMutex.compare_exchange_weak(lMutex, lMutex | 0x80000000u, std::memory_order_seq_cst))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == m_lMutex.compare_exchange_weak(lMutex, lMutex + 1, std::memory_order_seq_cst))
|
||||
continue;
|
||||
WaitForSingleObject(m_xhEvtEnter, INFINITE);
|
||||
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CondVar::Wait()
|
||||
{
|
||||
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
|
||||
m_dwWaitingForSignal.store(dwWaitingForSignal + 1, std::memory_order_seq_cst);
|
||||
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
|
||||
|
||||
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
|
||||
for (;;)
|
||||
{
|
||||
unsigned dwWaitingToOwn = lMutex & 0x7FFFFFFFu;
|
||||
RL_ASSERT(dwWaitingToOwn >= dwWaitingForSignal);
|
||||
if (dwWaitingToOwn == dwWaitingForSignal)
|
||||
{
|
||||
if (m_lMutex.compare_exchange_weak(lMutex, dwWaitingToOwn + 1, std::memory_order_seq_cst))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent(m_xhEvtEnter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WaitForSingleObject(m_xhSemRelease, INFINITE);
|
||||
WaitForSingleObject(m_xhEvtEnter, INFINITE);
|
||||
|
||||
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
|
||||
}
|
||||
|
||||
void CondVar::Release()
|
||||
{
|
||||
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
|
||||
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
|
||||
if (dwWaitingForSignal != 0)
|
||||
{
|
||||
m_dwWaitingForSignal.store(dwWaitingForSignal - 1, std::memory_order_seq_cst);
|
||||
ReleaseSemaphore(m_xhSemRelease, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CondVar::ReleaseAll()
|
||||
{
|
||||
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
|
||||
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
|
||||
if (dwWaitingForSignal != 0)
|
||||
{
|
||||
m_dwWaitingForSignal.store(0, std::memory_order_seq_cst);
|
||||
ReleaseSemaphore(m_xhSemRelease, dwWaitingForSignal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CondVar::Leave()
|
||||
{
|
||||
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
|
||||
RL_ASSERT(lMutex < 0);
|
||||
for (;;)
|
||||
{
|
||||
unsigned dwWaitingToOwn = lMutex & 0x7FFFFFFFu;
|
||||
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
|
||||
RL_ASSERT(dwWaitingToOwn >= dwWaitingForSignal);
|
||||
if (dwWaitingToOwn == dwWaitingForSignal)
|
||||
{
|
||||
if (m_lMutex.compare_exchange_weak(lMutex, lMutex & 0x7FFFFFFF, std::memory_order_seq_cst))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == m_lMutex.compare_exchange_weak(lMutex, lMutex - 1, std::memory_order_seq_cst))
|
||||
continue;
|
||||
SetEvent(m_xhEvtEnter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CondVarTest : rl::test_suite<CondVarTest, 3>
|
||||
{
|
||||
VAR_T(int) stage;
|
||||
CondVar cv;
|
||||
|
||||
void before()
|
||||
{
|
||||
VAR(stage) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
cv.Enter();
|
||||
VAR(stage) += 1;
|
||||
cv.ReleaseAll();
|
||||
while (VAR(stage) != 2)
|
||||
cv.Wait();
|
||||
cv.Leave();
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
cv.Enter();
|
||||
while (VAR(stage) != 1)
|
||||
cv.Wait();
|
||||
VAR(stage) += 1;
|
||||
cv.ReleaseAll();
|
||||
cv.Leave();
|
||||
}
|
||||
else if (2 == index)
|
||||
{
|
||||
cv.Enter();
|
||||
while (VAR(stage) != 2)
|
||||
cv.Wait();
|
||||
cv.Leave();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<CondVarTest>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="condvar"
|
||||
ProjectGUID="{6CC59CF8-408B-441B-8F65-15651210CB82}"
|
||||
RootNamespace="condvar"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\condvar.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="condvar"
|
||||
ProjectGUID="{6CC59CF8-408B-441B-8F65-15651210CB82}"
|
||||
RootNamespace="condvar"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\condvar.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_MSVC_OUTPUT
|
||||
//#define RL_DEBUGBREAK_ON_FAILURE
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
#define BOOST_ALL_NO_LIB
|
||||
#pragma warning (push, 3)
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include "C:\boost_1_35_0\libs\thread\src\win32\exceptions.cpp"
|
||||
#pragma warning (pop)
|
||||
|
||||
|
||||
class business_logic
|
||||
{
|
||||
public:
|
||||
typedef unsigned account_id_t;
|
||||
typedef double balance_t;
|
||||
|
||||
bool add_account(account_id_t acc_id, balance_t balance)
|
||||
{
|
||||
accounts_guard.lock();
|
||||
if (accounts.find(acc_id) != accounts.end())
|
||||
{
|
||||
accounts_guard.unlock();
|
||||
return false;
|
||||
}
|
||||
accounts[acc_id].balance = balance;
|
||||
accounts_guard.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
|
||||
{
|
||||
accounts_guard.lock_shared();
|
||||
if (accounts.find(acc_id1) != accounts.end()
|
||||
|| accounts.find(acc_id2) != accounts.end())
|
||||
{
|
||||
accounts_guard.unlock_shared();
|
||||
return false;
|
||||
}
|
||||
account_info& acc1 = accounts[acc_id1];
|
||||
account_info& acc2 = accounts[acc_id2];
|
||||
acc1.mtx.lock();
|
||||
acc2.mtx.lock();
|
||||
accounts_guard.unlock_shared();
|
||||
|
||||
acc1.balance -= amount;
|
||||
acc2.balance += amount;
|
||||
|
||||
acc1.mtx.unlock();
|
||||
acc2.mtx.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct account_info
|
||||
{
|
||||
balance_t balance;
|
||||
boost::mutex mtx;
|
||||
|
||||
account_info()
|
||||
: balance()
|
||||
{}
|
||||
|
||||
account_info(account_info const& acc)
|
||||
: balance(acc.balance)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::map<account_id_t, account_info> account_map_t;
|
||||
account_map_t accounts;
|
||||
boost::shared_mutex accounts_guard;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#undef RL_TEST
|
||||
|
||||
#ifndef RL_TEST
|
||||
//# define ASSERT assert
|
||||
typedef boost::mutex mutex_t;
|
||||
# define $$
|
||||
#else
|
||||
//# define ASSERT RL_ASSERT
|
||||
typedef rl::recursive_mutex mutex_t;
|
||||
# define $$ $
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class business_logic
|
||||
{
|
||||
public:
|
||||
typedef unsigned account_id_t;
|
||||
typedef double balance_t;
|
||||
|
||||
bool add_account(account_id_t acc_id, balance_t balance)
|
||||
{
|
||||
accounts_guard.lock($$);
|
||||
if (accounts.find(acc_id) != accounts.end())
|
||||
{
|
||||
accounts_guard.unlock($$);
|
||||
return false;
|
||||
}
|
||||
accounts[acc_id].balance = balance;
|
||||
accounts_guard.unlock($$);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
|
||||
{
|
||||
accounts_guard.lock($$);
|
||||
if (accounts.find(acc_id1) == accounts.end()
|
||||
|| accounts.find(acc_id2) == accounts.end())
|
||||
{
|
||||
accounts_guard.unlock($$);
|
||||
return false;
|
||||
}
|
||||
account_info& acc1 = accounts[acc_id1];
|
||||
account_info& acc2 = accounts[acc_id2];
|
||||
acc1.mtx.lock($$);
|
||||
acc2.mtx.lock($$);
|
||||
accounts_guard.unlock($$);
|
||||
|
||||
acc1.balance -= amount;
|
||||
acc2.balance += amount;
|
||||
|
||||
acc1.mtx.unlock($$);
|
||||
acc2.mtx.unlock($$);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct account_info
|
||||
{
|
||||
balance_t balance;
|
||||
mutex_t mtx;
|
||||
|
||||
account_info()
|
||||
: balance()
|
||||
{}
|
||||
|
||||
account_info(account_info const& acc)
|
||||
: balance(acc.balance)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::map<account_id_t, account_info> account_map_t;
|
||||
account_map_t accounts;
|
||||
mutex_t accounts_guard;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
struct business_logic_test : rl::test_suite<business_logic_test, 2>
|
||||
{
|
||||
business_logic bl;
|
||||
|
||||
static size_t const account_count = 10;
|
||||
|
||||
void before()
|
||||
{
|
||||
for (size_t i = 0; i != account_count; ++i)
|
||||
{
|
||||
bool rv = bl.add_account(i, i * 10.0);
|
||||
RL_ASSERT(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void thread(unsigned)
|
||||
{
|
||||
business_logic::account_id_t acc1 = rl::rand(account_count);
|
||||
business_logic::account_id_t acc2 = rl::rand(account_count);
|
||||
bool rv = bl.transfer_balance(acc1, acc2, 1.0);
|
||||
RL_ASSERT(rv);
|
||||
}
|
||||
};
|
||||
*/
|
||||
@@ -0,0 +1,707 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../relacy/windows.h"
|
||||
|
||||
#define HANDLE rl::HANDLE
|
||||
|
||||
#define CreateSemaphoreA rl::RL_CreateSemaphore($)
|
||||
#define CreateSemaphoreW rl::RL_CreateSemaphore($)
|
||||
#ifndef CreateSemaphore
|
||||
# define CreateSemaphore CreateSemaphoreW
|
||||
#endif
|
||||
|
||||
|
||||
#define CloseHandle rl::RL_CloseHandle($)
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#if defined(WIN32) && defined(_MSC_VER)
|
||||
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
|
||||
class semaphore
|
||||
{
|
||||
public:
|
||||
semaphore()
|
||||
{
|
||||
h_ = CreateSemaphore(0, 0, LONG_MAX, 0);
|
||||
}
|
||||
|
||||
~semaphore()
|
||||
{
|
||||
CloseHandle(h_);
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
WaitForSingleObject(h_, INFINITE);
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
ReleaseSemaphore(h_, 1, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE h_;
|
||||
|
||||
semaphore(semaphore const&);
|
||||
semaphore& operator = (semaphore const&);
|
||||
};
|
||||
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
InitializeCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
DeleteCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
EnterCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
LeaveCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION cs_;
|
||||
|
||||
mutex(mutex const&);
|
||||
mutex& operator = (mutex const&);
|
||||
};
|
||||
|
||||
void full_memory_fence()
|
||||
{
|
||||
_mm_mfence();
|
||||
}
|
||||
|
||||
#define THREAD_LOCAL __declspec(thread)
|
||||
|
||||
#elif defined(POSIX) && defined(GCC)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
class semaphore
|
||||
{
|
||||
public:
|
||||
semaphore()
|
||||
{
|
||||
sem_init(&sem_, 0, 0);
|
||||
}
|
||||
|
||||
~semaphore()
|
||||
{
|
||||
sem_destroy(&sem_);
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
sem_wait(&sem_);
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
sem_post(&sem_);
|
||||
}
|
||||
|
||||
private:
|
||||
sem_t sem_;
|
||||
|
||||
semaphore(semaphore const&);
|
||||
semaphore& operator = (semaphore const&);
|
||||
};
|
||||
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutex_init(&mutex_, 0);
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&mutex_);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
mutex(mutex const&);
|
||||
mutex& operator = (mutex const&);
|
||||
};
|
||||
|
||||
void full_memory_fence()
|
||||
{
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
#define THREAD_LOCAL __thread
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class lock
|
||||
{
|
||||
public:
|
||||
lock(mutex& m)
|
||||
: m_(m)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
~lock()
|
||||
{
|
||||
m_.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
mutex& m_;
|
||||
|
||||
lock(lock const&);
|
||||
lock& operator = (lock const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** simple single-threaded double-linked list
|
||||
* nothing interesting
|
||||
*/
|
||||
class dlist
|
||||
{
|
||||
public:
|
||||
struct node
|
||||
{
|
||||
node* prev_;
|
||||
node* next_;
|
||||
|
||||
node()
|
||||
{
|
||||
prev_ = 0;
|
||||
next_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
dlist()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void push(node* n)
|
||||
{
|
||||
size_ += 1;
|
||||
n->next_ = head_.next_;
|
||||
n->prev_ = &head_;
|
||||
head_.next_->prev_ = n;
|
||||
head_.next_ = n;
|
||||
}
|
||||
|
||||
node* pop()
|
||||
{
|
||||
if (size_ == 0)
|
||||
return 0;
|
||||
node* n = head_.next_;
|
||||
remove(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void remove(node* n)
|
||||
{
|
||||
size_ -= 1;
|
||||
n->prev_->next_ = n->next_;
|
||||
n->next_->prev_ = n->prev_;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
node* begin()
|
||||
{
|
||||
return head_.next_;
|
||||
}
|
||||
|
||||
void flush_to(dlist& target)
|
||||
{
|
||||
if (size_)
|
||||
{
|
||||
target.size_ = size_;
|
||||
target.head_.next_ = head_.next_;
|
||||
target.head_.next_->prev_ = &target.head_;
|
||||
target.tail_.prev_ = tail_.prev_;
|
||||
target.tail_.prev_->next_ = &target.tail_;
|
||||
}
|
||||
else
|
||||
{
|
||||
target.reset();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
static bool not_last(node* n)
|
||||
{
|
||||
return n->next_ != 0;
|
||||
}
|
||||
|
||||
static node* get_next(node* n)
|
||||
{
|
||||
return n->next_;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t volatile size_;
|
||||
node head_;
|
||||
node tail_;
|
||||
|
||||
void reset()
|
||||
{
|
||||
size_ = 0;
|
||||
head_.next_ = &tail_;
|
||||
head_.prev_ = 0;
|
||||
tail_.next_ = 0;
|
||||
tail_.prev_ = &head_;
|
||||
}
|
||||
|
||||
dlist(dlist const&);
|
||||
dlist& operator = (dlist const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** pre-thread descriptor for eventcount
|
||||
*/
|
||||
struct ec_thread
|
||||
{
|
||||
dlist::node node_;
|
||||
semaphore sema_;
|
||||
unsigned epoch_;
|
||||
bool volatile in_waitset_;
|
||||
bool spurious_;
|
||||
void* ctx_;
|
||||
|
||||
ec_thread()
|
||||
{
|
||||
epoch_ = 0;
|
||||
in_waitset_ = false;
|
||||
spurious_ = false;
|
||||
ctx_ = 0;
|
||||
}
|
||||
|
||||
~ec_thread()
|
||||
{
|
||||
if (spurious_)
|
||||
sema_.wait();
|
||||
}
|
||||
|
||||
static ec_thread* current()
|
||||
{
|
||||
static THREAD_LOCAL ec_thread* ec_thread_instance = 0;
|
||||
ec_thread* instance = ec_thread_instance;
|
||||
if (instance == 0)
|
||||
{
|
||||
instance = new ec_thread;
|
||||
ec_thread_instance = instance;
|
||||
}
|
||||
return instance;
|
||||
// instance must be destroyed in DllMain() callback
|
||||
// or in pthread_key_create() callback
|
||||
}
|
||||
|
||||
private:
|
||||
ec_thread(ec_thread const&);
|
||||
ec_thread& operator = (ec_thread const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** fine-grained eventcount implementation
|
||||
*/
|
||||
class eventcount
|
||||
{
|
||||
public:
|
||||
eventcount()
|
||||
{
|
||||
epoch_ = 0;
|
||||
}
|
||||
|
||||
void prepare_wait(void* ctx = 0)
|
||||
{
|
||||
ec_thread* th = ec_thread::current();
|
||||
// this is good place to pump previous spurious wakeup
|
||||
if (th->spurious_)
|
||||
{
|
||||
th->spurious_ = false;
|
||||
th->sema_.wait();
|
||||
}
|
||||
th->in_waitset_ = true;
|
||||
th->ctx_ = ctx;
|
||||
{
|
||||
lock l (mtx_);
|
||||
th->epoch_ = epoch_;
|
||||
waitset_.push(&th->node_);
|
||||
}
|
||||
full_memory_fence();
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
ec_thread* th = ec_thread::current();
|
||||
// this check is just an optimization
|
||||
if (th->epoch_ == epoch_)
|
||||
th->sema_.wait();
|
||||
else
|
||||
retire_wait();
|
||||
}
|
||||
|
||||
void retire_wait()
|
||||
{
|
||||
ec_thread* th = ec_thread::current();
|
||||
// spurious wakeup will be pumped in following prepare_wait()
|
||||
th->spurious_ = true;
|
||||
// try to remove node from waitset
|
||||
if (th->in_waitset_)
|
||||
{
|
||||
lock l (mtx_);
|
||||
if (th->in_waitset_)
|
||||
{
|
||||
// successfully removed from waitset,
|
||||
// so there will be no spurious wakeup
|
||||
th->in_waitset_ = false;
|
||||
th->spurious_ = false;
|
||||
waitset_.remove(&th->node_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
full_memory_fence();
|
||||
notify_one_relaxed();
|
||||
}
|
||||
|
||||
template<typename predicate_t>
|
||||
void notify(predicate_t pred)
|
||||
{
|
||||
full_memory_fence();
|
||||
notify_relaxed(pred);
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
full_memory_fence();
|
||||
notify_all_relaxed();
|
||||
}
|
||||
|
||||
void notify_one_relaxed()
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist::node* n;
|
||||
{
|
||||
lock l (mtx_);
|
||||
epoch_ += 1;
|
||||
n = waitset_.pop();
|
||||
if (n)
|
||||
to_ec_thread(n)->in_waitset_ = false;
|
||||
}
|
||||
if (n)
|
||||
{
|
||||
to_ec_thread(n)->sema_.post();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename predicate_t>
|
||||
void notify_relaxed(predicate_t pred)
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist temp;
|
||||
{
|
||||
lock l (mtx_);
|
||||
epoch_ += 1;
|
||||
size_t size = waitset_.size();
|
||||
size_t idx = 0;
|
||||
dlist::node* n = waitset_.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
ec_thread* th = to_ec_thread(n);
|
||||
if (pred(th->ctx_, size, idx))
|
||||
{
|
||||
waitset_.remove(n);
|
||||
temp.push(n);
|
||||
th->in_waitset_ = false;
|
||||
}
|
||||
n = next;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
to_ec_thread(n)->sema_.post();
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all_relaxed()
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist temp;
|
||||
{
|
||||
lock l (mtx_);
|
||||
epoch_ += 1;
|
||||
waitset_.flush_to(temp);
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
to_ec_thread(n)->in_waitset_ = false;
|
||||
n = dlist::get_next(n);
|
||||
}
|
||||
}
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
to_ec_thread(n)->sema_.post();
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutex mtx_;
|
||||
dlist waitset_;
|
||||
volatile unsigned epoch_;
|
||||
|
||||
ec_thread* to_ec_thread(dlist::node* n)
|
||||
{
|
||||
return (ec_thread*)((char*)n - offsetof(ec_thread, node_));
|
||||
}
|
||||
|
||||
eventcount(eventcount const&);
|
||||
eventcount& operator = (eventcount const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct scheduler
|
||||
{
|
||||
struct tbb_thread {};
|
||||
|
||||
eventcount ec_;
|
||||
tbb_thread* threads_;
|
||||
bool volatile is_permanently_open_;
|
||||
|
||||
void wait_while_pool_is_empty(tbb_thread* th)
|
||||
{
|
||||
if (is_permanently_open_)
|
||||
return;
|
||||
ec_.prepare_wait(th);
|
||||
if (pool_is_empty())
|
||||
ec_.wait();
|
||||
else
|
||||
ec_.retire_wait();
|
||||
}
|
||||
|
||||
void notify_about_new_task_available()
|
||||
{
|
||||
ec_.notify_one_relaxed();
|
||||
}
|
||||
|
||||
void notify_about_new_task_available_with_preference(tbb_thread* preference)
|
||||
{
|
||||
struct local
|
||||
{
|
||||
tbb_thread* preference_;
|
||||
bool fired_;
|
||||
|
||||
bool operator () (void* ctx, size_t count, size_t idx)
|
||||
{
|
||||
tbb_thread* th = (tbb_thread*)ctx;
|
||||
if (th == preference_)
|
||||
{
|
||||
fired_ = true;
|
||||
return true;
|
||||
}
|
||||
else if (idx == count - 1 && fired_ == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
pred = {preference};
|
||||
ec_.notify_relaxed(pred);
|
||||
}
|
||||
|
||||
void notify_about_list_of_tasks_available(size_t total_count, size_t preference_count, tbb_thread** preferences)
|
||||
{
|
||||
struct local
|
||||
{
|
||||
size_t remain_to_signal_;
|
||||
size_t preference_count_;
|
||||
tbb_thread** preferences_;
|
||||
|
||||
bool operator () (void* ctx, size_t count, size_t idx)
|
||||
{
|
||||
tbb_thread* th = (tbb_thread*)ctx;
|
||||
size_t remain_in_waitset = count - idx;
|
||||
if (remain_in_waitset <= remain_to_signal_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i != preference_count_; ++i)
|
||||
{
|
||||
if (preferences_[i] == th)
|
||||
{
|
||||
remain_to_signal_ -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pred = {total_count, preference_count, preferences};
|
||||
ec_.notify_relaxed(pred);
|
||||
}
|
||||
|
||||
bool pool_is_empty()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct queue
|
||||
{
|
||||
int producer_idx_;
|
||||
int consumer_idx_;
|
||||
|
||||
void** buffer_;
|
||||
|
||||
eventcount ec_;
|
||||
|
||||
void enqueue(void* data)
|
||||
{
|
||||
int idx = ++producer_idx_; // atomic
|
||||
buffer_[idx] = data;
|
||||
|
||||
struct local
|
||||
{
|
||||
int idx_;
|
||||
bool operator () (void* ctx, size_t /*count*/, size_t /*idx*/)
|
||||
{
|
||||
return idx_ == *(int*)ctx;
|
||||
}
|
||||
}
|
||||
pred = {idx};
|
||||
ec_.notify(pred); // not relaxed!!!
|
||||
}
|
||||
|
||||
void* dequeue()
|
||||
{
|
||||
int idx = ++consumer_idx_; // atomic
|
||||
void* data = buffer_[idx];
|
||||
if (data)
|
||||
return data;
|
||||
for (;;)
|
||||
{
|
||||
ec_.prepare_wait(&idx);
|
||||
data = buffer_[idx];
|
||||
if (data)
|
||||
{
|
||||
ec_.retire_wait();
|
||||
return data;
|
||||
}
|
||||
ec_.wait();
|
||||
data = buffer_[idx];
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class condition_variable
|
||||
{
|
||||
eventcount ec_;
|
||||
|
||||
public:
|
||||
void wait(mutex& mtx)
|
||||
{
|
||||
ec_.prepare_wait();
|
||||
mtx.unlock();
|
||||
ec_.wait();
|
||||
mtx.lock();
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
ec_.notify_one();
|
||||
}
|
||||
|
||||
void broadcast()
|
||||
{
|
||||
ec_.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct eventcount_test : rl::test_suite<eventcount_test, 2>
|
||||
{
|
||||
void thread(unsigned index)
|
||||
{
|
||||
delete ec_thread::current();
|
||||
(void)index;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
//p.iteration_count = 1000000;
|
||||
rl::simulate<eventcount_test>(p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="eventcount"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E54}"
|
||||
RootNamespace="eventcount"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\eventcount.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="eventcount"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E54}"
|
||||
RootNamespace="eventcount"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\eventcount.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ws_deque.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
struct amp_raw_condition_variable_s
|
||||
{
|
||||
CRITICAL_SECTION access_waiting_threads_count_critsec;
|
||||
HANDLE wake_waiting_threads_mutex;
|
||||
HANDLE waking_waiting_threads_count_control_sem;
|
||||
HANDLE finished_waking_waiting_threads_event;
|
||||
VAR_T(LONG) waiting_thread_count;
|
||||
VAR_T(BOOL) broadcast_in_progress;
|
||||
};
|
||||
|
||||
|
||||
struct amp_raw_mutex_s
|
||||
{
|
||||
CRITICAL_SECTION critical_section;
|
||||
BOOL is_locked;
|
||||
};
|
||||
|
||||
typedef amp_raw_condition_variable_s* amp_raw_condition_variable_t;
|
||||
typedef amp_raw_mutex_s* amp_raw_mutex_t;
|
||||
|
||||
int const AMP_SUCCESS = 0;
|
||||
|
||||
|
||||
int amp_raw_mutex_init(amp_raw_mutex_t mutex)
|
||||
{
|
||||
InitializeCriticalSectionAndSpinCount(&mutex->critical_section, 1);
|
||||
|
||||
mutex->is_locked = FALSE;
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int amp_raw_mutex_finalize(amp_raw_mutex_t mutex)
|
||||
{
|
||||
assert(NULL != mutex);
|
||||
|
||||
int retval = AMP_SUCCESS;
|
||||
|
||||
DeleteCriticalSection(&mutex->critical_section);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int amp_raw_mutex_lock(amp_raw_mutex_t mutex)
|
||||
{
|
||||
assert(NULL != mutex);
|
||||
|
||||
EnterCriticalSection(&mutex->critical_section);
|
||||
|
||||
mutex->is_locked = TRUE;
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
int amp_raw_mutex_unlock(amp_raw_mutex_t mutex)
|
||||
{
|
||||
assert(NULL != mutex);
|
||||
|
||||
mutex->is_locked = FALSE;
|
||||
LeaveCriticalSection(&mutex->critical_section);
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int amp_raw_condition_variable_init(amp_raw_condition_variable_t cond)
|
||||
{
|
||||
InitializeCriticalSectionAndSpinCount(&cond->access_waiting_threads_count_critsec, 1);
|
||||
|
||||
cond->wake_waiting_threads_mutex = CreateMutex(0, 0, 0);
|
||||
|
||||
cond->waking_waiting_threads_count_control_sem = CreateSemaphore(NULL, /* No inheritance to child processes */
|
||||
0, /* Initially no threads can pass */
|
||||
LONG_MAX, /* Max semaphore count */
|
||||
NULL); /* Only intra-process semaphore */
|
||||
|
||||
cond->finished_waking_waiting_threads_event = CreateEvent(NULL, /* Default security and no inheritance to child processes */
|
||||
FALSE, /* No manual reset */
|
||||
0, /* Initially not signaled */
|
||||
NULL /* Not inter-process available */
|
||||
);
|
||||
|
||||
|
||||
cond->VAR(waiting_thread_count) = 0l;
|
||||
cond->VAR(broadcast_in_progress) = FALSE;
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int amp_raw_condition_variable_finalize(amp_raw_condition_variable_t cond)
|
||||
{
|
||||
DeleteCriticalSection(&cond->access_waiting_threads_count_critsec);
|
||||
|
||||
CloseHandle(cond->wake_waiting_threads_mutex);
|
||||
CloseHandle(cond->waking_waiting_threads_count_control_sem);
|
||||
CloseHandle(cond->finished_waking_waiting_threads_event);
|
||||
|
||||
int ret_error_code = AMP_SUCCESS;
|
||||
return ret_error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int amp_raw_condition_variable_signal(amp_raw_condition_variable_t cond)
|
||||
{
|
||||
WaitForSingleObject(cond->wake_waiting_threads_mutex,
|
||||
INFINITE);
|
||||
BOOL at_least_one_waiting_thread = (0l != cond->VAR(waiting_thread_count));
|
||||
|
||||
if (at_least_one_waiting_thread) {
|
||||
LONG prev_sem_count = 0;
|
||||
ReleaseSemaphore(cond->waking_waiting_threads_count_control_sem,
|
||||
1,
|
||||
&prev_sem_count /* No interest in the previous sem count. */
|
||||
);
|
||||
|
||||
WaitForSingleObject(cond->finished_waking_waiting_threads_event,
|
||||
INFINITE);
|
||||
}
|
||||
|
||||
ReleaseMutex(cond->wake_waiting_threads_mutex);
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int amp_raw_condition_variable_broadcast(amp_raw_condition_variable_t cond)
|
||||
{
|
||||
WaitForSingleObject(cond->wake_waiting_threads_mutex,
|
||||
INFINITE);
|
||||
|
||||
LONG const waiting_thread_count = cond->VAR(waiting_thread_count);
|
||||
|
||||
if (0 < waiting_thread_count) {
|
||||
|
||||
cond->VAR(broadcast_in_progress) = TRUE;
|
||||
/* Releasing the sem here and waiting on it should update the memory of
|
||||
* the waiting threads to see that a broadcast is in progress.
|
||||
*/
|
||||
LONG prev_sem_count = 0;
|
||||
/* Assuming that less threads exist than max possible semaphore count.
|
||||
* TODO: @todo Decide if to spin here if the assumption doesn't hold
|
||||
* true in the future?
|
||||
*/
|
||||
ReleaseSemaphore(cond->waking_waiting_threads_count_control_sem,
|
||||
waiting_thread_count,
|
||||
&prev_sem_count /* No interest in the previous sem count. */
|
||||
);
|
||||
|
||||
WaitForSingleObject(cond->finished_waking_waiting_threads_event,
|
||||
INFINITE);
|
||||
cond->VAR(broadcast_in_progress) = FALSE;
|
||||
|
||||
}
|
||||
|
||||
ReleaseMutex(cond->wake_waiting_threads_mutex);
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int amp_raw_condition_variable_wait(amp_raw_condition_variable_t cond,
|
||||
struct amp_raw_mutex_s *mutex)
|
||||
{
|
||||
WaitForSingleObject(cond->wake_waiting_threads_mutex,
|
||||
INFINITE);
|
||||
{
|
||||
++(cond->VAR(waiting_thread_count));
|
||||
}
|
||||
|
||||
amp_raw_mutex_unlock(mutex);
|
||||
|
||||
SignalObjectAndWait(cond->wake_waiting_threads_mutex, cond->waking_waiting_threads_count_control_sem, INFINITE, FALSE);
|
||||
|
||||
BOOL broadcast_in_progress = FALSE;
|
||||
LONG count = 0;
|
||||
EnterCriticalSection(&cond->access_waiting_threads_count_critsec);
|
||||
{
|
||||
count = --(cond->VAR(waiting_thread_count));
|
||||
|
||||
broadcast_in_progress = cond->VAR(broadcast_in_progress);
|
||||
}
|
||||
LeaveCriticalSection(&cond->access_waiting_threads_count_critsec);
|
||||
|
||||
BOOL all_waiting_threads_awake = TRUE;
|
||||
if (TRUE == broadcast_in_progress && count > 0) {
|
||||
all_waiting_threads_awake = FALSE;
|
||||
}
|
||||
|
||||
if (TRUE == all_waiting_threads_awake) {
|
||||
SetEvent(cond->finished_waking_waiting_threads_event);
|
||||
}
|
||||
|
||||
|
||||
amp_raw_mutex_lock(mutex);
|
||||
|
||||
return AMP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
struct amp_condvar_test : rl::test_suite<amp_condvar_test, 2>
|
||||
{
|
||||
VAR_T(int) data;
|
||||
amp_raw_mutex_s mtx;
|
||||
amp_raw_condition_variable_s cv;
|
||||
|
||||
void before()
|
||||
{
|
||||
VAR(data) = 0;
|
||||
amp_raw_mutex_init(&mtx);
|
||||
amp_raw_condition_variable_init(&cv);
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
amp_raw_mutex_finalize(&mtx);
|
||||
amp_raw_condition_variable_finalize(&cv);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
data($) += 1;
|
||||
amp_raw_condition_variable_signal(&cv);
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
while (0 == data($))
|
||||
{
|
||||
amp_raw_condition_variable_wait(&cv, &mtx);
|
||||
}
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct amp_condvar_test2 : rl::test_suite<amp_condvar_test2, 4>
|
||||
{
|
||||
VAR_T(int) stage;
|
||||
amp_raw_mutex_s mtx;
|
||||
amp_raw_condition_variable_s cv;
|
||||
|
||||
void before()
|
||||
{
|
||||
VAR(stage) = 0;
|
||||
amp_raw_mutex_init(&mtx);
|
||||
amp_raw_condition_variable_init(&cv);
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
amp_raw_mutex_finalize(&mtx);
|
||||
amp_raw_condition_variable_finalize(&cv);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
stage($) += 1;
|
||||
amp_raw_condition_variable_broadcast(&cv);
|
||||
while (stage($) < 2)
|
||||
amp_raw_condition_variable_wait(&cv, &mtx);
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
while (stage($) != 1)
|
||||
amp_raw_condition_variable_wait(&cv, &mtx);
|
||||
stage($) += 1;
|
||||
amp_raw_condition_variable_broadcast(&cv);
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
}
|
||||
else if (2 == index)
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
while (stage($) != 2)
|
||||
amp_raw_condition_variable_wait(&cv, &mtx);
|
||||
stage($) += 1;
|
||||
//amp_raw_condition_variable_broadcast(&cv);
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
amp_raw_condition_variable_signal(&cv);
|
||||
}
|
||||
else if (3 == index)
|
||||
{
|
||||
amp_raw_mutex_lock(&mtx);
|
||||
while (stage($) != 3)
|
||||
amp_raw_condition_variable_wait(&cv, &mtx);
|
||||
amp_raw_mutex_unlock(&mtx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "stdafx.h"
|
||||
#include "spsc_overwrite_queue.hpp"
|
||||
#include "amp_condvar.hpp"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
p.iteration_count = 10000;
|
||||
//p.search_type = rl::sched_bound;
|
||||
//p.context_bound = 3;
|
||||
|
||||
rl::execute<spsc_overwrite_queue_test, 2>(p);
|
||||
rl::simulate<amp_condvar_test>(p);
|
||||
rl::simulate<amp_condvar_test2>(p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="examples"
|
||||
ProjectGUID="{1EB73A6F-7F94-4ED4-8EB3-C245E773207A}"
|
||||
RootNamespace="examples"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\amp_condvar.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\examples.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\spsc_overwrite_queue.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
template<typename T>
|
||||
class queue
|
||||
{
|
||||
public:
|
||||
queue(size_t count)
|
||||
{
|
||||
assert(count >= 6);
|
||||
sema = CreateSemaphore(0, 0, 1, 0);
|
||||
waiting.store(false, std::memory_order_relaxed);
|
||||
deq_node = 0;
|
||||
block = new node [count];
|
||||
block->next.store(0, std::memory_order_relaxed);
|
||||
full_tail = block;
|
||||
full_head.store(block, std::memory_order_relaxed);
|
||||
free_head = block + 1;
|
||||
free_tail.store(block + count - 1, std::memory_order_relaxed);
|
||||
free_tail.load(std::memory_order_relaxed)->next.store(0, std::memory_order_relaxed);
|
||||
for (size_t i = 1; i != count - 1; i += 1)
|
||||
block[i].next.store(block + i + 1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~queue()
|
||||
{
|
||||
CloseHandle(sema);
|
||||
delete [] block;
|
||||
}
|
||||
|
||||
VAR_T(T)& enqueue_prepare()
|
||||
{
|
||||
return full_tail->data;
|
||||
}
|
||||
|
||||
void enqueue_commit()
|
||||
{
|
||||
node* n = get_free_node();
|
||||
n->next.store(0, std::memory_order_release);
|
||||
full_tail->next.store(n, std::memory_order_seq_cst);
|
||||
bool signal = waiting.load(std::memory_order_seq_cst);
|
||||
full_tail = n;
|
||||
if (signal)
|
||||
{
|
||||
waiting.store(false, std::memory_order_relaxed);
|
||||
ReleaseSemaphore(sema, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
VAR_T(T)& dequeue_prepare()
|
||||
{
|
||||
deq_node = get_full_node();
|
||||
return deq_node->data;
|
||||
}
|
||||
|
||||
void dequeue_commit()
|
||||
{
|
||||
deq_node->next.store(0, std::memory_order_release);
|
||||
node* prev = free_tail.exchange(deq_node, std::memory_order_acq_rel);
|
||||
prev->next.store(deq_node, std::memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
struct node
|
||||
{
|
||||
std::atomic<node*> next;
|
||||
VAR_T(T) data;
|
||||
};
|
||||
|
||||
node* block;
|
||||
node* full_tail;
|
||||
node* free_head;
|
||||
node* deq_node;
|
||||
char pad [64];
|
||||
std::atomic<node*> full_head;
|
||||
std::atomic<node*> free_tail;
|
||||
std::atomic<bool> waiting;
|
||||
HANDLE sema;
|
||||
|
||||
node* get_free_node()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
node* n = free_head;
|
||||
node* next = n->next.load(std::memory_order_acquire);
|
||||
if (next)
|
||||
{
|
||||
free_head = next;
|
||||
return n;
|
||||
}
|
||||
|
||||
n = full_head.load(std::memory_order_acquire);
|
||||
next = n->next.load(std::memory_order_acquire);
|
||||
if (next)
|
||||
{
|
||||
if (full_head.compare_exchange_strong(n, next, std::memory_order_seq_cst))
|
||||
{
|
||||
//node* n2 = free_head;
|
||||
//node* next2 = n2->next.load(std::memory_order_acquire);
|
||||
//if (next2)
|
||||
//{
|
||||
// n->next.store(0, std::memory_order_release);
|
||||
// node* prev = free_tail.exchange(n, std::memory_order_acq_rel);
|
||||
// prev->next.store(n, std::memory_order_release);
|
||||
// free_head = next2;
|
||||
// return n2;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node* get_full_node()
|
||||
{
|
||||
node* n = full_head.load(std::memory_order_acquire);
|
||||
for (;;)
|
||||
{
|
||||
node* next = n->next.load(std::memory_order_acquire);
|
||||
if (next == 0)
|
||||
{
|
||||
waiting.store(true, std::memory_order_seq_cst);
|
||||
n = full_head.load(std::memory_order_seq_cst);
|
||||
next = n->next.load(std::memory_order_acquire);
|
||||
if (next)
|
||||
{
|
||||
waiting.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitForSingleObject(sema, INFINITE);
|
||||
n = full_head.load(std::memory_order_acquire);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (full_head.compare_exchange_strong(n, next, std::memory_order_acq_rel))
|
||||
return n;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
unsigned RL_STDCALL consumer_thread(void* ctx)
|
||||
{
|
||||
queue<int>* q = (queue<int>*)ctx;
|
||||
int prev_data = -1;
|
||||
for (;;)
|
||||
{
|
||||
VAR_T(int)& data0 = q->dequeue_prepare();
|
||||
int data = VAR(data0);
|
||||
assert(data > prev_data);
|
||||
prev_data = data;
|
||||
q->dequeue_commit();
|
||||
//printf("%d\n", prev_data);
|
||||
if (prev_data == 11)
|
||||
break;
|
||||
//Sleep(5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned RL_STDCALL producer_thread(void* ctx)
|
||||
{
|
||||
queue<int>* q = (queue<int>*)ctx;
|
||||
for (int i = 0; i != 12; i += 1)
|
||||
{
|
||||
VAR_T(int)& data = q->enqueue_prepare();
|
||||
VAR(data) = i;
|
||||
q->enqueue_commit();
|
||||
//Sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spsc_overwrite_queue_test()
|
||||
{
|
||||
queue<int> q (6);
|
||||
HANDLE th [2];
|
||||
th[0] = (HANDLE)_beginthreadex(0, 0, consumer_thread, &q, 0, 0);
|
||||
th[1] = (HANDLE)_beginthreadex(0, 0, producer_thread, &q, 0, 0);
|
||||
WaitForMultipleObjects(2, th, 1, INFINITE);
|
||||
|
||||
for (int i = 100; i != 104; i += 1)
|
||||
{
|
||||
VAR_T(int)& data = q.enqueue_prepare();
|
||||
VAR(data) = i;
|
||||
q.enqueue_commit();
|
||||
}
|
||||
|
||||
for (int i = 100; i != 104; i += 1)
|
||||
{
|
||||
VAR_T(int)& data0 = q.dequeue_prepare();
|
||||
int data = VAR(data0);
|
||||
assert(data == i);
|
||||
q.dequeue_commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_FORCE_SEQ_CST
|
||||
#define RL_MSVC_OUTPUT
|
||||
//#define RL_DEBUGBREAK_ON_FAILURE
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
#include "../../relacy/stdlib/windows.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_java.hpp"
|
||||
|
||||
|
||||
using rl::jvar;
|
||||
using rl::jvolatile;
|
||||
using rl::mutex;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ws_deque
|
||||
{
|
||||
public:
|
||||
ws_deque()
|
||||
{
|
||||
m_mask($) = initial_size - 1;
|
||||
m_headIndex($) = 0;
|
||||
m_tailIndex($) = 0;
|
||||
m_array($) = new jvar<T> [initial_size];
|
||||
m_arraySize($) = initial_size;
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return m_headIndex($) >= m_tailIndex($);
|
||||
}
|
||||
|
||||
size_t Count()
|
||||
{
|
||||
return m_tailIndex($) - m_headIndex($);
|
||||
}
|
||||
|
||||
void push(T item)
|
||||
{
|
||||
size_t tail = m_tailIndex($);
|
||||
if (tail <= m_headIndex($) + m_mask($))
|
||||
{
|
||||
m_array($)[tail & m_mask($)]($) = item;
|
||||
m_tailIndex($) = tail + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
size_t head = m_headIndex($);
|
||||
size_t count = Count();
|
||||
if (count >= m_mask($))
|
||||
{
|
||||
size_t arraySize = m_arraySize($);
|
||||
size_t mask = m_mask($);
|
||||
jvar<T>* newArray = new jvar<T> [arraySize * 2];
|
||||
jvar<T>* arr = m_array($);
|
||||
for (size_t i = 0; i != count; ++i)
|
||||
newArray[i]($) = arr[(i + head) & mask]($);
|
||||
m_array($) = newArray;
|
||||
m_arraySize($) = arraySize * 2;
|
||||
m_headIndex($) = 0;
|
||||
m_tailIndex($) = count;
|
||||
tail = count;
|
||||
m_mask($) = (mask * 2) | 1;
|
||||
}
|
||||
m_array($)[tail & m_mask($)]($) = item;
|
||||
m_tailIndex($) = tail + 1;
|
||||
m_foreignLock.unlock($);
|
||||
}
|
||||
}
|
||||
|
||||
bool pop(T& item)
|
||||
{
|
||||
size_t tail = m_tailIndex($);
|
||||
if (tail == 0)
|
||||
return false;
|
||||
tail -= 1;
|
||||
m_tailIndex($) = tail;
|
||||
if (m_headIndex($) <= tail)
|
||||
{
|
||||
item = m_array($)[tail & m_mask($)]($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
if (m_headIndex($) <= tail)
|
||||
{
|
||||
item = m_array($)[tail & m_mask($)]($);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tailIndex($) = tail + 1;
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool steal(T& item)
|
||||
{
|
||||
if (false == m_foreignLock.try_lock($))
|
||||
return false;
|
||||
size_t head = m_headIndex($);
|
||||
m_headIndex($) = head + 1;
|
||||
if (head < m_tailIndex($))
|
||||
{
|
||||
item = m_array($)[head & m_mask($)]($);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_headIndex($) = head;
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t const initial_size = 2;
|
||||
jvar<jvar<T>*> m_array;
|
||||
jvar<size_t> m_mask;
|
||||
jvar<size_t> m_arraySize;
|
||||
jvolatile<size_t> m_headIndex;
|
||||
jvolatile<size_t> m_tailIndex;
|
||||
mutex m_foreignLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ws_deque_test : rl::test_suite<ws_deque_test, 2>
|
||||
{
|
||||
ws_deque<int> q;
|
||||
bool state [2];
|
||||
|
||||
void before()
|
||||
{
|
||||
state[0] = true;
|
||||
state[1] = true;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
RL_ASSERT(state[0] == false);
|
||||
RL_ASSERT(state[1] == false);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
q.push(1);
|
||||
q.push(2);
|
||||
|
||||
int item = 0;
|
||||
bool res = q.pop(item);
|
||||
RL_ASSERT(res && item == 2);
|
||||
RL_ASSERT(state[1]);
|
||||
state[1] = false;
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
RL_ASSERT(res == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int item = 0;
|
||||
bool res = q.steal(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(item == 1);
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<ws_deque_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="java_ws_deque"
|
||||
ProjectGUID="{9E88433F-779E-4461-9963-35E3338873AC}"
|
||||
RootNamespace="java_ws_deque"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\java_ws_deque.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
|
||||
|
||||
511
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/mpmc.cpp
vendored
Normal file
511
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/mpmc.cpp
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
#ifdef RL_TEST
|
||||
#define ATOMIC(x) rl::atomic<x>
|
||||
#define VAR(x) rl::var<x>
|
||||
#define ATOMIC_FETCH_ADD(x, v) x($).fetch_add(v)
|
||||
#define ATOMIC_COMPARE_EXCHANGE(x, c, v) x($).compare_exchange(c, v)
|
||||
#define LOAD_ACQ(x) x($).load(rl::memory_order_acquire)
|
||||
#define STORE_REL(x, v) x($).store(v, rl::memory_order_release)
|
||||
#else
|
||||
#define ATOMIC(x) x volatile
|
||||
#define VAR(x) x
|
||||
#define ATOMIC_FETCH_ADD(x, v) _InterlockedExchangeAdd((long*)&x, v)
|
||||
#define ATOMIC_COMPARE_EXCHANGE(x, c, v) interlocked_compare_exchange(x, c, v)
|
||||
#define LOAD_ACQ(x) x
|
||||
#define STORE_REL(x, v) x = v
|
||||
|
||||
template<typename T>
|
||||
bool interlocked_compare_exchange(T& x, T& c, T v)
|
||||
{
|
||||
T c0 = _InterlockedCompareExchange((long*)&x), v, c);
|
||||
if (c0 == c)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = c0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#include "pcx.h"
|
||||
|
||||
|
||||
/*
|
||||
template<typename T>
|
||||
class mpmcq
|
||||
{
|
||||
public:
|
||||
mpmcq()
|
||||
{
|
||||
STORE_REL(head_, alloc_block());
|
||||
STORE_REL(tail_, LOAD_ACQ(head_));
|
||||
}
|
||||
|
||||
void enqueue(T v)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
block* b = LOAD_ACQ(head_);
|
||||
unsigned raw = ATOMIC_FETCH_ADD(b->state_, state_head_inc);
|
||||
unsigned idx = raw >> state_head_pos;
|
||||
if (idx < item_count)
|
||||
{
|
||||
STORE_REL(b->data_[idx], v);
|
||||
return;
|
||||
}
|
||||
unsigned last = raw & state_last_msk;
|
||||
if (0 == last)
|
||||
{
|
||||
ATOMIC_COMPARE_EXCHANGE(head_, b, b+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
block* b2 = LOAD_ACQ(b->next_);
|
||||
if (b2)
|
||||
{
|
||||
ATOMIC_COMPARE_EXCHANGE(head_, b, b2);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2 = alloc_block();
|
||||
block* b3 = 0;
|
||||
if (ATOMIC_COMPARE_EXCHANGE(b->next_, b3, b2))
|
||||
{
|
||||
ATOMIC_COMPARE_EXCHANGE(head_, b, b2);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
b = LOAD_ACQ(head_);
|
||||
while (0 == (LOAD_ACQ(b->state_) & state_last_msk))
|
||||
b = b + 1;
|
||||
while (LOAD_ACQ(b->next_))
|
||||
b = LOAD_ACQ(b->next_) + block_count - 1;
|
||||
b3 = 0;
|
||||
if (ATOMIC_COMPARE_EXCHANGE(b->next_, b3, b2))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T dequeue()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
block* b = LOAD_ACQ(tail_);
|
||||
unsigned cmp = LOAD_ACQ(b->state_);
|
||||
unsigned tail = cmp & (state_last_msk - 1);
|
||||
if (tail < item_count)
|
||||
{
|
||||
unsigned head = cmp >> state_head_pos;
|
||||
if (tail < head)
|
||||
{
|
||||
unsigned xchg = cmp + state_tail_inc;
|
||||
if (ATOMIC_COMPARE_EXCHANGE(b->state_, cmp, xchg))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
T v = LOAD_ACQ(b->data_[tail]);
|
||||
if (v != T())
|
||||
return v;
|
||||
rl::yield($);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return T();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned last = cmp & state_last_msk;
|
||||
if (0 == last)
|
||||
{
|
||||
ATOMIC_COMPARE_EXCHANGE(tail_, b, b+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
block* b2 = LOAD_ACQ(b->next_);
|
||||
if (0 == b2)
|
||||
return T();
|
||||
ATOMIC_COMPARE_EXCHANGE(tail_, b, b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static unsigned const state_head_pos = 7;
|
||||
static unsigned const state_head_inc = 1 << state_head_pos;
|
||||
static unsigned const state_last_msk = 1 << 6;
|
||||
static unsigned const state_tail_inc = 1 << 0;
|
||||
|
||||
static unsigned const item_count = 2;
|
||||
static unsigned const block_count = 16;
|
||||
|
||||
struct block
|
||||
{
|
||||
//unsigned head_ : 24;
|
||||
//unsigned last_ : 1;
|
||||
//unsigned tail_ : 7;
|
||||
ATOMIC(unsigned) state_;
|
||||
ATOMIC(block*) next_;
|
||||
ATOMIC(T) data_ [item_count];
|
||||
};
|
||||
|
||||
struct superblock
|
||||
{
|
||||
block blocks_ [block_count];
|
||||
};
|
||||
|
||||
char pad0_ [64];
|
||||
ATOMIC(block*) head_;
|
||||
char pad1_ [64];
|
||||
ATOMIC(block*) tail_;
|
||||
char pad2_ [64];
|
||||
|
||||
block* alloc_block()
|
||||
{
|
||||
superblock* sb = RL_NEW(superblock);
|
||||
for (int x = 0; x != block_count; ++x)
|
||||
{
|
||||
block* b = &sb->blocks_[x];
|
||||
STORE_REL(b->state_, 0);
|
||||
STORE_REL(b->next_, 0);
|
||||
for (int y = 0; y != item_count; ++y)
|
||||
{
|
||||
STORE_REL(b->data_[y], 0);
|
||||
}
|
||||
}
|
||||
STORE_REL(sb->blocks_[block_count - 1].state_, 1 * state_head_inc + 1 * state_tail_inc + state_last_msk);
|
||||
return &sb->blocks_[0];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct test_mpmc : rl::test_suite<test_mpmc, 6>
|
||||
{
|
||||
mpmcq<int> q;
|
||||
|
||||
void thread(unsigned idx)
|
||||
{
|
||||
if (idx < thread_count / 2)
|
||||
{
|
||||
for (int i = 0; i != 2; ++i)
|
||||
q.enqueue(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i != 2; ++i)
|
||||
q.dequeue();
|
||||
}
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct thread_node
|
||||
{
|
||||
rl::var<thread_node*> next;
|
||||
rl::var<size_t> count;
|
||||
rl::var<size_t> unconsumed;
|
||||
rl::HANDLE sema;
|
||||
rl::CRITICAL_SECTION mtx;
|
||||
};
|
||||
|
||||
|
||||
void on_thread_exit(thread_node*& t_thread_node)
|
||||
{
|
||||
thread_node* head = t_thread_node;
|
||||
thread_node* my = 0;
|
||||
if (head)
|
||||
{
|
||||
rl::EnterCriticalSection(&head->mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
if (head->next($))
|
||||
{
|
||||
my = head->next($);
|
||||
head->next($) = (thread_node*)my->next($);
|
||||
}
|
||||
else
|
||||
{
|
||||
my = head;
|
||||
}
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&head->mtx, $);
|
||||
|
||||
while (my->unconsumed($))
|
||||
{
|
||||
rl::WaitForSingleObject(my->sema, rl::RL_INFINITE, $);
|
||||
my->unconsumed($) -= 1;
|
||||
}
|
||||
|
||||
rl::DeleteCriticalSection(&my->mtx, $);
|
||||
rl::CloseHandle(my->sema, $);
|
||||
RL_DELETE(my);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct eventcount
|
||||
{
|
||||
eventcount()
|
||||
{
|
||||
root($) = 0;
|
||||
rl::InitializeCriticalSection(&mtx, $);
|
||||
}
|
||||
|
||||
~eventcount()
|
||||
{
|
||||
rl::DeleteCriticalSection(&mtx, $);
|
||||
}
|
||||
|
||||
void prepare_wait(thread_node*& t_thread_node)
|
||||
{
|
||||
thread_node* my = 0;
|
||||
thread_node* head = t_thread_node;
|
||||
if (head)
|
||||
{
|
||||
rl::EnterCriticalSection(&head->mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
//RL_ASSERT(head->status == stat_root);
|
||||
RL_ASSERT (root($) != head);
|
||||
if (head->next($))
|
||||
{
|
||||
my = head->next($);
|
||||
head->next($) = (thread_node*)my->next($);
|
||||
my->next($) = 0;
|
||||
|
||||
//node_status st;
|
||||
//if (stat_bucket != (st = (node_status)_InterlockedExchange(&my->status, stat_private)))
|
||||
// __asm int 3;
|
||||
RL_ASSERT (0 == my->count($));
|
||||
}
|
||||
else
|
||||
{
|
||||
my = head;
|
||||
|
||||
//node_status st;
|
||||
//if (stat_root != (st = (node_status)_InterlockedExchange(&my->status, stat_private)))
|
||||
// __asm int 3;
|
||||
RL_ASSERT(0 == my->count($));
|
||||
}
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&head->mtx, $);
|
||||
}
|
||||
else
|
||||
{
|
||||
my = RL_NEW thread_node;
|
||||
my->next($) = 0;
|
||||
my->count($) = 0;
|
||||
my->unconsumed($) = 0;
|
||||
my->sema = rl::CreateSemaphore(0, 0, LONG_MAX, 0, $);
|
||||
//my->status = stat_private;
|
||||
rl::InitializeCriticalSection(&my->mtx, $);
|
||||
}
|
||||
|
||||
while (my->unconsumed($))
|
||||
{
|
||||
rl::WaitForSingleObject(my->sema, rl::RL_INFINITE, $);
|
||||
my->unconsumed($) -= 1;
|
||||
}
|
||||
|
||||
RL_ASSERT(0 == my->next($));
|
||||
RL_ASSERT(0 == my->count($));
|
||||
//if (my->status != stat_private) __asm int 3;
|
||||
|
||||
rl::EnterCriticalSection(&mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
RL_ASSERT(root($) != my);
|
||||
if (root($))
|
||||
{
|
||||
my->next($) = (thread_node*)((thread_node*)root($))->next($);
|
||||
((thread_node*)root($))->next($) = my;
|
||||
|
||||
//node_status st;
|
||||
//if (stat_private != (st = (node_status)_InterlockedExchange(&my->status, stat_bucket)))
|
||||
// __asm int 3;
|
||||
|
||||
my = root($);
|
||||
}
|
||||
else
|
||||
{
|
||||
root($) = my;
|
||||
|
||||
//node_status st;
|
||||
//if (stat_private != (st = (node_status)_InterlockedExchange(&my->status, stat_root)))
|
||||
// __asm int 3;
|
||||
}
|
||||
((thread_node*)root($))->count($) += 1;
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&mtx, $);
|
||||
t_thread_node = my;
|
||||
}
|
||||
|
||||
void wait(thread_node*& t_thread_node)
|
||||
{
|
||||
thread_node* head = t_thread_node;
|
||||
if (head == root($))
|
||||
{
|
||||
rl::WaitForSingleObject(head->sema, rl::RL_INFINITE, $);
|
||||
}
|
||||
else
|
||||
{
|
||||
rl::EnterCriticalSection(&head->mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
head->unconsumed($) += 1;
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&head->mtx, $);
|
||||
}
|
||||
}
|
||||
|
||||
void retire_wait(thread_node*& t_thread_node)
|
||||
{
|
||||
thread_node* head = t_thread_node;
|
||||
if (head == root($))
|
||||
{
|
||||
rl::EnterCriticalSection(&mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
if (head == root($))
|
||||
{
|
||||
thread_node* my = 0;
|
||||
head->count($) -= 1;
|
||||
if (head->next($))
|
||||
{
|
||||
my = head->next($);
|
||||
head->next($) = (thread_node*)my->next($);
|
||||
my->next($) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
my = head;
|
||||
root($) = 0;
|
||||
}
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&mtx, $);
|
||||
//my->status = stat_root;
|
||||
t_thread_node = my;
|
||||
return;
|
||||
}
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&mtx, $);
|
||||
}
|
||||
rl::EnterCriticalSection(&head->mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
head->unconsumed($) += 1;
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&head->mtx, $);
|
||||
}
|
||||
|
||||
void signal_all()
|
||||
{
|
||||
//std::
|
||||
//_mm_mfence();
|
||||
thread_node* head = root($);
|
||||
if (0 == head)
|
||||
return;
|
||||
rl::EnterCriticalSection(&mtx, $);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
if (head != root($))
|
||||
{
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&mtx, $);
|
||||
return;
|
||||
}
|
||||
size_t count = head->count($);
|
||||
head->count($) = 0;
|
||||
root($) = 0;
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
rl::LeaveCriticalSection(&mtx, $);
|
||||
rl::ReleaseSemaphore(head->sema, count, 0, $);
|
||||
}
|
||||
|
||||
std::atomic<thread_node*> root;
|
||||
rl::CRITICAL_SECTION mtx;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct test_ec : rl::test_suite<test_ec, 8>
|
||||
{
|
||||
std::atomic<int> x [2];
|
||||
eventcount ec;
|
||||
|
||||
void before()
|
||||
{
|
||||
x[0]($) = 0;
|
||||
x[1]($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned idx)
|
||||
{
|
||||
if (idx < 4)
|
||||
{
|
||||
for (int i = 0; i != 3; ++i)
|
||||
{
|
||||
x[idx % 2]($).fetch_add(1);
|
||||
ec.signal_all();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_node* my = 0;
|
||||
for (int i = 0; i != 3; ++i)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int cmp = x[idx % 2]($);
|
||||
if (cmp > 0)
|
||||
{
|
||||
if (x[idx % 2]($).compare_exchange(cmp, cmp - 1))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
ec.prepare_wait(my);
|
||||
cmp = x[idx % 2]($);
|
||||
if (cmp > 0)
|
||||
{
|
||||
ec.retire_wait(my);
|
||||
break;
|
||||
}
|
||||
ec.wait(my);
|
||||
cmp = x[idx % 2]($);
|
||||
if (cmp > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
on_thread_exit(my);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
p.iteration_count = 20000000;
|
||||
p.initial_state = "10000000";
|
||||
rl::simulate<test_ec>(p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="mpmc"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}"
|
||||
RootNamespace="mpmc"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\mpmc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\pcx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
481
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/pcx.h
vendored
Normal file
481
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/pcx.h
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
#pragma once
|
||||
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic (_InterlockedExchangeAdd)
|
||||
#pragma intrinsic (_InterlockedCompareExchange)
|
||||
|
||||
//#define PCX_DEBUG
|
||||
|
||||
#ifdef PCX_DEBUG
|
||||
#include <sstream>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
size_t const cacheline_size = 64;
|
||||
|
||||
struct pcx_node
|
||||
{
|
||||
typedef void (*pcx_dtor_t)(pcx_node*);
|
||||
ATOMIC(pcx_node*) pcx_next_;
|
||||
ATOMIC(pcx_dtor_t) pcx_dtor_;
|
||||
};
|
||||
|
||||
namespace pcx_int
|
||||
{
|
||||
unsigned const word_bits = 32;
|
||||
unsigned const collector_bits = 4;
|
||||
unsigned const collector_count = 1 << collector_bits;
|
||||
unsigned const counter_inc = 1 << (collector_bits * 2);
|
||||
unsigned const is_current_inc = 1;
|
||||
unsigned const back_link_inc = 2;
|
||||
|
||||
struct master;
|
||||
struct collector;
|
||||
|
||||
struct local_collector
|
||||
{
|
||||
pcx_node* defer_head_;
|
||||
pcx_node defer_tail_;
|
||||
unsigned defer_size_;
|
||||
};
|
||||
|
||||
struct thread_int
|
||||
{
|
||||
pcx_int::master* master_;
|
||||
pcx_int::collector* collectors_;
|
||||
unsigned recursion_count_;
|
||||
unsigned is_acquired_;
|
||||
unsigned collector_index_;
|
||||
unsigned last_seen_collector_index_;
|
||||
unsigned flush_tail_;
|
||||
pcx_node* defer_head_;
|
||||
pcx_node defer_tail_;
|
||||
unsigned defer_size_;
|
||||
unsigned promote_;
|
||||
local_collector local_collectors_ [collector_count];
|
||||
};
|
||||
}
|
||||
|
||||
class pcx_thread : private pcx_int::thread_int
|
||||
{
|
||||
public:
|
||||
static pcx_thread& get();
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
void defer(pcx_node* node, pcx_node::pcx_dtor_t dtor);
|
||||
void flush();
|
||||
void promote();
|
||||
void quiescent();
|
||||
|
||||
void init();
|
||||
void deinit();
|
||||
|
||||
private:
|
||||
unsigned acquire_impl();
|
||||
void release_impl(unsigned, unsigned);
|
||||
void flush_impl();
|
||||
void local_flush();
|
||||
void quiescent_impl();
|
||||
friend void init();
|
||||
friend void deinit();
|
||||
friend void thread_callback(bool);
|
||||
};
|
||||
|
||||
namespace pcx_int
|
||||
{
|
||||
struct master
|
||||
{
|
||||
char pad0_ [64];
|
||||
|
||||
unsigned garbage_threshold_;
|
||||
|
||||
char pad1_ [64];
|
||||
|
||||
struct state_part
|
||||
{
|
||||
unsigned current_collector_ : collector_bits;
|
||||
unsigned collector_tail_ : collector_bits;
|
||||
unsigned outer_counter_ : word_bits - 2 * collector_bits;
|
||||
};
|
||||
|
||||
union state
|
||||
{
|
||||
long whole_;
|
||||
state_part part_;
|
||||
};
|
||||
|
||||
state state_;
|
||||
|
||||
char pad2_ [64];
|
||||
|
||||
state state_copy_;
|
||||
|
||||
char pad3_ [64];
|
||||
};
|
||||
|
||||
struct collector
|
||||
{
|
||||
char pad0_ [64];
|
||||
|
||||
pcx_node* defer_list_head_;
|
||||
unsigned defer_list_size_;
|
||||
|
||||
char pad1_ [64];
|
||||
|
||||
struct state_part
|
||||
{
|
||||
unsigned is_current_ : 1;
|
||||
unsigned back_link_ : 1;
|
||||
unsigned pad_ : collector_bits * 2 - 2;
|
||||
unsigned inner_counter_ : word_bits - 2 * collector_bits;
|
||||
};
|
||||
|
||||
union state
|
||||
{
|
||||
long whole_;
|
||||
state_part part_;
|
||||
};
|
||||
|
||||
state state_;
|
||||
|
||||
char pad2_ [64];
|
||||
};
|
||||
|
||||
__declspec(selectany)
|
||||
master g_master;
|
||||
__declspec(selectany)
|
||||
collector g_collectors [collector_count];
|
||||
__declspec(selectany, thread)
|
||||
thread_int* g_thread_instance;
|
||||
|
||||
typedef void (__stdcall nt_tls_cb_t)(void*, unsigned long, void*);
|
||||
nt_tls_cb_t on_tls_callback;
|
||||
|
||||
#pragma data_seg(push, old_seg)
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
__declspec(selectany, dllexport)
|
||||
nt_tls_cb_t* volatile p_thread_callback = on_tls_callback;
|
||||
#pragma data_seg(pop, old_seg)
|
||||
|
||||
inline void __stdcall on_tls_callback(void*, unsigned long reason, void*)
|
||||
{
|
||||
if (1 == reason)
|
||||
{
|
||||
init();
|
||||
thread_callback(true);
|
||||
}
|
||||
else if (0 == reason)
|
||||
{
|
||||
thread_callback(false);
|
||||
deinit();
|
||||
}
|
||||
if (2 == reason)
|
||||
{
|
||||
thread_callback(true);
|
||||
}
|
||||
else if (3 == reason)
|
||||
{
|
||||
thread_callback(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void init()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
master& m = g_master;
|
||||
m.garbage_threshold_ = 128;
|
||||
m.state_.part_.current_collector_ = 0;
|
||||
m.state_.part_.collector_tail_ = 0;
|
||||
m.state_.part_.outer_counter_ = 0;
|
||||
m.state_copy_.part_.current_collector_ = 0;
|
||||
m.state_copy_.part_.collector_tail_ = 0;
|
||||
m.state_copy_.part_.outer_counter_ = 0;
|
||||
for (unsigned i = 0; i != collector_count; ++i)
|
||||
{
|
||||
collector& c = g_collectors[i];
|
||||
c.defer_list_head_ = 0;
|
||||
c.defer_list_size_ = 0;
|
||||
c.state_.part_.is_current_ = 1;
|
||||
c.state_.part_.back_link_ = 1;
|
||||
c.state_.part_.inner_counter_ = 0;
|
||||
}
|
||||
g_collectors[0].state_.part_.back_link_ = 0;
|
||||
}
|
||||
|
||||
inline void deinit()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
pcx_thread::get().release_impl(g_master.state_.part_.current_collector_, is_current_inc);
|
||||
}
|
||||
|
||||
inline void thread_callback(bool init)
|
||||
{
|
||||
if (init)
|
||||
{
|
||||
g_thread_instance = RL_NEW pcx_thread ();
|
||||
pcx_thread::get().init();
|
||||
}
|
||||
else
|
||||
{
|
||||
pcx_thread::get().deinit();
|
||||
RL_DELETE(g_thread_instance);
|
||||
g_thread_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline pcx_thread& pcx_thread::get()
|
||||
{
|
||||
return static_cast<pcx_thread&>(*pcx_int::g_thread_instance);
|
||||
}
|
||||
|
||||
inline unsigned pcx_thread::acquire_impl()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
long const prev =
|
||||
_InterlockedExchangeAdd(
|
||||
&master_->state_.whole_, counter_inc);
|
||||
master::state_part u = {prev};
|
||||
|
||||
#ifdef PCX_DEBUG
|
||||
std::ostringstream ss;
|
||||
ss << "[PCX] thread " << this << " acquire " << u.current_collector_ << "\n";
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
#endif
|
||||
|
||||
if (u.current_collector_ == flush_tail_
|
||||
&& local_collectors_[flush_tail_].defer_size_)
|
||||
{
|
||||
local_flush();
|
||||
}
|
||||
|
||||
return u.current_collector_;
|
||||
}
|
||||
|
||||
inline void pcx_thread::release_impl(unsigned index, unsigned count)
|
||||
{
|
||||
using namespace pcx_int;
|
||||
collector& c = collectors_[index];
|
||||
unsigned const prev =
|
||||
_InterlockedExchangeAdd(
|
||||
&c.state_.whole_, (unsigned)-(int)count);
|
||||
|
||||
#ifdef PCX_DEBUG
|
||||
std::ostringstream ss;
|
||||
ss << "[PCX] thread " << this << " release " << index << "\n";
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
#endif
|
||||
|
||||
if (0 == prev - count)
|
||||
{
|
||||
pcx_node* curr = c.defer_list_head_;
|
||||
while (curr)
|
||||
{
|
||||
pcx_node* next = curr->pcx_next_;
|
||||
curr->pcx_dtor_(curr);
|
||||
curr = next;
|
||||
}
|
||||
c.defer_list_head_ = 0;
|
||||
c.defer_list_size_ = 0;
|
||||
c.state_.part_.back_link_ = 1;
|
||||
c.state_.part_.is_current_ = 1;
|
||||
|
||||
long u;
|
||||
if (index != collector_count - 1)
|
||||
u = collector_count;
|
||||
else
|
||||
u = -(long)(collector_count * (collector_count - 1));
|
||||
_InterlockedExchangeAdd(&master_->state_.whole_, u);
|
||||
|
||||
release_impl((index + 1) % collector_count, back_link_inc);
|
||||
}
|
||||
}
|
||||
|
||||
inline void pcx_thread::flush_impl()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
_mm_mfence();
|
||||
master::state state = master_->state_;
|
||||
last_seen_collector_index_ = state.part_.current_collector_;
|
||||
collector& gc = collectors_[state.part_.current_collector_];
|
||||
local_collector& lc = local_collectors_[state.part_.current_collector_];
|
||||
lc.defer_head_->pcx_next_ = defer_tail_.pcx_next_;
|
||||
lc.defer_head_ = defer_tail_.pcx_next_;
|
||||
lc.defer_size_ += defer_size_;
|
||||
defer_head_ = &defer_tail_;
|
||||
defer_tail_.pcx_next_ = 0;
|
||||
defer_size_ = 0;
|
||||
if (master_->garbage_threshold_ < lc.defer_size_ || promote_)
|
||||
{
|
||||
master::state cmp;
|
||||
master::state val;
|
||||
do
|
||||
{
|
||||
cmp = master_->state_;
|
||||
if (cmp.part_.current_collector_ != last_seen_collector_index_)
|
||||
{
|
||||
promote_ = 0;
|
||||
return;
|
||||
}
|
||||
unsigned next_index = (last_seen_collector_index_ + 1) % collector_count;
|
||||
if (cmp.part_.collector_tail_ == next_index)
|
||||
return;
|
||||
val = cmp;
|
||||
val.part_.current_collector_ += 1;
|
||||
val.part_.outer_counter_ = 0;
|
||||
}
|
||||
while (cmp.whole_ != _InterlockedCompareExchange(
|
||||
(long*)&master_->state_.whole_, val.whole_, cmp.whole_));
|
||||
last_seen_collector_index_ = val.part_.current_collector_;
|
||||
promote_ = 0;
|
||||
_InterlockedIncrement((long*)&master_->state_copy_.whole_);
|
||||
_InterlockedExchangeAdd((long*)&gc.state_.whole_,
|
||||
cmp.part_.outer_counter_ * counter_inc - is_current_inc);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(noinline)
|
||||
inline void pcx_thread::local_flush()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
if (flush_tail_ == master_->state_.part_.collector_tail_)
|
||||
return;
|
||||
|
||||
#ifdef PCX_DEBUG
|
||||
std::ostringstream ss;
|
||||
ss << "[PCX] thread " << this << " flush " << flush_tail_ << "\n";
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
#endif
|
||||
|
||||
local_collector& lc = local_collectors_[flush_tail_];
|
||||
pcx_node* curr = lc.defer_tail_.pcx_next_;
|
||||
while (curr)
|
||||
{
|
||||
#ifdef PCX_DEBUG
|
||||
std::ostringstream ss;
|
||||
ss << "[PCX] thread " << this << " destroy " << curr << "\n";
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
#endif
|
||||
|
||||
pcx_node* next = curr->pcx_next_;
|
||||
curr->pcx_dtor_(curr);
|
||||
curr = next;
|
||||
}
|
||||
lc.defer_head_ = &lc.defer_tail_;
|
||||
lc.defer_tail_.pcx_next_ = 0;
|
||||
lc.defer_size_ = 0;
|
||||
flush_tail_ = (flush_tail_ + 1) % collector_count;
|
||||
}
|
||||
|
||||
__declspec(noinline)
|
||||
inline void pcx_thread::quiescent_impl()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
if (defer_size_)
|
||||
flush_impl();
|
||||
release_impl(collector_index_, counter_inc);
|
||||
collector_index_ = acquire_impl();
|
||||
}
|
||||
|
||||
inline void pcx_thread::acquire()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
recursion_count_ += 1;
|
||||
if (1 != recursion_count_)
|
||||
return;
|
||||
if (is_acquired_)
|
||||
return;
|
||||
collector_index_ = acquire_impl();
|
||||
last_seen_collector_index_ = collector_index_;
|
||||
is_acquired_ = 1;
|
||||
}
|
||||
|
||||
inline void pcx_thread::release()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
recursion_count_ -= 1;
|
||||
if (0 == recursion_count_)
|
||||
{
|
||||
if (master_->state_copy_.part_.current_collector_ != collector_index_
|
||||
|| promote_)
|
||||
{
|
||||
if (defer_size_)
|
||||
flush_impl();
|
||||
release_impl(collector_index_, counter_inc);
|
||||
is_acquired_ = 0;
|
||||
}
|
||||
}
|
||||
if (flush_tail_ != last_seen_collector_index_)
|
||||
{
|
||||
local_flush();
|
||||
}
|
||||
}
|
||||
|
||||
inline void pcx_thread::quiescent()
|
||||
{
|
||||
if (master_->state_copy_.part_.current_collector_ != collector_index_
|
||||
|| promote_)
|
||||
{
|
||||
quiescent_impl();
|
||||
}
|
||||
if (flush_tail_ != last_seen_collector_index_)
|
||||
{
|
||||
local_flush();
|
||||
}
|
||||
}
|
||||
|
||||
inline void pcx_thread::defer(pcx_node* node, pcx_node::pcx_dtor_t dtor)
|
||||
{
|
||||
using namespace pcx_int;
|
||||
node->pcx_next_ = 0;
|
||||
node->pcx_dtor_ = dtor;
|
||||
defer_head_->pcx_next_ = node;
|
||||
defer_head_ = node;
|
||||
defer_size_ += 1;
|
||||
}
|
||||
|
||||
inline void pcx_thread::flush()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
if (recursion_count_)
|
||||
return;
|
||||
if (0 == is_acquired_)
|
||||
return;
|
||||
if (defer_size_)
|
||||
flush_impl();
|
||||
release_impl(collector_index_, counter_inc);
|
||||
is_acquired_ = 0;
|
||||
}
|
||||
|
||||
inline void pcx_thread::promote()
|
||||
{
|
||||
promote_ = 1;
|
||||
}
|
||||
|
||||
inline void pcx_thread::init()
|
||||
{
|
||||
using namespace pcx_int;
|
||||
master_ = &g_master;
|
||||
collectors_ = g_collectors;
|
||||
defer_head_ = &defer_tail_;
|
||||
defer_tail_.pcx_next_ = 0;
|
||||
for (unsigned i = 0; i != collector_count; ++i)
|
||||
{
|
||||
local_collectors_[i].defer_head_ = &local_collectors_[i].defer_tail_;
|
||||
}
|
||||
}
|
||||
|
||||
inline void pcx_thread::deinit()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ws_deque.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
10
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/stdafx.h
vendored
Normal file
10
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/mpmc/stdafx.h
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#pragma warning (disable: 4201)
|
||||
|
||||
//#define RL_GC
|
||||
#define RL_MSVC_OUTPUT
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="mutex_business_logic"
|
||||
ProjectGUID="{B03A7216-E196-44C6-8861-C77D90055512}"
|
||||
RootNamespace="mutex_business_logic"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\mutex_business_logic.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,131 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
class business_logic
|
||||
{
|
||||
public:
|
||||
typedef unsigned account_id_t;
|
||||
typedef double balance_t;
|
||||
|
||||
business_logic()
|
||||
{
|
||||
pthread_rwlock_init(&accounts_guard, 0);
|
||||
}
|
||||
|
||||
~business_logic()
|
||||
{
|
||||
pthread_rwlock_destroy(&accounts_guard);
|
||||
}
|
||||
|
||||
bool add_account(account_id_t acc_id, balance_t balance)
|
||||
{
|
||||
pthread_rwlock_wrlock(&accounts_guard);
|
||||
if (accounts.find(acc_id) != accounts.end())
|
||||
{
|
||||
pthread_rwlock_unlock(&accounts_guard);
|
||||
return false;
|
||||
}
|
||||
accounts[acc_id].balance = balance;
|
||||
pthread_rwlock_unlock(&accounts_guard);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
|
||||
{
|
||||
if (acc_id1 == acc_id2)
|
||||
return true;
|
||||
pthread_rwlock_rdlock(&accounts_guard);
|
||||
if (accounts.find(acc_id1) == accounts.end()
|
||||
|| accounts.find(acc_id2) == accounts.end())
|
||||
{
|
||||
pthread_rwlock_unlock(&accounts_guard);
|
||||
return false;
|
||||
}
|
||||
account_info& acc1 = accounts[acc_id1];
|
||||
account_info& acc2 = accounts[acc_id2];
|
||||
if (acc_id1 > acc_id2)
|
||||
{
|
||||
pthread_mutex_lock(&acc1.mtx);
|
||||
pthread_mutex_lock(&acc2.mtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&acc2.mtx);
|
||||
pthread_mutex_lock(&acc1.mtx);
|
||||
}
|
||||
pthread_rwlock_unlock(&accounts_guard);
|
||||
|
||||
acc1.balance -= amount;
|
||||
acc2.balance += amount;
|
||||
|
||||
pthread_mutex_unlock(&acc1.mtx);
|
||||
pthread_mutex_unlock(&acc2.mtx);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct account_info
|
||||
{
|
||||
balance_t balance;
|
||||
pthread_mutex_t mtx;
|
||||
|
||||
account_info()
|
||||
: balance()
|
||||
{
|
||||
pthread_mutex_init(&mtx, 0);
|
||||
}
|
||||
|
||||
account_info(account_info const& acc)
|
||||
: balance(acc.balance)
|
||||
{
|
||||
pthread_mutex_init(&mtx, 0);
|
||||
}
|
||||
|
||||
~account_info()
|
||||
{
|
||||
pthread_mutex_destroy(&mtx);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<account_id_t, account_info> account_map_t;
|
||||
account_map_t accounts;
|
||||
pthread_rwlock_t accounts_guard;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct business_logic_test : rl::test_suite<business_logic_test, 2>
|
||||
{
|
||||
business_logic bl;
|
||||
|
||||
static size_t const account_count = 4;
|
||||
|
||||
void before()
|
||||
{
|
||||
for (size_t i = 0; i != account_count; ++i)
|
||||
{
|
||||
bool rv = bl.add_account(i, i * 10.0);
|
||||
RL_ASSERT(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void thread(unsigned /*index*/)
|
||||
{
|
||||
business_logic::account_id_t acc1 = rl::rand(account_count);
|
||||
business_logic::account_id_t acc2 = rl::rand(account_count);
|
||||
bool rv = bl.transfer_balance(acc1, acc2, 1.0);
|
||||
RL_ASSERT(rv);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<business_logic_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_MSVC_OUTPUT
|
||||
//#define RL_DEBUGBREAK_ON_FAILURE
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="peterson"
|
||||
ProjectGUID="{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
|
||||
RootNamespace="peterson"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\peterson.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="peterson"
|
||||
ProjectGUID="{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
|
||||
RootNamespace="peterson"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\peterson.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,469 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
#include "../../relacy/windows.h"
|
||||
|
||||
|
||||
struct peterson_mutex_test : rl::test_suite<peterson_mutex_test, 2>
|
||||
{
|
||||
std::atomic<int> flag0;
|
||||
std::atomic<int> flag1;
|
||||
std::atomic<int> turn;
|
||||
|
||||
rl::var<int> data;
|
||||
|
||||
void before()
|
||||
{
|
||||
flag0($) = 0;
|
||||
flag1($) = 0;
|
||||
turn($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
flag0($).store(1);
|
||||
turn($).store(1);
|
||||
|
||||
while (flag1($).load()
|
||||
&& 1 == turn($).load());
|
||||
|
||||
data($) = 1;
|
||||
|
||||
flag0($).store(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag1($).store(1);
|
||||
turn($).store(0);
|
||||
|
||||
while (flag0($).load()
|
||||
&& 0 == turn($).load());
|
||||
|
||||
data($) = 2;
|
||||
|
||||
flag1($).store(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct peterson_mutex_test2 : rl::test_suite<peterson_mutex_test2, 2>
|
||||
{
|
||||
std::atomic<int> flag0;
|
||||
std::atomic<int> flag1;
|
||||
std::atomic<int> turn;
|
||||
|
||||
rl::var<int> data;
|
||||
|
||||
void before()
|
||||
{
|
||||
flag0($) = 0;
|
||||
flag1($) = 0;
|
||||
turn($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
flag0.store(1, rl::memory_order_relaxed);
|
||||
turn.exchange(1, rl::memory_order_acq_rel);
|
||||
|
||||
while (flag1.load(rl::memory_order_acquire)
|
||||
&& 1 == turn.load(rl::memory_order_relaxed))
|
||||
rl::yield(1, $);
|
||||
|
||||
data($) = 1;
|
||||
|
||||
flag0.store(0, rl::memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag1.store(1, rl::memory_order_relaxed);
|
||||
turn.exchange(0, rl::memory_order_acq_rel);
|
||||
|
||||
while (flag0.load(rl::memory_order_acquire)
|
||||
&& 0 == turn.load(rl::memory_order_relaxed))
|
||||
rl::yield(1, $);
|
||||
|
||||
data($) = 2;
|
||||
|
||||
flag1.store(0, rl::memory_order_release);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct peterson_mutex_test3 : rl::test_suite<peterson_mutex_test3, 2>
|
||||
{
|
||||
std::atomic<int> flag0;
|
||||
std::atomic<int> flag1;
|
||||
std::atomic<int> turn;
|
||||
|
||||
rl::var<int> data;
|
||||
|
||||
void before()
|
||||
{
|
||||
flag0($) = 0;
|
||||
flag1($) = 0;
|
||||
turn($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
flag0.store(1, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
turn.store(1, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
while (flag1.load(std::memory_order_acquire)
|
||||
&& 1 == turn.load(std::memory_order_relaxed));
|
||||
|
||||
data($) = 1;
|
||||
|
||||
flag0.store(0, std::memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag1.store(1, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
turn.store(0, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
while (flag0.load(std::memory_order_acquire)
|
||||
&& 0 == turn.load(std::memory_order_relaxed));
|
||||
|
||||
data($) = 2;
|
||||
|
||||
flag1.store(0, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// FAILS WITH DATA RACE
|
||||
struct peterson_mutex_test4 : rl::test_suite<peterson_mutex_test4, 2>
|
||||
{
|
||||
std::atomic<int> flag0;
|
||||
std::atomic<int> flag1;
|
||||
std::atomic<int> turn;
|
||||
|
||||
rl::var<int> data;
|
||||
|
||||
void before()
|
||||
{
|
||||
flag0($) = 0;
|
||||
flag1($) = 0;
|
||||
turn($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
flag0.exchange(1, rl::memory_order_acq_rel);
|
||||
turn.store(1, rl::memory_order_release);
|
||||
|
||||
while (flag1.load(rl::memory_order_acquire)
|
||||
&& 1 == turn.load(rl::memory_order_acquire))
|
||||
rl::yield(1, $);
|
||||
|
||||
data($) = 1;
|
||||
|
||||
flag0.store(0, rl::memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag1.exchange(1, rl::memory_order_acq_rel);
|
||||
turn.store(0, rl::memory_order_release);
|
||||
|
||||
while (flag0.load(rl::memory_order_acquire)
|
||||
&& 0 == turn.load(rl::memory_order_relaxed))
|
||||
rl::yield(1, $);
|
||||
|
||||
data($) = 2;
|
||||
|
||||
flag1.store(0, rl::memory_order_release);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class eventcount
|
||||
{
|
||||
public:
|
||||
typedef unsigned state_t;
|
||||
|
||||
eventcount()
|
||||
{
|
||||
state_.store(0, std::memory_order_relaxed);
|
||||
sema_ = CreateSemaphore(0, 0, LONG_MAX, 0);
|
||||
}
|
||||
|
||||
~eventcount()
|
||||
{
|
||||
CloseHandle(sema_);
|
||||
}
|
||||
|
||||
state_t prepare()
|
||||
{
|
||||
return state_.fetch_add(waiters_inc, std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
void retire()
|
||||
{
|
||||
state_.fetch_add((state_t)-(int)waiters_inc, std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
void wait(state_t cmp)
|
||||
{
|
||||
WaitForSingleObject(sema_, INFINITE);
|
||||
state_t cmp0 = state_.load(std::memory_order_seq_cst);
|
||||
if ((cmp & generation_mask) == (cmp0 & generation_mask))
|
||||
{
|
||||
state_.fetch_add((state_t)-(int)waiters_inc, std::memory_order_seq_cst);
|
||||
ReleaseSemaphore(sema_, 1, 0);
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
signal_relaxed();
|
||||
}
|
||||
|
||||
void signal_relaxed()
|
||||
{
|
||||
state_t cmp = state_.load(std::memory_order_seq_cst);
|
||||
if (0 == (cmp & waiters_mask))
|
||||
return;
|
||||
for (;;)
|
||||
{
|
||||
state_t xchg = (cmp & ~waiters_mask) + generation_inc;
|
||||
if (state_.compare_exchange_weak(cmp, xchg, std::memory_order_seq_cst))
|
||||
{
|
||||
ReleaseSemaphore(sema_, cmp & waiters_mask, 0);
|
||||
return;
|
||||
}
|
||||
if (0 == (cmp & waiters_mask))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<state_t> state_;
|
||||
HANDLE sema_;
|
||||
|
||||
static state_t const waiters_inc = 1;
|
||||
static state_t const waiters_mask = (1 << 20) - 1;
|
||||
static state_t const generation_inc = 1 << 20;
|
||||
static state_t const generation_mask = ~waiters_mask;
|
||||
|
||||
eventcount(eventcount const&);
|
||||
eventcount& operator = (eventcount const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class eventcount_blocking
|
||||
{
|
||||
public:
|
||||
eventcount_blocking(eventcount& ec)
|
||||
: ec_(ec)
|
||||
{
|
||||
cmp_ = ec_.prepare();
|
||||
wait_ = false;
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
RL_ASSERT(false == wait_);
|
||||
wait_ = true;
|
||||
ec_.wait(cmp_);
|
||||
}
|
||||
|
||||
~eventcount_blocking()
|
||||
{
|
||||
if (false == wait_)
|
||||
ec_.retire();
|
||||
}
|
||||
|
||||
private:
|
||||
eventcount& ec_;
|
||||
eventcount::state_t cmp_;
|
||||
bool wait_;
|
||||
|
||||
eventcount_blocking(eventcount_blocking const&);
|
||||
eventcount_blocking& operator = (eventcount_blocking const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct signaling_test : rl::test_suite<signaling_test, 6>
|
||||
{
|
||||
//rl::HANDLE var_wait_for_items;
|
||||
//rl::CRITICAL_SECTION mtx_items_avail;
|
||||
//std::atomic<unsigned> n_waiting_consumers;
|
||||
//rl::var<unsigned> consumer_wait_generation;
|
||||
//rl::var<unsigned> n_consumers_to_wakeup;
|
||||
|
||||
eventcount ec_;
|
||||
|
||||
static int const max_queue_length = 4;
|
||||
int queue [max_queue_length];
|
||||
int queue_head;
|
||||
int queue_tail;
|
||||
int queue_head_data;
|
||||
int queue_tail_data;
|
||||
|
||||
void before()
|
||||
{
|
||||
//var_wait_for_items = rl::CreateEvent(0, 1, 0, 0, $);
|
||||
//rl::InitializeCriticalSection(&mtx_items_avail, $);
|
||||
//n_waiting_consumers($) = 0;
|
||||
//consumer_wait_generation($) = 0;
|
||||
//n_consumers_to_wakeup($) = 0;
|
||||
for (int i = 0; i != max_queue_length; ++i)
|
||||
queue[i] = 0;
|
||||
queue_head = 0;
|
||||
queue_tail = 0;
|
||||
queue_head_data = 0;
|
||||
queue_tail_data = 0;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
//rl::CloseHandle(var_wait_for_items, $);
|
||||
//rl::DeleteCriticalSection(&mtx_items_avail, $);
|
||||
}
|
||||
|
||||
struct enqueue_desc
|
||||
{
|
||||
int pos;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << "enqueue " << pos;
|
||||
}
|
||||
};
|
||||
|
||||
void enqueue()
|
||||
{
|
||||
queue[queue_head++] = ++queue_head_data;
|
||||
RL_HIST_IMPL(rl::ctx(), $, enqueue_desc) {queue_head - 1} RL_HIST_END();
|
||||
signal();
|
||||
}
|
||||
|
||||
void dequeue()
|
||||
{
|
||||
int my_pos = queue_tail++;
|
||||
for (;;)
|
||||
{
|
||||
if (queue[my_pos])
|
||||
{
|
||||
RL_ASSERT(queue[my_pos] == my_pos + 1);
|
||||
return;
|
||||
}
|
||||
wait(my_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
ec_.signal();
|
||||
/*
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
if (n_waiting_consumers($).load(std::memory_order_relaxed))
|
||||
{
|
||||
rl::EnterCriticalSection(&mtx_items_avail, $);
|
||||
if (n_waiting_consumers($).load(std::memory_order_relaxed) > 0)
|
||||
{
|
||||
consumer_wait_generation($) += 1;
|
||||
//RL_ASSERT(n_consumers_to_wakeup($) == 0);
|
||||
n_consumers_to_wakeup($) = n_waiting_consumers($).load(std::memory_order_relaxed);
|
||||
rl::SetEvent(var_wait_for_items, $);
|
||||
}
|
||||
rl::LeaveCriticalSection(&mtx_items_avail, $);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void wait(int my_pos)
|
||||
{
|
||||
eventcount_blocking block (ec_);
|
||||
if (queue[my_pos])
|
||||
return;
|
||||
block.wait();
|
||||
|
||||
/*
|
||||
rl::EnterCriticalSection(&mtx_items_avail, $);
|
||||
n_waiting_consumers($).store(n_waiting_consumers($).load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
while (0 == queue[my_pos])
|
||||
{
|
||||
unsigned my_generation = consumer_wait_generation($);
|
||||
for (;;)
|
||||
{
|
||||
rl::LeaveCriticalSection(&mtx_items_avail, $);
|
||||
rl::WaitForSingleObject(var_wait_for_items, rl::RL_INFINITE, $);
|
||||
rl::EnterCriticalSection(&mtx_items_avail, $);
|
||||
if (n_consumers_to_wakeup($) > 0 && consumer_wait_generation($) != my_generation)
|
||||
break;
|
||||
}
|
||||
if (--n_consumers_to_wakeup($) == 0)
|
||||
rl::ResetEvent(var_wait_for_items, $);
|
||||
}
|
||||
n_waiting_consumers($).store(n_waiting_consumers($).load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
|
||||
rl::LeaveCriticalSection(&mtx_items_avail, $);
|
||||
*/
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (index < rl::test_suite<signaling_test, 6>::params::thread_count/2+1)
|
||||
{
|
||||
enqueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
dequeue();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
//p.search_type = rl::fair_context_bound_scheduler_type;
|
||||
p.search_type = rl::sched_bound;
|
||||
//p.context_bound = 1;
|
||||
//p.execution_depth_limit = 100;
|
||||
//p.iteration_count = 5000;
|
||||
//p.initial_state = "280572";
|
||||
//rl::simulate<signaling_test>(p);
|
||||
|
||||
rl::simulate<peterson_mutex_test>();
|
||||
rl::simulate<peterson_mutex_test2>(p);
|
||||
rl::simulate<peterson_mutex_test3>();
|
||||
rl::simulate<peterson_mutex_test4>(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_MSVC_OUTPUT
|
||||
//#define RL_DEBUGBREAK_ON_FAILURE
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="proxy_collector"
|
||||
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
|
||||
RootNamespace="ref_counting"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Profile|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/Ob0"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
WholeProgramOptimization="false"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\proxy_collector.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,299 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="proxy_collector"
|
||||
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
|
||||
RootNamespace="ref_counting"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Profile|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/Ob0"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
WholeProgramOptimization="false"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\original.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\proxy_collector.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\rtl.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,318 @@
|
||||
#include "stdafx.h"
|
||||
#include <stdint.h>
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
struct pc_sys_anchor;
|
||||
struct pc_region;
|
||||
struct pc_master;
|
||||
typedef pc_region pc_node;
|
||||
typedef void (pc_fp_dtor) (pc_region*);
|
||||
|
||||
struct pc_sys_anchor
|
||||
{
|
||||
int refcnt;
|
||||
pc_region* region;
|
||||
|
||||
pc_sys_anchor()
|
||||
{
|
||||
}
|
||||
|
||||
pc_sys_anchor(int rc, pc_region* r = 0)
|
||||
{
|
||||
refcnt = rc;
|
||||
region = r;
|
||||
}
|
||||
|
||||
bool operator == (pc_sys_anchor const& right) const
|
||||
{
|
||||
return refcnt == right.refcnt
|
||||
&& region == right.region;
|
||||
}
|
||||
|
||||
pc_sys_anchor operator + (pc_sys_anchor const& right) const
|
||||
{
|
||||
pc_sys_anchor res;
|
||||
res.refcnt = refcnt + right.refcnt;
|
||||
res.region = (pc_region*)((intptr_t)region + (intptr_t)right.region);
|
||||
return res;
|
||||
}
|
||||
|
||||
pc_sys_anchor operator - (pc_sys_anchor const& right) const
|
||||
{
|
||||
pc_sys_anchor res;
|
||||
res.refcnt = refcnt - right.refcnt;
|
||||
res.region = (pc_region*)((intptr_t)region - (intptr_t)right.region);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& s, pc_sys_anchor const& right)
|
||||
{
|
||||
return s << "{" << right.refcnt << "," << right.region << "}";
|
||||
}
|
||||
|
||||
struct pc_region
|
||||
{
|
||||
std::atomic<pc_sys_anchor> next;
|
||||
std::atomic<pc_region*> defer;
|
||||
|
||||
pc_region()
|
||||
{
|
||||
next($) = pc_sys_anchor(0, 0);
|
||||
defer($) = 0;
|
||||
}
|
||||
|
||||
void link(pc_region* next)
|
||||
{
|
||||
defer.store(next, rl::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void defer_node(pc_region* node)
|
||||
{
|
||||
pc_region* region = defer.exchange(node, rl::memory_order_release);
|
||||
node->defer.store(region, rl::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
|
||||
struct pc_master
|
||||
{
|
||||
std::atomic<pc_sys_anchor> head;
|
||||
pc_region stub_region;
|
||||
pc_fp_dtor* fp_dtor;
|
||||
|
||||
pc_master(pc_fp_dtor* const dtor)
|
||||
{
|
||||
pc_sys_anchor src (0, &stub_region);
|
||||
head.store(src, rl::memory_order_relaxed);
|
||||
fp_dtor = dtor;
|
||||
}
|
||||
|
||||
pc_region* acquire()
|
||||
{
|
||||
pc_sys_anchor cmp (head.load(rl::memory_order_relaxed));
|
||||
pc_sys_anchor xchg;
|
||||
do
|
||||
{
|
||||
xchg.refcnt = cmp.refcnt + 2;
|
||||
xchg.region = cmp.region;
|
||||
}
|
||||
while (false == head.compare_exchange_weak(cmp, xchg, rl::memory_order_acquire));
|
||||
return cmp.region;
|
||||
}
|
||||
|
||||
void release(pc_region* region)
|
||||
{
|
||||
pc_sys_anchor prev = region->next.fetch_sub(2, rl::memory_order_acq_rel);
|
||||
if (prev.refcnt == 3)
|
||||
sys_dtor(region);
|
||||
}
|
||||
|
||||
void mutate(pc_region* node)
|
||||
{
|
||||
pc_sys_anchor src (2, 0);
|
||||
node->next.store(src, rl::memory_order_relaxed);
|
||||
pc_sys_anchor xchg (0, node);
|
||||
pc_sys_anchor cmp = head.load(rl::memory_order_relaxed);
|
||||
while (false == head.compare_exchange_weak(cmp, xchg, std::memory_order_acq_rel));
|
||||
|
||||
pc_sys_anchor cmp2 = cmp.region->next.load(rl::memory_order_relaxed);
|
||||
pc_sys_anchor xchg2;
|
||||
do
|
||||
{
|
||||
xchg2 = pc_sys_anchor(cmp2.refcnt, node);
|
||||
}
|
||||
while (false == cmp.region->next.compare_exchange_weak(cmp2, xchg2, rl::memory_order_release));
|
||||
|
||||
pc_sys_anchor prev = cmp.region->next.fetch_add(cmp.refcnt + 1, rl::memory_order_acq_rel);
|
||||
if (prev.refcnt == -cmp.refcnt)
|
||||
sys_dtor(cmp.region);
|
||||
}
|
||||
|
||||
void sys_dtor(pc_region* region)
|
||||
{
|
||||
int reset = 0;
|
||||
pc_region* head = region;
|
||||
pc_region* tail = region;
|
||||
pc_sys_anchor nx = region->next.load(rl::memory_order_relaxed);
|
||||
pc_region* next = nx.region;
|
||||
|
||||
while (next)
|
||||
{
|
||||
pc_sys_anchor prev = next->next.fetch_sub(2, rl::memory_order_acq_rel);
|
||||
if (prev.refcnt != 3)
|
||||
break;
|
||||
tail = next;
|
||||
nx = next->next.load(rl::memory_order_relaxed);
|
||||
next = nx.region;
|
||||
}
|
||||
|
||||
nx = tail->next.load(rl::memory_order_relaxed);
|
||||
nx.region = 0;
|
||||
tail->next.store(nx, rl::memory_order_relaxed);
|
||||
|
||||
while (head)
|
||||
{
|
||||
nx = head->next.load(rl::memory_order_relaxed);
|
||||
pc_region* const next = nx.region;
|
||||
|
||||
pc_region* defer = head->defer.load(rl::memory_order_relaxed);
|
||||
|
||||
nx = head->next.load(rl::memory_order_relaxed);
|
||||
RL_ASSERT(nx.refcnt == 1);
|
||||
|
||||
if (head != &stub_region)
|
||||
{
|
||||
head->defer.store(defer, rl::memory_order_relaxed);
|
||||
defer = head;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset = 1;
|
||||
}
|
||||
|
||||
while (defer)
|
||||
{
|
||||
pc_region* const next = defer->defer.load(rl::memory_order_relaxed);
|
||||
fp_dtor(defer);
|
||||
defer = next;
|
||||
}
|
||||
head = next;
|
||||
}
|
||||
|
||||
if (reset)
|
||||
{
|
||||
stub_region.defer.store(0, rl::memory_order_relaxed);
|
||||
mutate(&stub_region);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct foo_node
|
||||
{
|
||||
pc_node pcn;
|
||||
std::atomic<foo_node*> next;
|
||||
rl::var<int> data;
|
||||
};
|
||||
|
||||
void foo_node_dtor(pc_node* pcn)
|
||||
{
|
||||
// yes, very fragile
|
||||
foo_node* const n = (foo_node*)pcn;
|
||||
delete n;
|
||||
}
|
||||
|
||||
struct foo_list
|
||||
{
|
||||
std::atomic<foo_node*> head;
|
||||
pc_master pc;
|
||||
|
||||
foo_list()
|
||||
: head(0)
|
||||
, pc(foo_node_dtor)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct proxy_collector_test : rl::test_suite<proxy_collector_test, 4>
|
||||
{
|
||||
foo_list m_list;
|
||||
|
||||
void before()
|
||||
{
|
||||
m_list.head($) = 0;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
foo_node* node = new foo_node;
|
||||
m_list.pc.mutate(&node->pcn);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (index < 2)
|
||||
{
|
||||
pc_region* pcr = m_list.pc.acquire();
|
||||
for (int i = 0; i != 4; ++i)
|
||||
{
|
||||
foo_node* node = m_list.head.load(rl::memory_order_acquire);
|
||||
while (node)
|
||||
{
|
||||
foo_node* const next = node->next.load(rl::memory_order_acquire);
|
||||
intptr_t volatile data = node->data($);
|
||||
(void)data;
|
||||
node = next;
|
||||
}
|
||||
if (2 == i)
|
||||
{
|
||||
m_list.pc.release(pcr);
|
||||
pcr = m_list.pc.acquire();
|
||||
}
|
||||
}
|
||||
m_list.pc.release(pcr);
|
||||
}
|
||||
else
|
||||
{
|
||||
pc_region* pcr = m_list.pc.acquire();
|
||||
for (int i = 0; i != 4; ++i)
|
||||
{
|
||||
if (0 == (i % 2))
|
||||
{
|
||||
foo_node* node = new foo_node;
|
||||
node->data($) = 1;
|
||||
foo_node* cmp = m_list.head.load(rl::memory_order_relaxed);
|
||||
do
|
||||
{
|
||||
node->next.store(cmp, rl::memory_order_relaxed);
|
||||
}
|
||||
while (false == m_list.head.compare_exchange_weak(cmp, node, rl::memory_order_release));
|
||||
}
|
||||
else
|
||||
{
|
||||
foo_node* node = m_list.head.load(rl::memory_order_acquire);
|
||||
foo_node* next;
|
||||
do
|
||||
{
|
||||
if (0 == node)
|
||||
break;
|
||||
next = node->next.load(rl::memory_order_relaxed);
|
||||
}
|
||||
while (false == m_list.head.compare_exchange_weak(node, next, rl::memory_order_acquire));
|
||||
|
||||
if (node)
|
||||
{
|
||||
//if (1 == i)
|
||||
{
|
||||
m_list.pc.mutate(&node->pcn);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// pcr->defer_node(&node->pcn);
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (i % 2)
|
||||
{
|
||||
m_list.pc.release(pcr);
|
||||
pcr = m_list.pc.acquire();
|
||||
}
|
||||
}
|
||||
m_list.pc.release(pcr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params params;
|
||||
params.iteration_count = 1000;
|
||||
rl::simulate<proxy_collector_test>(params);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="ref_counting"
|
||||
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
|
||||
RootNamespace="ref_counting"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\ref_counting.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="ref_counting"
|
||||
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
|
||||
RootNamespace="ref_counting"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
EnableFiberSafeOptimizations="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\ref_counting.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,269 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
struct rc_object
|
||||
{
|
||||
std::atomic<int> rc;
|
||||
rl::var<int> data;
|
||||
|
||||
void acquire()
|
||||
{
|
||||
rc.fetch_add(1, rl::memory_order_acquire);
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (1 == rc.fetch_sub(1, rl::memory_order_release))
|
||||
{
|
||||
rc.load(rl::memory_order_acquire);
|
||||
data($) = 0;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
rc_object(int data)
|
||||
: rc(1)
|
||||
, data(data)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void post_to_channel(rl::atomic<rc_object*>& ch, rc_object* obj)
|
||||
{
|
||||
obj->acquire();
|
||||
rl::backoff b;
|
||||
for (;;)
|
||||
{
|
||||
rc_object* cmp = 0;
|
||||
if (ch.compare_exchange_weak(cmp, obj, rl::memory_order_release))
|
||||
break;
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
|
||||
rc_object* get_from_channel(rl::atomic<rc_object*>& ch)
|
||||
{
|
||||
return ch.exchange(0, rl::memory_order_acquire);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct ref_counting_test : rl::test_suite<ref_counting_test, 2>
|
||||
{
|
||||
std::atomic<rc_object*> channel;
|
||||
|
||||
void before()
|
||||
{
|
||||
channel($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
rc_object* obj = new rc_object (rand());
|
||||
post_to_channel(channel, obj);
|
||||
int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
rl::backoff b;
|
||||
for (;;)
|
||||
{
|
||||
rc_object* obj = get_from_channel(channel);
|
||||
if (obj)
|
||||
{
|
||||
int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ref_counting_test2 : rl::test_suite<ref_counting_test2, 3>
|
||||
{
|
||||
std::atomic<rc_object*> channel01;
|
||||
std::atomic<rc_object*> channel02;
|
||||
std::atomic<rc_object*> channel12;
|
||||
std::atomic<rc_object*> channel21;
|
||||
|
||||
void before()
|
||||
{
|
||||
channel01($) = 0;
|
||||
channel02($) = 0;
|
||||
channel12($) = 0;
|
||||
channel21($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
{
|
||||
rc_object* obj1 = new rc_object (rand());
|
||||
post_to_channel(channel01, obj1);
|
||||
volatile int data = obj1->data($);
|
||||
(void)data;
|
||||
obj1->release();
|
||||
}
|
||||
|
||||
{
|
||||
rc_object* obj2 = new rc_object (rand());
|
||||
post_to_channel(channel02, obj2);
|
||||
volatile int data = obj2->data($);
|
||||
(void)data;
|
||||
obj2->release();
|
||||
}
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
rl::backoff b;
|
||||
bool ch0 = false;
|
||||
bool ch2 = false;
|
||||
while (!ch0 || !ch2)
|
||||
{
|
||||
{
|
||||
rc_object* obj = get_from_channel(channel01);
|
||||
if (obj)
|
||||
{
|
||||
post_to_channel(channel12, obj);
|
||||
volatile int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
ch0 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
{
|
||||
rc_object* obj = get_from_channel(channel21);
|
||||
if (obj)
|
||||
{
|
||||
volatile int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
ch2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rl::backoff b;
|
||||
bool ch0 = false;
|
||||
bool ch1 = false;
|
||||
while (!ch0 || !ch1)
|
||||
{
|
||||
{
|
||||
rc_object* obj = get_from_channel(channel02);
|
||||
if (obj)
|
||||
{
|
||||
post_to_channel(channel21, obj);
|
||||
volatile int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
ch0 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
{
|
||||
rc_object* obj = get_from_channel(channel12);
|
||||
if (obj)
|
||||
{
|
||||
volatile int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
ch1 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.yield($);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ref_counting_test3 : rl::test_suite<ref_counting_test3, 2>
|
||||
{
|
||||
std::atomic<rc_object*> channel;
|
||||
|
||||
void before()
|
||||
{
|
||||
channel($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
rc_object* obj = new rc_object (rand());
|
||||
post_to_channel(channel, obj);
|
||||
volatile int data = obj->data($);
|
||||
(void)data;
|
||||
obj->release();
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
rl::backoff b;
|
||||
rc_object* obj = 0;
|
||||
for (;;)
|
||||
{
|
||||
obj = get_from_channel(channel);
|
||||
if (obj)
|
||||
break;
|
||||
else
|
||||
b.yield($);
|
||||
}
|
||||
obj->acquire();
|
||||
obj->release();
|
||||
//volatile int data = obj->data($);
|
||||
//(void)data;
|
||||
obj->release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params params;
|
||||
params.context_bound = 2;
|
||||
params.iteration_count = 10000;
|
||||
rl::simulate<ref_counting_test>(params);
|
||||
std::cout << "count: " << params.stop_iteration << std::endl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
TARGET=smr
|
||||
SRC=smr.cpp
|
||||
HEADERS=stdafx.h
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: Makefile ${SRC} ${HEADERS}
|
||||
g++ ${SRC} -O3 -g -o ${TARGET}
|
||||
|
||||
clean:
|
||||
rm ${TARGET}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="smr"
|
||||
ProjectGUID="{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
|
||||
RootNamespace="smr"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\smr.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="smr"
|
||||
ProjectGUID="{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
|
||||
RootNamespace="smr"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\smr.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
189
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/smr/smr.cpp
vendored
Normal file
189
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/smr/smr.cpp
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
unsigned const thread_count = 3;
|
||||
unsigned const node_count = 6;
|
||||
|
||||
|
||||
struct smr_test : rl::test_suite<smr_test, thread_count>
|
||||
{
|
||||
struct node
|
||||
{
|
||||
std::atomic<node*> next_;
|
||||
rl::var<int> data_;
|
||||
};
|
||||
|
||||
std::atomic<node*> head_;
|
||||
|
||||
std::atomic<node*> hp_ [thread_count];
|
||||
rl::var<node*> defer_ [thread_count][thread_count];
|
||||
rl::var<int> defer_size_ [thread_count];
|
||||
|
||||
void before()
|
||||
{
|
||||
head_.store(0, std::memory_order_relaxed);
|
||||
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
hp_[i].store(0, std::memory_order_relaxed);
|
||||
VAR(defer_size_[i]) = 0;
|
||||
for (size_t j = 0; j != thread_count; ++j)
|
||||
VAR(defer_[i][j]) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void push(unsigned index, int data)
|
||||
{
|
||||
node* n = new node ();
|
||||
n->VAR(data_) = data;
|
||||
node* next = head_.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
n->next_.store(next, rl::memory_order_relaxed);
|
||||
if (head_.compare_exchange_weak(next, n, rl::memory_order_release))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int pop(unsigned index)
|
||||
{
|
||||
node* n = 0;
|
||||
for (;;)
|
||||
{
|
||||
n = smr_acquire(index, head_);
|
||||
if (0 == n)
|
||||
break;
|
||||
node* next = n->next_.load(rl::memory_order_relaxed);
|
||||
if (head_.compare_exchange_weak(n, next, rl::memory_order_acquire))
|
||||
break;
|
||||
smr_release(index);
|
||||
}
|
||||
smr_release(index);
|
||||
if (n)
|
||||
{
|
||||
int data = n->VAR(data_);
|
||||
smr_defer(index, n);
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void smr_pump(unsigned index)
|
||||
{
|
||||
node* hp [thread_count] = {};
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
hp[i] = hp_[i].load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
node* nn = VAR(defer_[index][i]);
|
||||
if (nn)
|
||||
{
|
||||
for (size_t j = 0; j != thread_count; ++j)
|
||||
{
|
||||
if (nn == hp[j])
|
||||
{
|
||||
nn = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nn)
|
||||
{
|
||||
VAR(defer_[index][i]) = 0;
|
||||
VAR(defer_size_[index]) -= 1;
|
||||
delete nn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void smr_defer(unsigned index, node* n)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
smr_pump(index);
|
||||
|
||||
if (VAR(defer_size_[index]) == thread_count)
|
||||
{
|
||||
delete n;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found = false;
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
if (VAR(defer_[index][i]) == 0)
|
||||
{
|
||||
VAR(defer_[index][i]) = n;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RL_ASSERT(found);
|
||||
VAR(defer_size_[index]) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
node* smr_acquire(unsigned index, std::atomic<node*>& n)
|
||||
{
|
||||
node* v = 0;
|
||||
for (;;)
|
||||
{
|
||||
v = n.load(std::memory_order_relaxed);
|
||||
hp_[index].store(v, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
node* v2 = n.load(std::memory_order_acquire);
|
||||
if (v2 == v)
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void smr_release(unsigned index)
|
||||
{
|
||||
hp_[index].store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
for (unsigned i = 0; i != node_count; ++i)
|
||||
{
|
||||
push(index, index * thread_count + i + 1);
|
||||
}
|
||||
for (unsigned i = 0; i != node_count; ++i)
|
||||
{
|
||||
int data = pop(index);
|
||||
RL_ASSERT(0 != data);
|
||||
}
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
for (unsigned i = 0; i != ::thread_count; ++i)
|
||||
{
|
||||
smr_pump(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
//p.collect_history = true;
|
||||
//p.output_history = true;
|
||||
//p.initial_state = "991172";
|
||||
p.iteration_count = 1000;
|
||||
rl::simulate<smr_test>(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
10
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/smr/stdafx.h
vendored
Normal file
10
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/smr/stdafx.h
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_MSVC_OUTPUT
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="spsc_queue"
|
||||
ProjectGUID="{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}"
|
||||
RootNamespace="spsc_queue"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../../.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\spsc_queue.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="spsc_queue"
|
||||
ProjectGUID="{3F32C4FA-E451-42BC-9E65-74129120B6E4}"
|
||||
RootNamespace="spsc_queue"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\spsc_queue.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,202 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
template<typename T>
|
||||
class nonblocking_spsc_queue
|
||||
{
|
||||
public:
|
||||
nonblocking_spsc_queue()
|
||||
{
|
||||
node* n = new node ();
|
||||
VAR(head) = n;
|
||||
VAR(tail) = n;
|
||||
}
|
||||
|
||||
~nonblocking_spsc_queue()
|
||||
{
|
||||
RL_ASSERT(VAR(head) == VAR(tail));
|
||||
delete (node*)VAR(head);
|
||||
}
|
||||
|
||||
void enqueue(T data)
|
||||
{
|
||||
node* n = new node (data);
|
||||
VAR(head)->next.store(n, std::memory_order_release);
|
||||
VAR(head) = n;
|
||||
}
|
||||
|
||||
bool dequeue(T& data)
|
||||
{
|
||||
node* t = VAR(tail);
|
||||
node* n = t->next.load(std::memory_order_acquire);
|
||||
if (0 == n)
|
||||
return false;
|
||||
data = n->VAR(data);
|
||||
delete t;
|
||||
VAR(tail) = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct node
|
||||
{
|
||||
std::atomic<node*> next;
|
||||
VAR_T(T) data;
|
||||
|
||||
node(T data = T())
|
||||
: next(0)
|
||||
, data(data)
|
||||
{}
|
||||
};
|
||||
|
||||
VAR_T(node*) head;
|
||||
VAR_T(node*) tail;
|
||||
};
|
||||
|
||||
struct nonblocking_spsc_queue_test : rl::test_suite<nonblocking_spsc_queue_test, 2>
|
||||
{
|
||||
nonblocking_spsc_queue<int> q;
|
||||
|
||||
void thread(unsigned thread_index)
|
||||
{
|
||||
if (0 == thread_index)
|
||||
{
|
||||
q.enqueue(11);
|
||||
}
|
||||
else
|
||||
{
|
||||
int data = 0;
|
||||
while (false == q.dequeue(data))
|
||||
{}
|
||||
RL_ASSERT(11 == data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class eventcount
|
||||
{
|
||||
public:
|
||||
eventcount()
|
||||
: count(0)
|
||||
, waiters(0)
|
||||
{}
|
||||
|
||||
void signal_relaxed()
|
||||
{
|
||||
unsigned cmp = count.load(std::memory_order_relaxed);
|
||||
signal_impl(cmp);
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
unsigned cmp = count.fetch_add(0, std::memory_order_seq_cst);
|
||||
signal_impl(cmp);
|
||||
}
|
||||
|
||||
unsigned get()
|
||||
{
|
||||
unsigned cmp = count.fetch_or(0x80000000, std::memory_order_acquire);
|
||||
return cmp & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
void wait(unsigned cmp)
|
||||
{
|
||||
unsigned ec = count.load(std::memory_order_seq_cst);
|
||||
if (cmp == (ec & 0x7FFFFFFF))
|
||||
{
|
||||
guard.lock($);
|
||||
ec = count.load(std::memory_order_seq_cst);
|
||||
if (cmp == (ec & 0x7FFFFFFF))
|
||||
{
|
||||
waiters($) += 1;
|
||||
cv.wait(guard, $);
|
||||
}
|
||||
guard.unlock($);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<unsigned> count;
|
||||
VAR_T(unsigned) waiters;
|
||||
std::mutex guard;
|
||||
std::condition_variable cv;
|
||||
|
||||
void signal_impl(unsigned cmp)
|
||||
{
|
||||
if (cmp & 0x80000000)
|
||||
{
|
||||
guard.lock($);
|
||||
while (false == count.compare_exchange_weak(cmp,
|
||||
(cmp + 1) & 0x7FFFFFFF, std::memory_order_relaxed));
|
||||
unsigned w = VAR(waiters);
|
||||
VAR(waiters) = 0;
|
||||
guard.unlock($);
|
||||
if (w)
|
||||
cv.notify_all($);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class spsc_queue : nonblocking_spsc_queue<T>
|
||||
{
|
||||
public:
|
||||
typedef nonblocking_spsc_queue<T> base_t;
|
||||
|
||||
void enqueue(T data)
|
||||
{
|
||||
base_t::enqueue(data);
|
||||
ec.signal/*_relaxed*/();
|
||||
}
|
||||
|
||||
T dequeue()
|
||||
{
|
||||
T data;
|
||||
bool res = base_t::dequeue(data);
|
||||
while (false == res)
|
||||
{
|
||||
int cmp = ec.get();
|
||||
res = base_t::dequeue(data);
|
||||
if (res)
|
||||
break;
|
||||
ec.wait(cmp);
|
||||
res = base_t::dequeue(data);
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private:
|
||||
eventcount ec;
|
||||
};
|
||||
|
||||
|
||||
struct spsc_queue_test : rl::test_suite<spsc_queue_test, 2>
|
||||
{
|
||||
spsc_queue<int> q;
|
||||
|
||||
void thread(unsigned thread_index)
|
||||
{
|
||||
if (0 == thread_index)
|
||||
{
|
||||
q.enqueue(11);
|
||||
}
|
||||
else
|
||||
{
|
||||
int d = q.dequeue();
|
||||
RL_ASSERT(11 == d);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<nonblocking_spsc_queue_test>();
|
||||
rl::simulate<spsc_queue_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
//#define RL_MSVC_OUTPUT
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
lock-free stack
|
||||
code contains several bugs: access to freed memory and ABA problem
|
||||
@@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="stack"
|
||||
ProjectGUID="{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
|
||||
RootNamespace="stack"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stack.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="stack"
|
||||
ProjectGUID="{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
|
||||
RootNamespace="stack"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stack.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
105
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/stack/stack.cpp
vendored
Normal file
105
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/example/stack/stack.cpp
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
// TEST FAILS WITH "ACCESS TO FREED MEMORY"
|
||||
|
||||
class stack
|
||||
{
|
||||
public:
|
||||
stack()
|
||||
: head_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void push(int data)
|
||||
{
|
||||
rl::var<node*> n = new node ();
|
||||
n($)->data_($) = data;
|
||||
node* next = head_.load(rl::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
n($)->next_.store(next, rl::memory_order_relaxed);
|
||||
if (head_.compare_exchange_weak(next, n($), rl::memory_order_release))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int pop()
|
||||
{
|
||||
node* n = head_.load(rl::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
if (0 == n)
|
||||
break;
|
||||
node* next = n->next_.load(rl::memory_order_relaxed);
|
||||
if (head_.compare_exchange_weak(n, next, rl::memory_order_acquire))
|
||||
break;
|
||||
}
|
||||
if (n)
|
||||
{
|
||||
int data = n->data_($);
|
||||
delete n;
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct node
|
||||
{
|
||||
std::atomic<node*> next_;
|
||||
rl::var<int> data_;
|
||||
};
|
||||
|
||||
std::atomic<node*> head_;
|
||||
|
||||
stack(stack const&);
|
||||
stack& operator = (stack const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct stack_test : rl::test_suite<stack_test, 4>
|
||||
{
|
||||
stack s_;
|
||||
|
||||
int produced_count_;
|
||||
int consumed_count_;
|
||||
|
||||
void before()
|
||||
{
|
||||
produced_count_ = 0;
|
||||
consumed_count_ = 0;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
typedef rl::test_suite<stack_test, 4> base_t;
|
||||
RL_ASSERT(base_t::params::thread_count == produced_count_);
|
||||
RL_ASSERT(base_t::params::thread_count == consumed_count_);
|
||||
}
|
||||
|
||||
void thread(unsigned /*index*/)
|
||||
{
|
||||
s_.push(rand() + 1);
|
||||
produced_count_ += 1;
|
||||
int data = s_.pop();
|
||||
RL_ASSERT(data);
|
||||
consumed_count_ += 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<stack_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
|
||||
@@ -0,0 +1,842 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../relacy/windows.h"
|
||||
|
||||
/*
|
||||
#define HANDLE rl::HANDLE
|
||||
|
||||
#define CreateSemaphoreA rl::RL_CreateSemaphore($)
|
||||
#define CreateSemaphoreW rl::RL_CreateSemaphore($)
|
||||
#ifndef CreateSemaphore
|
||||
# define CreateSemaphore CreateSemaphoreW
|
||||
#endif
|
||||
|
||||
//#define CRITICAL_SECTION rl::CRITICAL_SECTION
|
||||
//#define InitializeCriticalSection rl::InitializeCriticalSection($)
|
||||
|
||||
#define CloseHandle rl::RL_CloseHandle($)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#if defined(WIN32) && defined(_MSC_VER)
|
||||
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
|
||||
class semaphore
|
||||
{
|
||||
public:
|
||||
semaphore()
|
||||
{
|
||||
h_ = rl::CreateSemaphore(0, 0, LONG_MAX, 0, $);
|
||||
}
|
||||
|
||||
~semaphore()
|
||||
{
|
||||
rl::CloseHandle(h_, $);
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
rl::WaitForSingleObject(h_, rl::RL_INFINITE, $);
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
rl::ReleaseSemaphore(h_, 1, 0, $);
|
||||
}
|
||||
|
||||
private:
|
||||
rl::HANDLE h_;
|
||||
|
||||
semaphore(semaphore const&);
|
||||
semaphore& operator = (semaphore const&);
|
||||
};
|
||||
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
rl::InitializeCriticalSection(&cs_, $);
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
rl::DeleteCriticalSection(&cs_, $);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
rl::EnterCriticalSection(&cs_, $);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
rl::LeaveCriticalSection(&cs_, $);
|
||||
}
|
||||
|
||||
private:
|
||||
rl::CRITICAL_SECTION cs_;
|
||||
|
||||
mutex(mutex const&);
|
||||
mutex& operator = (mutex const&);
|
||||
};
|
||||
|
||||
//void full_memory_fence()
|
||||
//{
|
||||
// _mm_mfence();
|
||||
//}
|
||||
|
||||
//#define THREAD_LOCAL __declspec(thread)
|
||||
|
||||
#elif defined(POSIX) && defined(GCC)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
class semaphore
|
||||
{
|
||||
public:
|
||||
semaphore()
|
||||
{
|
||||
sem_init(&sem_, 0, 0);
|
||||
}
|
||||
|
||||
~semaphore()
|
||||
{
|
||||
sem_destroy(&sem_);
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
sem_wait(&sem_);
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
sem_post(&sem_);
|
||||
}
|
||||
|
||||
private:
|
||||
sem_t sem_;
|
||||
|
||||
semaphore(semaphore const&);
|
||||
semaphore& operator = (semaphore const&);
|
||||
};
|
||||
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutex_init(&mutex_, 0);
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&mutex_);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex_;
|
||||
|
||||
mutex(mutex const&);
|
||||
mutex& operator = (mutex const&);
|
||||
};
|
||||
|
||||
void full_memory_fence()
|
||||
{
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
//#define THREAD_LOCAL __thread
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class lock
|
||||
{
|
||||
public:
|
||||
lock(mutex& m)
|
||||
: m_(m)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
~lock()
|
||||
{
|
||||
m_.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
mutex& m_;
|
||||
|
||||
lock(lock const&);
|
||||
lock& operator = (lock const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** simple single-threaded double-linked list
|
||||
* nothing interesting
|
||||
*/
|
||||
class dlist
|
||||
{
|
||||
public:
|
||||
struct node
|
||||
{
|
||||
rl::var<node*> prev_;
|
||||
rl::var<node*> next_;
|
||||
|
||||
node()
|
||||
{
|
||||
prev_($) = 0;
|
||||
next_($) = 0;
|
||||
}
|
||||
};
|
||||
|
||||
dlist()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void push(node* n)
|
||||
{
|
||||
size_t s = size_($).load(rl::memory_order_relaxed);
|
||||
size_($).store(s + 1, rl::memory_order_relaxed);
|
||||
n->next_($) = head_.next_($);
|
||||
n->prev_($) = &head_;
|
||||
head_.next_($)->prev_($) = n;
|
||||
head_.next_($) = n;
|
||||
}
|
||||
|
||||
node* pop()
|
||||
{
|
||||
if (size_($).load(rl::memory_order_relaxed) == 0)
|
||||
return 0;
|
||||
node* n = head_.next_($);
|
||||
remove(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void remove(node* n)
|
||||
{
|
||||
size_t s = size_($).load(rl::memory_order_relaxed);
|
||||
size_($).store(s - 1, rl::memory_order_relaxed);
|
||||
n->prev_($)->next_($) = n->next_($);
|
||||
n->next_($)->prev_($) = n->prev_($);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_($).load(rl::memory_order_relaxed);
|
||||
}
|
||||
|
||||
node* begin()
|
||||
{
|
||||
return head_.next_($);
|
||||
}
|
||||
|
||||
void flush_to(dlist& target)
|
||||
{
|
||||
if (size_($).load(rl::memory_order_relaxed))
|
||||
{
|
||||
target.size_($).store(size_($).load(rl::memory_order_relaxed));
|
||||
target.head_.next_($) = head_.next_($);
|
||||
target.head_.next_($)->prev_($) = &target.head_;
|
||||
target.tail_.prev_($) = tail_.prev_($);
|
||||
target.tail_.prev_($)->next_($) = &target.tail_;
|
||||
}
|
||||
else
|
||||
{
|
||||
target.reset();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
static bool not_last(node* n)
|
||||
{
|
||||
return n->next_($) != 0;
|
||||
}
|
||||
|
||||
static node* get_next(node* n)
|
||||
{
|
||||
return n->next_($);
|
||||
}
|
||||
|
||||
private:
|
||||
rl::atomic<size_t> size_;
|
||||
node head_;
|
||||
node tail_;
|
||||
|
||||
void reset()
|
||||
{
|
||||
size_($) = 0;
|
||||
head_.next_($) = &tail_;
|
||||
head_.prev_($) = 0;
|
||||
tail_.next_($) = 0;
|
||||
tail_.prev_($) = &head_;
|
||||
}
|
||||
|
||||
dlist(dlist const&);
|
||||
dlist& operator = (dlist const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** pre-thread descriptor for eventcount
|
||||
*/
|
||||
struct ec_thread
|
||||
{
|
||||
dlist::node node_;
|
||||
semaphore sema_;
|
||||
rl::var<unsigned> epoch_;
|
||||
rl::atomic<bool> in_waitset_;
|
||||
rl::var<bool> spurious_;
|
||||
rl::var<void*> ctx_;
|
||||
|
||||
ec_thread()
|
||||
{
|
||||
epoch_($) = 0;
|
||||
in_waitset_($) = false;
|
||||
spurious_($) = false;
|
||||
ctx_($) = 0;
|
||||
}
|
||||
|
||||
~ec_thread()
|
||||
{
|
||||
if (spurious_($))
|
||||
sema_.wait();
|
||||
}
|
||||
|
||||
/*
|
||||
static ec_thread* current()
|
||||
{
|
||||
static THREAD_LOCAL ec_thread* ec_thread_instance = 0;
|
||||
ec_thread* instance = ec_thread_instance;
|
||||
if (instance == 0)
|
||||
{
|
||||
instance = new ec_thread;
|
||||
ec_thread_instance = instance;
|
||||
}
|
||||
return instance;
|
||||
// instance must be destroyed in DllMain() callback
|
||||
// or in pthread_key_create() callback
|
||||
}
|
||||
*/
|
||||
|
||||
private:
|
||||
ec_thread(ec_thread const&);
|
||||
ec_thread& operator = (ec_thread const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** fine-grained eventcount implementation
|
||||
*/
|
||||
class eventcount
|
||||
{
|
||||
public:
|
||||
eventcount()
|
||||
{
|
||||
epoch_($) = 0;
|
||||
}
|
||||
|
||||
void prepare_wait(ec_thread* th = 0, void* ctx = 0)
|
||||
{
|
||||
RL_ASSERT(th);
|
||||
// this is good place to pump previous spurious wakeup
|
||||
if (th->spurious_($))
|
||||
{
|
||||
th->spurious_($) = false;
|
||||
th->sema_.wait();
|
||||
}
|
||||
th->in_waitset_($).store(true, rl::memory_order_relaxed);
|
||||
th->ctx_($) = ctx;
|
||||
{
|
||||
lock l (mtx_);
|
||||
th->epoch_($) = epoch_($).load(rl::memory_order_relaxed);
|
||||
waitset_.push(&th->node_);
|
||||
}
|
||||
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
void commit_wait(ec_thread* th = 0)
|
||||
{
|
||||
RL_ASSERT(th);
|
||||
// this check is just an optimization
|
||||
//if (th->epoch_($) == epoch_($).load(rl::memory_order_relaxed))
|
||||
if (th->in_waitset_($).load(rl::memory_order_acquire))
|
||||
th->sema_.wait();
|
||||
else
|
||||
cancel_wait(true, th); //!!! add 'th'
|
||||
}
|
||||
|
||||
void cancel_wait(bool /*from_commit*/, ec_thread* th = 0)
|
||||
{
|
||||
RL_ASSERT(th);
|
||||
// spurious wakeup will be pumped in the following prepare_wait()
|
||||
th->spurious_($) = true;
|
||||
// try to remove node from waitset
|
||||
if (th->in_waitset_($).load(rl::memory_order_acquire))
|
||||
{
|
||||
lock l (mtx_);
|
||||
if (th->in_waitset_($).load(rl::memory_order_relaxed))
|
||||
{
|
||||
// successfully removed from waitset,
|
||||
// so there will be no spurious wakeup
|
||||
th->in_waitset_($).store(false, rl::memory_order_relaxed);
|
||||
th->spurious_($) = false;
|
||||
waitset_.remove(&th->node_);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (from_commit)
|
||||
//int volatile x = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//RL_ASSERT(from_commit == false);
|
||||
//if (from_commit)
|
||||
// int volatile x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
|
||||
notify_one_relaxed();
|
||||
}
|
||||
|
||||
template<typename predicate_t>
|
||||
void notify(predicate_t pred)
|
||||
{
|
||||
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
|
||||
notify_relaxed(pred);
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
|
||||
notify_all_relaxed();
|
||||
}
|
||||
|
||||
void notify_one_relaxed()
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist::node* n;
|
||||
{
|
||||
lock l (mtx_);
|
||||
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
|
||||
epoch_($).store(ep + 1, rl::memory_order_relaxed);
|
||||
n = waitset_.pop();
|
||||
if (n)
|
||||
to_ec_thread(n)->in_waitset_($).store(false, rl::memory_order_release);
|
||||
}
|
||||
if (n)
|
||||
{
|
||||
to_ec_thread(n)->sema_.post();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename predicate_t>
|
||||
void notify_relaxed(predicate_t pred)
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist temp;
|
||||
{
|
||||
lock l (mtx_);
|
||||
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
|
||||
epoch_($).store(ep + 1, rl::memory_order_relaxed);
|
||||
size_t size = waitset_.size();
|
||||
size_t idx = 0;
|
||||
dlist::node* n = waitset_.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
ec_thread* th = to_ec_thread(n);
|
||||
if (pred(th->ctx_($), size, idx))
|
||||
{
|
||||
waitset_.remove(n);
|
||||
temp.push(n);
|
||||
th->in_waitset_($).store(false, rl::memory_order_release);
|
||||
}
|
||||
n = next;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
to_ec_thread(n)->sema_.post();
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all_relaxed()
|
||||
{
|
||||
if (waitset_.size() == 0)
|
||||
return;
|
||||
dlist temp;
|
||||
{
|
||||
lock l (mtx_);
|
||||
waitset_.flush_to(temp);
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
to_ec_thread(n)->in_waitset_($).store(false, rl::memory_order_release);
|
||||
n = dlist::get_next(n);
|
||||
}
|
||||
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
|
||||
epoch_($).store(ep + 1, rl::memory_order_relaxed);
|
||||
}
|
||||
dlist::node* n = temp.begin();
|
||||
while (dlist::not_last(n))
|
||||
{
|
||||
dlist::node* next = dlist::get_next(n);
|
||||
to_ec_thread(n)->sema_.post();
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
class wait_guard;
|
||||
|
||||
private:
|
||||
mutex mtx_;
|
||||
dlist waitset_;
|
||||
rl::atomic<unsigned>epoch_;
|
||||
|
||||
ec_thread* to_ec_thread(dlist::node* n)
|
||||
{
|
||||
return (ec_thread*)((char*)n - offsetof(ec_thread, node_));
|
||||
}
|
||||
|
||||
eventcount(eventcount const&);
|
||||
eventcount& operator = (eventcount const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class eventcount::wait_guard
|
||||
{
|
||||
public:
|
||||
wait_guard(eventcount& ec, ec_thread* th = 0, void* ctx = 0)
|
||||
: ec_(ec)
|
||||
, th_(th)
|
||||
, wait_(false)
|
||||
{
|
||||
ec_.prepare_wait(th_, ctx);
|
||||
}
|
||||
|
||||
void commit_wait()
|
||||
{
|
||||
assert(false == wait_);
|
||||
wait_ = true;
|
||||
ec_.commit_wait(th_);
|
||||
}
|
||||
|
||||
~wait_guard()
|
||||
{
|
||||
if (false == wait_)
|
||||
ec_.cancel_wait(false, th_);
|
||||
}
|
||||
|
||||
private:
|
||||
eventcount& ec_;
|
||||
ec_thread* th_;
|
||||
bool wait_;
|
||||
|
||||
wait_guard(wait_guard const&);
|
||||
wait_guard& operator = (wait_guard const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct scheduler
|
||||
{
|
||||
struct tbb_thread
|
||||
{
|
||||
ec_thread th;
|
||||
};
|
||||
|
||||
eventcount ec_;
|
||||
tbb_thread* threads_;
|
||||
bool volatile is_permanently_open_;
|
||||
|
||||
void wait_while_pool_is_empty(tbb_thread* th)
|
||||
{
|
||||
if (is_permanently_open_)
|
||||
return;
|
||||
eventcount::wait_guard wait (ec_, &th->th);
|
||||
if (pool_is_empty())
|
||||
wait.commit_wait();
|
||||
}
|
||||
|
||||
void notify_about_new_task_available()
|
||||
{
|
||||
ec_.notify_one_relaxed();
|
||||
}
|
||||
|
||||
void notify_about_new_task_available_with_preference(tbb_thread* preference)
|
||||
{
|
||||
struct local
|
||||
{
|
||||
tbb_thread* preference_;
|
||||
bool fired_;
|
||||
|
||||
bool operator () (void* ctx, size_t count, size_t idx)
|
||||
{
|
||||
tbb_thread* th = (tbb_thread*)ctx;
|
||||
if (th == preference_)
|
||||
{
|
||||
fired_ = true;
|
||||
return true;
|
||||
}
|
||||
else if (idx == count - 1 && fired_ == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
pred = {preference};
|
||||
ec_.notify_relaxed(pred);
|
||||
}
|
||||
|
||||
void notify_about_list_of_tasks_available(size_t total_count, size_t preference_count, tbb_thread** preferences)
|
||||
{
|
||||
struct local
|
||||
{
|
||||
size_t remain_to_signal_;
|
||||
size_t preference_count_;
|
||||
tbb_thread** preferences_;
|
||||
|
||||
bool operator () (void* ctx, size_t count, size_t idx)
|
||||
{
|
||||
tbb_thread* th = (tbb_thread*)ctx;
|
||||
size_t remain_in_waitset = count - idx;
|
||||
if (remain_in_waitset <= remain_to_signal_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i != preference_count_; ++i)
|
||||
{
|
||||
if (preferences_[i] == th)
|
||||
{
|
||||
remain_to_signal_ -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pred = {total_count, preference_count, preferences};
|
||||
ec_.notify_relaxed(pred);
|
||||
}
|
||||
|
||||
bool pool_is_empty()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct queue
|
||||
{
|
||||
rl::atomic<int> producer_idx_;
|
||||
rl::atomic<int> consumer_idx_;
|
||||
|
||||
rl::atomic<void*>* buffer_;
|
||||
|
||||
eventcount ec_;
|
||||
|
||||
queue()
|
||||
{
|
||||
producer_idx_($) = 0;
|
||||
consumer_idx_($) = 0;
|
||||
buffer_ = RL_NEW_ARR(rl::atomic<void*>, 10);
|
||||
for (size_t i = 0; i != 10; ++i)
|
||||
buffer_[i]($) = 0;
|
||||
}
|
||||
|
||||
~queue()
|
||||
{
|
||||
RL_DELETE_ARR(buffer_);
|
||||
}
|
||||
|
||||
void enqueue(void* data)
|
||||
{
|
||||
int idx = producer_idx_($).fetch_add(1) + 1; // atomic
|
||||
buffer_[idx]($).store(data, rl::memory_order_relaxed);
|
||||
|
||||
struct local
|
||||
{
|
||||
int idx_;
|
||||
bool operator () (void* ctx, size_t /*count*/, size_t /*idx*/)
|
||||
{
|
||||
return idx_ == (*(rl::var<int>*)ctx)($);
|
||||
}
|
||||
}
|
||||
pred = {idx};
|
||||
ec_.notify(pred); // not relaxed!!!
|
||||
}
|
||||
|
||||
void* dequeue(ec_thread* th)
|
||||
{
|
||||
int idx = consumer_idx_($).fetch_add(1) + 1; // atomic
|
||||
void* data = buffer_[idx]($).load(rl::memory_order_relaxed);
|
||||
if (data)
|
||||
return data;
|
||||
for (;;)
|
||||
{
|
||||
rl::var<int> idxv (idx);
|
||||
eventcount::wait_guard wait (ec_, th, &idxv);
|
||||
data = buffer_[idx]($).load(rl::memory_order_relaxed);
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
wait.commit_wait();
|
||||
idxv($) = 0;
|
||||
data = buffer_[idx]($).load(rl::memory_order_relaxed);
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
rl::yield($, 1);
|
||||
//RL_ASSERT(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class condition_variable
|
||||
{
|
||||
eventcount ec_;
|
||||
|
||||
public:
|
||||
void wait(mutex& mtx, ec_thread* th)
|
||||
{
|
||||
eventcount::wait_guard wait (ec_, th);
|
||||
mtx.unlock();
|
||||
wait.commit_wait();
|
||||
mtx.lock();
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
ec_.notify_one();
|
||||
}
|
||||
|
||||
void broadcast()
|
||||
{
|
||||
ec_.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct queue_test : rl::test_suite<queue_test, 4>
|
||||
{
|
||||
ec_thread threads_ [6];
|
||||
queue q_;
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (index < 2)
|
||||
{
|
||||
q_.enqueue((void*)(index*2+1));
|
||||
q_.enqueue((void*)(index*2+2));
|
||||
}
|
||||
else
|
||||
{
|
||||
int data1 = (int)q_.dequeue(&threads_[index]);
|
||||
RL_ASSERT(data1 >= 1 && data1 <= 6);
|
||||
int data2 = (int)q_.dequeue(&threads_[index]);
|
||||
RL_ASSERT(data2 >= 1 && data2 <= 6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct condvar_test : rl::test_suite<condvar_test, 3>
|
||||
{
|
||||
rl::var<int> stage;
|
||||
condition_variable cv;
|
||||
mutex mtx;
|
||||
ec_thread th [3];
|
||||
|
||||
void before()
|
||||
{
|
||||
stage($) = 0;
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
mtx.lock();
|
||||
stage($) += 1;
|
||||
cv.broadcast();
|
||||
while (stage($) != 2)
|
||||
cv.wait(mtx, &th[index]);
|
||||
mtx.unlock();
|
||||
}
|
||||
else if (1 == index)
|
||||
{
|
||||
mtx.lock();
|
||||
while (stage($) != 1)
|
||||
cv.wait(mtx, &th[index]);
|
||||
stage($) += 1;
|
||||
cv.broadcast();
|
||||
mtx.unlock();
|
||||
}
|
||||
else if (2 == index)
|
||||
{
|
||||
mtx.lock();
|
||||
while (stage($) != 2)
|
||||
cv.wait(mtx, &th[index]);
|
||||
mtx.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
p.iteration_count = 100000000;
|
||||
//p.initial_state = "30000000";
|
||||
//p.search_type = rl::fair_context_bound_scheduler_type;
|
||||
rl::simulate<queue_test>(p);
|
||||
//rl::simulate<condvar_test>(p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="eventcount"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
|
||||
RootNamespace="eventcount"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\eventcount.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="eventcount"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
|
||||
RootNamespace="eventcount"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\eventcount.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ws_deque.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="ws_deque"
|
||||
ProjectGUID="{0B597F19-DEBB-4832-B520-9A93A286D595}"
|
||||
RootNamespace="ws_deque"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ws_deque.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="ws_deque"
|
||||
ProjectGUID="{0B597F19-DEBB-4832-B520-9A93A286D595}"
|
||||
RootNamespace="ws_deque"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
ObjectFile="$(IntDir)\$(InputName)1.obj"
|
||||
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ws_deque.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define _SECURE_SCL 0
|
||||
#endif
|
||||
|
||||
#define RL_MSVC_OUTPUT
|
||||
//#define RL_DEBUGBREAK_ON_FAILURE
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
#include "stdafx.h"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using rl::var;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ws_deque
|
||||
{
|
||||
public:
|
||||
ws_deque()
|
||||
{
|
||||
VAR(m_mask) = initial_size - 1;
|
||||
m_headIndex.store(0, memory_order_relaxed);
|
||||
m_tailIndex.store(0, memory_order_relaxed);
|
||||
VAR(m_array) = new atomic<T> [initial_size];
|
||||
VAR(m_arraySize) = initial_size;
|
||||
}
|
||||
|
||||
~ws_deque()
|
||||
{
|
||||
delete [] VAR(m_array);
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return m_headIndex.load(memory_order_acquire)
|
||||
>= m_tailIndex.load(memory_order_acquire);
|
||||
}
|
||||
|
||||
size_t Count() const
|
||||
{
|
||||
return m_tailIndex.load(memory_order_acquire)
|
||||
- m_headIndex.load(memory_order_acquire);
|
||||
}
|
||||
|
||||
void push(T item)
|
||||
{
|
||||
size_t tail = m_tailIndex.load(memory_order_acquire);
|
||||
if (tail < m_headIndex.load(memory_order_acquire) + VAR(m_mask))
|
||||
{
|
||||
VAR(m_array)[tail & VAR(m_mask)].store(item, memory_order_relaxed);
|
||||
m_tailIndex.store(tail + 1, memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
size_t head = m_headIndex.load(memory_order_acquire);
|
||||
size_t count = Count();
|
||||
if (count >= VAR(m_mask))
|
||||
{
|
||||
size_t arraySize = m_arraySize($);
|
||||
size_t mask = VAR(m_mask);
|
||||
atomic<T>* newArray = new atomic<T> [arraySize * 2];
|
||||
atomic<T>* arr = m_array($);
|
||||
//!!! for (size_t i = 0; i != arraySize; ++i)
|
||||
for (size_t i = 0; i != count; ++i)
|
||||
newArray[i].store(arr[(i + head) & mask].load(memory_order_seq_cst), memory_order_relaxed);
|
||||
delete [] VAR(m_array);
|
||||
VAR(m_array) = newArray;
|
||||
VAR(m_arraySize) = arraySize * 2;
|
||||
m_headIndex.store(0, memory_order_release);
|
||||
m_tailIndex.store(count, memory_order_release);
|
||||
tail = count;
|
||||
VAR(m_mask) = (mask * 2) | 1;
|
||||
}
|
||||
VAR(m_array)[tail & VAR(m_mask)].store(item, memory_order_relaxed);
|
||||
m_tailIndex.store(tail + 1, memory_order_release);
|
||||
m_foreignLock.unlock($);
|
||||
}
|
||||
}
|
||||
|
||||
bool pop(T& item)
|
||||
{
|
||||
size_t tail = m_tailIndex.load(memory_order_acquire);
|
||||
if (tail == 0)
|
||||
return false;
|
||||
tail -= 1;
|
||||
m_tailIndex.store(tail, memory_order_release);
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
if (m_headIndex.load(memory_order_acquire) <= tail)
|
||||
{
|
||||
item = VAR(m_array)[tail & VAR(m_mask)].load(memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_foreignLock.lock($);
|
||||
if (m_headIndex.load(memory_order_acquire) <= tail)
|
||||
{
|
||||
item = VAR(m_array)[tail & VAR(m_mask)].load(memory_order_relaxed);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tailIndex.store(tail + 1, memory_order_release);
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool steal(T& item)
|
||||
{
|
||||
if (false == m_foreignLock.try_lock($))
|
||||
return false;
|
||||
size_t head = m_headIndex.load(memory_order_acquire);
|
||||
m_headIndex.store(head + 1, memory_order_release);
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
if (head < m_tailIndex.load(memory_order_acquire))
|
||||
{
|
||||
item = VAR(m_array)[head & VAR(m_mask)].load(memory_order_relaxed);
|
||||
m_foreignLock.unlock($);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_headIndex.store(head, memory_order_release);
|
||||
m_foreignLock.unlock($);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t const initial_size = 2;
|
||||
var<atomic<T>*> m_array;
|
||||
var<size_t> m_mask;
|
||||
var<size_t> m_arraySize;
|
||||
atomic<size_t> m_headIndex;
|
||||
atomic<size_t> m_tailIndex;
|
||||
mutex m_foreignLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ws_deque_test0 : rl::test_suite<ws_deque_test0, 4>
|
||||
{
|
||||
ws_deque<int> q;
|
||||
|
||||
void before()
|
||||
{
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push(10);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 5; ++i)
|
||||
{
|
||||
int p = 0;
|
||||
bool res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push(10);
|
||||
int p = 0;
|
||||
bool res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push(10);
|
||||
q.push(10);
|
||||
int p = 0;
|
||||
bool res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
p = 0;
|
||||
res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push(10);
|
||||
q.push(10);
|
||||
q.push(10);
|
||||
int p = 0;
|
||||
bool res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 14; ++i)
|
||||
{
|
||||
q.push(10);
|
||||
int p = 0;
|
||||
bool res = q.pop(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
int p = 0;
|
||||
bool res = q.steal(p);
|
||||
RL_ASSERT(10 == p || false == res);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ws_deque_test : rl::test_suite<ws_deque_test, 2>
|
||||
{
|
||||
ws_deque<int> q;
|
||||
bool state [2];
|
||||
|
||||
void before()
|
||||
{
|
||||
state[0] = true;
|
||||
state[1] = true;
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
RL_ASSERT(state[0] == false);
|
||||
RL_ASSERT(state[1] == false);
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
q.push(1);
|
||||
q.push(2);
|
||||
|
||||
int item = 0;
|
||||
bool res = q.pop(item);
|
||||
RL_ASSERT(res && item == 2);
|
||||
RL_ASSERT(state[1]);
|
||||
state[1] = false;
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
|
||||
item = 0;
|
||||
res = q.pop(item);
|
||||
RL_ASSERT(res == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int item = 0;
|
||||
bool res = q.steal(item);
|
||||
if (res)
|
||||
{
|
||||
RL_ASSERT(item == 1);
|
||||
RL_ASSERT(state[0]);
|
||||
state[0] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::simulate<ws_deque_test0>();
|
||||
rl::simulate<ws_deque_test>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="ws_deque"
|
||||
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}"
|
||||
RootNamespace="ws_deque"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ws_deque.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ws_deque.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../relacy/pch.hpp"
|
||||
#include "../../relacy/relacy_std.hpp"
|
||||
|
||||
@@ -0,0 +1,690 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
struct pdr
|
||||
{
|
||||
__declspec(thread) static pdr* instance;
|
||||
|
||||
static size_t const defer_limit = 1024;
|
||||
|
||||
typedef void(*dtor_f)(void*);
|
||||
struct entry_t
|
||||
{
|
||||
dtor_f dtor;
|
||||
void* ctx;
|
||||
};
|
||||
entry_t defer_list [defer_limit];
|
||||
size_t pos;
|
||||
size_t pos0;
|
||||
size_t thread_count;
|
||||
|
||||
size_t th [4];
|
||||
|
||||
void init(size_t count)
|
||||
{
|
||||
//assert(0 == instance);
|
||||
instance = this;
|
||||
|
||||
thread_count = count;
|
||||
pos = 0;
|
||||
pos0 = 0;
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
th[i] = defer_limit;
|
||||
}
|
||||
}
|
||||
|
||||
void fini()
|
||||
{
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
assert(th[i] == defer_limit);
|
||||
}
|
||||
|
||||
for (size_t i = pos0; i != pos; ++i)
|
||||
{
|
||||
assert(defer_list[i].dtor);
|
||||
defer_list[i].dtor(defer_list[i].ctx);
|
||||
}
|
||||
assert(this == instance);
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
|
||||
assert(th[rl::ctx().threadx_->index_] == defer_limit);
|
||||
th[rl::ctx().threadx_->index_] = pos;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
assert(th[rl::ctx().threadx_->index_] != defer_limit);
|
||||
th[rl::ctx().threadx_->index_] = defer_limit;
|
||||
pump();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void dtor_impl(void* p)
|
||||
{
|
||||
RL_DELETE(static_cast<T*>(p));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void defer(T* p)
|
||||
{
|
||||
std::atomic_thread_fence($)(std::memory_order_seq_cst);
|
||||
|
||||
assert(pos < defer_limit);
|
||||
entry_t& e = defer_list[pos++];
|
||||
e.dtor = &pdr::dtor_impl<T>;
|
||||
e.ctx = p;
|
||||
pump();
|
||||
}
|
||||
|
||||
void pump()
|
||||
{
|
||||
if (pos0 == pos)
|
||||
return;
|
||||
size_t min_pos = pos;
|
||||
for (size_t i = 0; i != thread_count; ++i)
|
||||
{
|
||||
if (th[i] < min_pos)
|
||||
min_pos = th[i];
|
||||
}
|
||||
for (size_t i = pos0; i != min_pos; ++i)
|
||||
{
|
||||
assert(defer_list[i].dtor);
|
||||
defer_list[i].dtor(defer_list[i].ctx);
|
||||
}
|
||||
pos0 = min_pos;
|
||||
}
|
||||
};
|
||||
|
||||
pdr* pdr::instance = 0;
|
||||
|
||||
void pdr_lock()
|
||||
{
|
||||
assert(pdr::instance);
|
||||
pdr::instance->lock();
|
||||
}
|
||||
|
||||
void pdr_unlock()
|
||||
{
|
||||
assert(pdr::instance);
|
||||
pdr::instance->unlock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void pdr_defer(T* p)
|
||||
{
|
||||
assert(pdr::instance);
|
||||
pdr::instance->defer(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ws_deque
|
||||
{
|
||||
public:
|
||||
|
||||
ws_deque()
|
||||
{
|
||||
bottom_.block_($) = 0;
|
||||
bottom_.real_block_id_ = 0;
|
||||
bottom_.real_index_ = 0;
|
||||
bottom_.block_id_ = 0;
|
||||
bottom_.index_ = 0;
|
||||
bottom_.block_seq_ = 0;
|
||||
bottom_.check_order_ = 1;
|
||||
|
||||
top::info t = {};
|
||||
top_.block_($) = 0;
|
||||
top_.info_($) = t;
|
||||
|
||||
alloc_block();
|
||||
bottom_.block_id_ = bottom_.block_($)->header_.id_;
|
||||
top_.block_($) = bottom_.block_($);
|
||||
t.top_block_id_ = static_cast<unsigned short>(top_.block_($).load()->header_.id_);
|
||||
t.bottom_block_id_ = static_cast<unsigned short>(top_.block_($).load()->header_.id_);
|
||||
top_.info_($) = t;
|
||||
}
|
||||
|
||||
~ws_deque()
|
||||
{
|
||||
for (block* p = top_.block_($), *next; p; p = next)
|
||||
{
|
||||
next = p->header_.next_($).load(std::memory_order_relaxed);
|
||||
RL_DELETE(p);
|
||||
}
|
||||
}
|
||||
|
||||
void push(void* const& i)
|
||||
{
|
||||
pdr_lock();
|
||||
|
||||
push_unbalanced(i);
|
||||
rebalance();
|
||||
|
||||
pdr_unlock();
|
||||
}
|
||||
|
||||
void push_unbalanced(void* i)
|
||||
{
|
||||
RL_ASSERT(bottom_.block_($)->header_.id_);
|
||||
|
||||
bottom_.block_($)->data_[bottom_.real_index_]($).store(i, std::memory_order_release);
|
||||
|
||||
if (block::item_count - 1 != bottom_.real_index_)
|
||||
{
|
||||
bottom_.real_index_ += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alloc_block();
|
||||
}
|
||||
}
|
||||
|
||||
void rebalance()
|
||||
{
|
||||
if (0 == --bottom_.check_order_)
|
||||
{
|
||||
check_bottom();
|
||||
}
|
||||
}
|
||||
|
||||
void* pop()
|
||||
{
|
||||
pdr_lock();
|
||||
|
||||
rebalance();
|
||||
void* p = pop_unbalanced();
|
||||
|
||||
pdr_unlock();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void* pop_unbalanced()
|
||||
{
|
||||
//!!! optimize
|
||||
|
||||
//! fast-path for empty deque
|
||||
|
||||
//! make comparasion faster
|
||||
|
||||
if ((bottom_.block_id_ != bottom_.real_block_id_
|
||||
|| bottom_.index_ != bottom_.real_index_)
|
||||
&& bottom_.real_index_)
|
||||
{
|
||||
bottom_.real_index_ -= 1;
|
||||
void* i = bottom_.block_($)->data_[bottom_.real_index_]($).load(std::memory_order_consume);
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pop_unbalanced_slow();
|
||||
}
|
||||
}
|
||||
|
||||
void* pop_unbalanced_slow()
|
||||
{
|
||||
if (0 == bottom_.real_index_)
|
||||
{
|
||||
if (bottom_.real_block_id_ > bottom_.block_id_)
|
||||
{
|
||||
return pop_slow();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
void* i;
|
||||
pop_check_result const rv = pop_check(i);
|
||||
if (pop_check_cont != rv)
|
||||
return pop_check_succ == rv ? i : 0;
|
||||
return pop_unbalanced(); // recursion, must succeed
|
||||
}
|
||||
}
|
||||
|
||||
void* steal()
|
||||
{
|
||||
pdr_lock();
|
||||
|
||||
retry:
|
||||
for (;;)
|
||||
{
|
||||
block* old_b = top_.block_($).load(std::memory_order_acquire);
|
||||
block* b = old_b;
|
||||
top::info old = top_.info_($).load(std::memory_order_consume);
|
||||
|
||||
if (old.top_index_ == old.bottom_index_
|
||||
&& old.top_block_id_ == old.bottom_block_id_)
|
||||
{
|
||||
pdr_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (b->header_.id_ != old.top_block_id_)
|
||||
{
|
||||
do
|
||||
{
|
||||
b = b->header_.next_($).load(std::memory_order_relaxed);
|
||||
//RL_ASSERT(b);
|
||||
//!!! temp stub - is it right?
|
||||
// it seems that we always return 0 after we hit this goto
|
||||
if (0 == b)
|
||||
goto retry;
|
||||
}
|
||||
//!!! AV
|
||||
// b == 0
|
||||
while (b->header_.id_ != old.top_block_id_);
|
||||
|
||||
if (top_.block_($).compare_swap(old_b, b, std::memory_order_seq_cst))
|
||||
{
|
||||
block* cur_b = old_b;
|
||||
do
|
||||
{
|
||||
pdr_defer(cur_b);
|
||||
cur_b = cur_b->header_.next_($).load(std::memory_order_relaxed);
|
||||
}
|
||||
while (cur_b != b);
|
||||
}
|
||||
}
|
||||
|
||||
block* next_block = 0;
|
||||
top::info mod = old;
|
||||
|
||||
void* i = b->data_[mod.top_index_]($).load(std::memory_order_consume);
|
||||
|
||||
if (block::item_count - 1 == mod.top_index_)
|
||||
{
|
||||
next_block = b->header_.next_($).load(std::memory_order_relaxed);
|
||||
mod.top_block_id_ += 1;
|
||||
mod.top_index_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod.top_index_ += 1;
|
||||
}
|
||||
|
||||
if (top_.info_($).compare_swap(old, mod, std::memory_order_seq_cst))
|
||||
{
|
||||
if (next_block)
|
||||
{
|
||||
if (top_.block_($).compare_swap(b, next_block))
|
||||
{
|
||||
pdr_defer(b);
|
||||
}
|
||||
}
|
||||
|
||||
pdr_unlock();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned size() const
|
||||
{
|
||||
top::info const top = top_.info_($).load(std::memory_order_relaxed);
|
||||
//unsigned volatile const top_block_id = top_.info_.part_.top_block_id_;
|
||||
//unsigned volatile const top_index = top_.info_.part_.top_index_;
|
||||
|
||||
if (bottom_.real_block_id_ == top.top_block_id_)
|
||||
{
|
||||
unsigned const size = bottom_.real_index_ - top.top_index_;
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned size = bottom_.real_index_;
|
||||
size += block::item_count - top.top_index_;
|
||||
size += (bottom_.real_block_id_ - top.top_block_id_ - 1) * block::item_count;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct block
|
||||
{
|
||||
struct header
|
||||
{
|
||||
std::atomic<block*> next_;
|
||||
std::atomic<block*> prev_;
|
||||
ws_deque* deque_;
|
||||
unsigned id_;
|
||||
|
||||
//!!!
|
||||
~header()
|
||||
{
|
||||
id_ = 0;
|
||||
}
|
||||
};
|
||||
static unsigned const item_count = 2;
|
||||
|
||||
header header_;
|
||||
std::atomic<void*> data_ [item_count];
|
||||
};
|
||||
|
||||
struct bottom
|
||||
{
|
||||
rl::var<block*> block_;
|
||||
|
||||
unsigned check_order_;
|
||||
|
||||
unsigned real_block_id_;
|
||||
unsigned real_index_;
|
||||
|
||||
unsigned block_id_;
|
||||
unsigned index_;
|
||||
|
||||
unsigned block_seq_;
|
||||
};
|
||||
|
||||
struct top
|
||||
{
|
||||
struct info
|
||||
{
|
||||
unsigned short top_index_;
|
||||
unsigned short top_block_id_;
|
||||
unsigned short bottom_index_;
|
||||
unsigned short bottom_block_id_;
|
||||
|
||||
bool operator == (info const& x) const
|
||||
{
|
||||
return top_index_ == x.top_index_
|
||||
&& top_block_id_ == x.top_block_id_
|
||||
&& bottom_index_ == x.bottom_index_
|
||||
&& bottom_block_id_ == x.bottom_block_id_;
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& ss, info const& x)
|
||||
{
|
||||
return ss << "{" << x.top_index_
|
||||
<< "," << x.top_block_id_
|
||||
<< "," << x.bottom_index_
|
||||
<< "," << x.bottom_block_id_ << "}";
|
||||
}
|
||||
};
|
||||
|
||||
std::atomic<block*> block_;
|
||||
std::atomic<info> info_;
|
||||
};
|
||||
|
||||
bottom bottom_;
|
||||
|
||||
char pad1 [64];
|
||||
|
||||
top top_;
|
||||
|
||||
char pad2 [64];
|
||||
|
||||
void alloc_block()
|
||||
{
|
||||
//!!! check whether we already have next block in
|
||||
// bottom_.block_->header_.next_
|
||||
block* b = bottom_.block_($) ? bottom_.block_($)->header_.next_($).load(std::memory_order_relaxed) : 0;
|
||||
if (0 == b)
|
||||
{
|
||||
b = RL_NEW block;
|
||||
b->header_.deque_ = this;
|
||||
bottom_.block_seq_ += 1;
|
||||
|
||||
//!!!
|
||||
if (bottom_.block_seq_ > 0xffff) __asm int 3;
|
||||
|
||||
bottom_.block_seq_ &= 0xffff;
|
||||
b->header_.id_ = bottom_.block_seq_;
|
||||
b->header_.prev_($).store(bottom_.block_($), std::memory_order_relaxed);
|
||||
if (bottom_.block_($))
|
||||
bottom_.block_($)->header_.next_($).store(b, std::memory_order_relaxed);
|
||||
b->header_.next_($).store(0, std::memory_order_relaxed);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = b;
|
||||
bottom_.block_seq_ += 1;
|
||||
//__asm int 3;
|
||||
}
|
||||
bottom_.block_($) = b;
|
||||
bottom_.real_block_id_ = b->header_.id_;
|
||||
bottom_.real_index_ = 0;
|
||||
}
|
||||
|
||||
enum pop_check_result {pop_check_fail, pop_check_succ, pop_check_cont};
|
||||
|
||||
pop_check_result pop_check(void*& i)
|
||||
{
|
||||
check_bottom();
|
||||
|
||||
if (bottom_.block_id_ == bottom_.real_block_id_
|
||||
&& bottom_.index_ == bottom_.real_index_)
|
||||
{
|
||||
top::info const top = top_.info_($).load(std::memory_order_seq_cst);
|
||||
|
||||
if ((bottom_.block_id_ == top.top_block_id_
|
||||
&& bottom_.index_ == (unsigned)top.top_index_ + 1)
|
||||
|| (bottom_.block_id_ == (unsigned)top.top_block_id_ + 1
|
||||
&& block::item_count - 1 == top.top_index_
|
||||
&& 0 == bottom_.index_ ))
|
||||
{
|
||||
__asm int 3;
|
||||
i = steal();
|
||||
if (i)
|
||||
return pop_check_succ;
|
||||
}
|
||||
|
||||
return pop_check_fail;
|
||||
}
|
||||
|
||||
return pop_check_cont;
|
||||
}
|
||||
|
||||
void* pop_slow()
|
||||
{
|
||||
bottom_.block_seq_ -= 1;
|
||||
bottom_.block_seq_ &= 0xffff;
|
||||
bottom_.block_($) = bottom_.block_($)->header_.prev_($).load(std::memory_order_relaxed);
|
||||
|
||||
//!!! AV: when core count set to 16
|
||||
// bottom_.block_ = 0
|
||||
// bottom.real_block_id = 1
|
||||
// bottom.block_id = 8
|
||||
|
||||
//!!! AV in xscale too (thread count is 4)
|
||||
// the same variables values
|
||||
bottom_.real_block_id_ = bottom_.block_($)->header_.id_;
|
||||
bottom_.real_index_ = block::item_count - 1;
|
||||
|
||||
top::info i = top_.info_($).load(std::memory_order_relaxed);
|
||||
|
||||
RL_ASSERT(bottom_.block_($)->header_.id_ == bottom_.block_seq_);
|
||||
RL_ASSERT((bottom_.real_block_id_ == i.bottom_block_id_ && bottom_.real_index_ >= i.bottom_index_)
|
||||
|| (bottom_.real_block_id_ > i.bottom_block_id_));
|
||||
|
||||
void* v = bottom_.block_($)->data_[block::item_count - 1]($).load(std::memory_order_consume);
|
||||
return v;
|
||||
}
|
||||
|
||||
void check_bottom()
|
||||
{
|
||||
//!!! must leave at least 1 element unreserved
|
||||
// because owner have to steal it
|
||||
|
||||
for (;;)
|
||||
{
|
||||
top::info old = top_.info_($).load(std::memory_order_relaxed);
|
||||
|
||||
unsigned const top_block_id = old.top_block_id_;
|
||||
unsigned const top_index = old.top_index_;
|
||||
|
||||
if (bottom_.real_block_id_ == top_block_id
|
||||
&& bottom_.real_index_ == top_index)
|
||||
{
|
||||
bottom_.check_order_ = 2;
|
||||
return;
|
||||
}
|
||||
unsigned const s = size();
|
||||
unsigned const r = reserved();
|
||||
if (!(0 == r || (r > 1 && 4*r > 3*s)))
|
||||
{
|
||||
//bottom_.check_order_ = 2;
|
||||
//!!! bottom_.check_order_ = s / 8 + 2;
|
||||
bottom_.check_order_ = s / 2 + 2;
|
||||
return;
|
||||
}
|
||||
unsigned r2 = s*3/4 + 1;
|
||||
if (r2 >= s)
|
||||
r2 = s - 1;
|
||||
unsigned bottom_block_id;
|
||||
unsigned bottom_index;
|
||||
if (r2 + top_index < block::item_count)
|
||||
{
|
||||
bottom_block_id = top_block_id;
|
||||
bottom_index = top_index + r2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned const r3 = r2 + top_index;
|
||||
bottom_block_id = top_block_id + r3 / block::item_count;
|
||||
bottom_index = r3 % block::item_count;
|
||||
}
|
||||
top::info i;
|
||||
i.top_block_id_ = static_cast<unsigned short>(top_block_id);
|
||||
i.top_index_ = static_cast<unsigned short>(top_index);
|
||||
i.bottom_block_id_ = static_cast<unsigned short>(bottom_block_id);
|
||||
i.bottom_index_ = static_cast<unsigned short>(bottom_index);
|
||||
|
||||
/*
|
||||
bottom volatile btm = bottom_;
|
||||
if (i.part_.top_block_id_ > i.part_.bottom_block_id_)
|
||||
__asm int 3;
|
||||
if (i.part_.top_block_id_ == i.part_.bottom_block_id_
|
||||
&& i.part_.top_index_ >= i.part_.bottom_index_)
|
||||
__asm int 3;
|
||||
if (i.part_.bottom_block_id_ > btm.real_block_id_)
|
||||
__asm int 3;
|
||||
if (i.part_.bottom_block_id_ == btm.real_block_id_
|
||||
&& i.part_.bottom_index_ > btm.real_index_)
|
||||
__asm int 3;
|
||||
*/
|
||||
|
||||
if (top_.info_($).compare_swap(old, i, std::memory_order_seq_cst))
|
||||
{
|
||||
bottom_.block_id_ = bottom_block_id;
|
||||
bottom_.index_ = bottom_index;
|
||||
//!!! bottom_.check_order_ = s / 8 + 2;
|
||||
bottom_.check_order_ = s / 2 + 2;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned reserved() const
|
||||
{
|
||||
if (bottom_.real_block_id_ == bottom_.block_id_)
|
||||
{
|
||||
unsigned const reserved = bottom_.real_index_ - bottom_.index_;
|
||||
return reserved;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned reserved = bottom_.real_index_;
|
||||
reserved += block::item_count - bottom_.index_;
|
||||
reserved += (bottom_.real_block_id_ - bottom_.block_id_ - 1) * block::item_count;
|
||||
return reserved;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int x = 0;
|
||||
|
||||
struct ws_deque_test : rl::test_suite<ws_deque_test, 4>
|
||||
{
|
||||
ws_deque q;
|
||||
pdr p;
|
||||
|
||||
void before()
|
||||
{
|
||||
p.init(4);
|
||||
}
|
||||
|
||||
void after()
|
||||
{
|
||||
p.fini();
|
||||
}
|
||||
|
||||
void thread(unsigned index)
|
||||
{
|
||||
if (0 == index)
|
||||
{
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push((void*)10);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 5; ++i)
|
||||
{
|
||||
void* p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push((void*)10);
|
||||
void* p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push((void*)10);
|
||||
q.push((void*)10);
|
||||
void* p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
q.push((void*)10);
|
||||
q.push((void*)10);
|
||||
q.push((void*)10);
|
||||
void* p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != 14; ++i)
|
||||
{
|
||||
q.push((void*)10);
|
||||
void* p = q.pop();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
void* p = q.steal();
|
||||
RL_ASSERT((void*)10 == p || 0 == p);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rl::test_params p;
|
||||
p.iteration_count = 1000000;
|
||||
rl::simulate<ws_deque_test>(p);
|
||||
}
|
||||
|
||||
723
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic.hpp
vendored
Normal file
723
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic.hpp
vendored
Normal file
@@ -0,0 +1,723 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_ATOMIC_HPP
|
||||
#define RL_ATOMIC_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "context.hpp"
|
||||
#include "memory_order.hpp"
|
||||
#include "signature.hpp"
|
||||
#include "atomic_events.hpp"
|
||||
#include "waitset.hpp"
|
||||
#include "rmw.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic;
|
||||
|
||||
|
||||
template<bool> struct bool_t {};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic_proxy_const
|
||||
{
|
||||
public:
|
||||
atomic_proxy_const(atomic<T> const /*volatile*/& var, debug_info_param info)
|
||||
: var_(const_cast<atomic<T>&>(var))
|
||||
, info_(info)
|
||||
{
|
||||
}
|
||||
|
||||
T load(memory_order mo = mo_seq_cst) const
|
||||
{
|
||||
return var_.load(mo, info_);
|
||||
}
|
||||
|
||||
operator T () const
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
protected:
|
||||
atomic<T>& var_;
|
||||
debug_info info_;
|
||||
|
||||
atomic_proxy_const& operator = (atomic_proxy_const const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic_proxy : public atomic_proxy_const<T>
|
||||
{
|
||||
public:
|
||||
typedef typename atomic_add_type<T>::type add_type;
|
||||
|
||||
atomic_proxy(atomic<T> /*volatile*/& var, debug_info_param info)
|
||||
: atomic_proxy_const<T>(var, info)
|
||||
{
|
||||
}
|
||||
|
||||
void store(T value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
this->var_.store(value, mo, this->info_);
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& cmp, T xchg, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.compare_exchange(bool_t<true>(), cmp, xchg, mo, this->info_);
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& cmp, T xchg, memory_order mo, memory_order failure_mo)
|
||||
{
|
||||
return this->var_.compare_exchange(bool_t<true>(), cmp, xchg, mo, failure_mo, this->info_);
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& cmp, T xchg, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.compare_exchange(bool_t<false>(), cmp, xchg, mo, this->info_);
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& cmp, T xchg, memory_order mo, memory_order failure_mo)
|
||||
{
|
||||
return this->var_.compare_exchange(bool_t<false>(), cmp, xchg, mo, failure_mo, this->info_);
|
||||
}
|
||||
|
||||
T exchange(T xchg, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_swap>(), xchg, mo, this->info_);
|
||||
}
|
||||
|
||||
T fetch_add(add_type value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_add>(), value, mo, this->info_);
|
||||
}
|
||||
|
||||
T fetch_sub(add_type value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_sub>(), value, mo, this->info_);
|
||||
}
|
||||
|
||||
T fetch_and(T value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_and>(), value, mo, this->info_);
|
||||
}
|
||||
|
||||
T fetch_or(T value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_or>(), value, mo, this->info_);
|
||||
}
|
||||
|
||||
T fetch_xor(T value, memory_order mo = mo_seq_cst)
|
||||
{
|
||||
return this->var_.rmw(rmw_type_t<rmw_type_xor>(), value, mo, this->info_);
|
||||
}
|
||||
|
||||
T operator = (T value)
|
||||
{
|
||||
store(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
T operator ++ (int)
|
||||
{
|
||||
return fetch_add(1);
|
||||
}
|
||||
|
||||
T operator -- (int)
|
||||
{
|
||||
return fetch_sub(1);
|
||||
}
|
||||
|
||||
T operator ++ ()
|
||||
{
|
||||
return fetch_add(1) + 1;
|
||||
}
|
||||
|
||||
T operator -- ()
|
||||
{
|
||||
return fetch_sub(1) - 1;
|
||||
}
|
||||
|
||||
T operator += (add_type value)
|
||||
{
|
||||
return fetch_add(value) + value;
|
||||
}
|
||||
|
||||
T operator -= (add_type value)
|
||||
{
|
||||
return fetch_sub(value) + value;
|
||||
}
|
||||
|
||||
T operator &= (T value)
|
||||
{
|
||||
return fetch_and(value) & value;
|
||||
}
|
||||
|
||||
T operator |= (T value)
|
||||
{
|
||||
return fetch_or(value) | value;
|
||||
}
|
||||
|
||||
T operator ^= (T value)
|
||||
{
|
||||
return fetch_xor(value) ^ value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T, bool strong_init>
|
||||
class generic_atomic
|
||||
{
|
||||
public:
|
||||
generic_atomic()
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
impl_ = c.atomic_ctor(this);
|
||||
initialized_ = false;
|
||||
value_ = T();
|
||||
already_failed_ = false;
|
||||
|
||||
if (val(strong_init))
|
||||
{
|
||||
unsigned const index = c.threadx_->atomic_init(impl_);
|
||||
last_index_ = index;
|
||||
initialized_ = true;
|
||||
history_[index] = T();
|
||||
value_ = T();
|
||||
}
|
||||
}
|
||||
|
||||
~generic_atomic()
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
sign_.check($);
|
||||
c.atomic_dtor(impl_);
|
||||
}
|
||||
|
||||
T debug_value() const
|
||||
{
|
||||
sign_.check($);
|
||||
return value_;
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
T load(memory_order mo, debug_info_param info) const
|
||||
{
|
||||
RL_VERIFY(mo_release != mo);
|
||||
RL_VERIFY(mo_acq_rel != mo);
|
||||
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed: return load_impl<mo_relaxed, &thread_info_base::atomic_load_relaxed>(info);
|
||||
case mo_consume: return load_impl<mo_consume, &thread_info_base::atomic_load_acquire>(info);
|
||||
case mo_acquire: return load_impl<mo_acquire, &thread_info_base::atomic_load_acquire>(info);
|
||||
case mo_seq_cst: return load_impl<mo_seq_cst, &thread_info_base::atomic_load_seq_cst>(info);
|
||||
default: break;
|
||||
}
|
||||
|
||||
RL_VERIFY(false);
|
||||
return T();
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
void store(T v, memory_order mo, debug_info_param info)
|
||||
{
|
||||
RL_VERIFY(mo_acquire != mo);
|
||||
RL_VERIFY(mo_acq_rel != mo);
|
||||
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed: return store_impl<mo_relaxed, &thread_info_base::atomic_store_relaxed>(v, info);
|
||||
case mo_release: return store_impl<mo_release, &thread_info_base::atomic_store_release>(v, info);
|
||||
case mo_seq_cst: return store_impl< mo_seq_cst, &thread_info_base::atomic_store_seq_cst>(v, info);
|
||||
default: break;
|
||||
}
|
||||
|
||||
RL_VERIFY(false);
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
bool compare_exchange_weak(T& cmp, T xchg, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return compare_exchange(bool_t<true>(), cmp, xchg, mo, info);
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
bool compare_exchange_strong(T& cmp, T xchg, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return compare_exchange(bool_t<false>(), cmp, xchg, mo, info);
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
bool compare_exchange_weak(T& cmp, T xchg, memory_order mo, debug_info_param info, memory_order failure_mo, debug_info_param)
|
||||
{
|
||||
return compare_exchange(bool_t<true>(), cmp, xchg, mo, failure_mo, info);
|
||||
}
|
||||
|
||||
RL_INLINE
|
||||
bool compare_exchange_strong(T& cmp, T xchg, memory_order mo, debug_info_param info, memory_order failure_mo, debug_info_param)
|
||||
{
|
||||
return compare_exchange(bool_t<false>(), cmp, xchg, mo, failure_mo, info);
|
||||
}
|
||||
|
||||
template<bool spurious_failures>
|
||||
RL_INLINE
|
||||
bool compare_exchange(bool_t<spurious_failures>, T& cmp, T xchg, memory_order mo, debug_info_param info)
|
||||
{
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed: return compare_swap_impl<spurious_failures, mo_relaxed, &thread_info_base::atomic_rmw_relaxed, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_consume: return compare_swap_impl<spurious_failures, mo_consume, &thread_info_base::atomic_rmw_acquire, mo_consume, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_acquire: return compare_swap_impl<spurious_failures, mo_acquire, &thread_info_base::atomic_rmw_acquire, mo_acquire, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_release: return compare_swap_impl<spurious_failures, mo_release, &thread_info_base::atomic_rmw_release, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_acq_rel: return compare_swap_impl<spurious_failures, mo_acq_rel, &thread_info_base::atomic_rmw_acq_rel, mo_acquire, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_seq_cst: return compare_swap_impl<spurious_failures, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst, mo_seq_cst, &thread_info_base::atomic_load_seq_cst_rmw>(cmp, xchg, info);
|
||||
}
|
||||
|
||||
RL_VERIFY(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool spurious_failures>
|
||||
RL_INLINE
|
||||
bool compare_exchange(bool_t<spurious_failures>, T& cmp, T xchg, memory_order mo, memory_order failure_mo, debug_info_param info)
|
||||
{
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo);
|
||||
return compare_swap_impl<spurious_failures, mo_relaxed, &thread_info_base::atomic_rmw_relaxed, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
}
|
||||
case mo_consume:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo || mo_consume == failure_mo);
|
||||
switch (failure_mo)
|
||||
{
|
||||
case mo_relaxed: return compare_swap_impl<spurious_failures, mo_consume, &thread_info_base::atomic_rmw_acquire, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_consume: return compare_swap_impl<spurious_failures, mo_consume, &thread_info_base::atomic_rmw_acquire, mo_consume, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
default: RL_VERIFY(false); return false;
|
||||
}
|
||||
}
|
||||
case mo_acquire:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo || mo_consume == failure_mo || mo_acquire == failure_mo);
|
||||
switch (failure_mo)
|
||||
{
|
||||
case mo_relaxed: return compare_swap_impl<spurious_failures, mo_acquire, &thread_info_base::atomic_rmw_acquire, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_consume: return compare_swap_impl<spurious_failures, mo_acquire, &thread_info_base::atomic_rmw_acquire, mo_consume, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_acquire: return compare_swap_impl<spurious_failures, mo_acquire, &thread_info_base::atomic_rmw_acquire, mo_acquire, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
default: RL_VERIFY(false); return false;
|
||||
}
|
||||
}
|
||||
case mo_release:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo);
|
||||
return compare_swap_impl<spurious_failures, mo_release, &thread_info_base::atomic_rmw_release, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
}
|
||||
case mo_acq_rel:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo || mo_consume == failure_mo || mo_acquire == failure_mo);
|
||||
switch (failure_mo)
|
||||
{
|
||||
case mo_relaxed: return compare_swap_impl<spurious_failures, mo_acq_rel, &thread_info_base::atomic_rmw_acq_rel, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_consume: return compare_swap_impl<spurious_failures, mo_acq_rel, &thread_info_base::atomic_rmw_acq_rel, mo_consume, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_acquire: return compare_swap_impl<spurious_failures, mo_acq_rel, &thread_info_base::atomic_rmw_acq_rel, mo_acquire, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
default: RL_VERIFY(false); return false;
|
||||
}
|
||||
}
|
||||
case mo_seq_cst:
|
||||
{
|
||||
RL_VERIFY(mo_relaxed == failure_mo || mo_consume == failure_mo || mo_acquire == failure_mo || mo_seq_cst == failure_mo);
|
||||
switch (failure_mo)
|
||||
{
|
||||
case mo_relaxed: return compare_swap_impl<spurious_failures, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst, mo_relaxed, &thread_info_base::atomic_load_relaxed_rmw>(cmp, xchg, info);
|
||||
case mo_consume: return compare_swap_impl<spurious_failures, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst, mo_consume, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_acquire: return compare_swap_impl<spurious_failures, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst, mo_acquire, &thread_info_base::atomic_load_acquire_rmw>(cmp, xchg, info);
|
||||
case mo_seq_cst: return compare_swap_impl<spurious_failures, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst, mo_seq_cst, &thread_info_base::atomic_load_seq_cst_rmw>(cmp, xchg, info);
|
||||
default: RL_VERIFY(false); return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RL_VERIFY(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
T exchange(T xchg, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_swap>(), xchg, mo, info);
|
||||
}
|
||||
|
||||
T fetch_add(typename atomic_add_type<T>::type value, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_add>(), value, mo, info);
|
||||
}
|
||||
|
||||
T fetch_sub(typename atomic_add_type<T>::type value, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_sub>(), value, mo, info);
|
||||
}
|
||||
|
||||
T fetch_and(T value, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_and>(), value, mo, info);
|
||||
}
|
||||
|
||||
T fetch_or(T value, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_or>(), value, mo, info);
|
||||
}
|
||||
|
||||
T fetch_xor(T value, memory_order mo, debug_info_param info)
|
||||
{
|
||||
return rmw(rmw_type_t<rmw_type_xor>(), value, mo, info);
|
||||
}
|
||||
|
||||
template<typename Y, rmw_type_e type>
|
||||
RL_INLINE
|
||||
T rmw(rmw_type_t<type>, Y op, memory_order mo, debug_info_param info)
|
||||
{
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed: return rmw_impl<Y, mo_relaxed, &thread_info_base::atomic_rmw_relaxed>(rmw_type_t<type>(), op, info);
|
||||
case mo_consume: return rmw_impl<Y, mo_consume, &thread_info_base::atomic_rmw_acquire>(rmw_type_t<type>(), op, info);
|
||||
case mo_acquire: return rmw_impl<Y, mo_acquire, &thread_info_base::atomic_rmw_acquire>(rmw_type_t<type>(), op, info);
|
||||
case mo_release: return rmw_impl<Y, mo_release, &thread_info_base::atomic_rmw_release>(rmw_type_t<type>(), op, info);
|
||||
case mo_acq_rel: return rmw_impl<Y, mo_acq_rel, &thread_info_base::atomic_rmw_acq_rel>(rmw_type_t<type>(), op, info);
|
||||
case mo_seq_cst: return rmw_impl<Y, mo_seq_cst, &thread_info_base::atomic_rmw_seq_cst>(rmw_type_t<type>(), op, info);
|
||||
}
|
||||
|
||||
RL_VERIFY(false);
|
||||
return T();
|
||||
}
|
||||
|
||||
unpark_reason wait(context& c, bool is_timed, bool allow_spurious_wakeup, debug_info_param info)
|
||||
{
|
||||
sign_.check(info);
|
||||
return c.threadx_->atomic_wait(impl_, is_timed, allow_spurious_wakeup, info);
|
||||
}
|
||||
|
||||
thread_id_t wake(context& c, thread_id_t count, debug_info_param info)
|
||||
{
|
||||
sign_.check(info);
|
||||
return c.threadx_->atomic_wake(impl_, count, info);
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
T history_ [atomic_history_size];
|
||||
atomic_data* impl_;
|
||||
unsigned last_index_;
|
||||
signature<987654321> sign_;
|
||||
bool initialized_;
|
||||
bool already_failed_;
|
||||
|
||||
template<memory_order mo, unsigned (thread_info_base::*impl)(atomic_data* RL_RESTRICT data)>
|
||||
T load_impl(debug_info_param info) const
|
||||
{
|
||||
context& c = ctx();
|
||||
c.sched();
|
||||
sign_.check(info);
|
||||
|
||||
if (false == c.invariant_executing)
|
||||
{
|
||||
unsigned const index = (c.threadx_->*impl)(impl_);
|
||||
if ((unsigned)-1 == index)
|
||||
{
|
||||
RL_HIST(atomic_load_event<T>) {this, T(), mo, false} RL_HIST_END();
|
||||
RL_ASSERT_IMPL(false, test_result_unitialized_access, "", info);
|
||||
}
|
||||
T const v = history_[index];
|
||||
|
||||
RL_HIST(atomic_load_event<T>) {this, v, mo, last_index_ != index} RL_HIST_END();
|
||||
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == initialized_)
|
||||
{
|
||||
RL_HIST(atomic_load_event<T>) {this, T(), mo, false} RL_HIST_END();
|
||||
RL_ASSERT_IMPL(false, test_result_unitialized_access, "", info);
|
||||
}
|
||||
return value_;
|
||||
}
|
||||
}
|
||||
|
||||
template<memory_order mo, unsigned (thread_info_base::*impl)(atomic_data* RL_RESTRICT data)>
|
||||
void store_impl(T v, debug_info_param info)
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
c.sched();
|
||||
sign_.check(info);
|
||||
|
||||
unsigned const index = (c.threadx_->*impl)(impl_);
|
||||
|
||||
T const prev = value_;
|
||||
last_index_ = index;
|
||||
history_[index] = v;
|
||||
value_ = v;
|
||||
initialized_ = true;
|
||||
RL_HIST(atomic_store_event<T>) {this, prev, v, mo} RL_HIST_END();
|
||||
}
|
||||
|
||||
template<bool spurious_failures, memory_order mo, unsigned (thread_info_base::*impl)(atomic_data* RL_RESTRICT data, bool&), memory_order failure_mo, unsigned (thread_info_base::*failure_impl)(atomic_data* RL_RESTRICT data)>
|
||||
bool compare_swap_impl(T& cmp, T xchg, debug_info_param info)
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
c.sched();
|
||||
sign_.check(info);
|
||||
|
||||
if (false == initialized_)
|
||||
{
|
||||
RL_HIST(atomic_load_event<T>) {this, T(), mo, false} RL_HIST_END();
|
||||
RL_ASSERT_IMPL(false, test_result_unitialized_access, "", info);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
bool spurious_failure = false;
|
||||
bool aba = false;
|
||||
|
||||
T const cmpv = cmp;
|
||||
T const current = value_;
|
||||
if (current == cmpv)
|
||||
{
|
||||
if (val(spurious_failures))
|
||||
{
|
||||
if (c.is_random_sched())
|
||||
{
|
||||
spurious_failure = (0 == c.rand(4, sched_type_cas_fail));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == already_failed_)
|
||||
{
|
||||
spurious_failure = 0 == c.rand(2, sched_type_cas_fail);
|
||||
if (spurious_failure)
|
||||
already_failed_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false == spurious_failure)
|
||||
{
|
||||
success = true;
|
||||
unsigned const index = (c.threadx_->*impl)(impl_, aba);
|
||||
value_ = xchg;
|
||||
last_index_ = index;
|
||||
history_[index] = xchg;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == success)
|
||||
{
|
||||
(c.threadx_->*failure_impl)(impl_);
|
||||
cmp = current;
|
||||
}
|
||||
|
||||
RL_HIST(atomic_cas_event<T>) {RL_INFO, this, current, cmpv, xchg, mo, success, spurious_failure, aba} RL_HIST_END();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template<typename Y, memory_order mo, unsigned (thread_info_base::*impl)(atomic_data* RL_RESTRICT data, bool&), rmw_type_e type>
|
||||
T rmw_impl(rmw_type_t<type>, Y op, debug_info_param info)
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
c.sched();
|
||||
sign_.check(info);
|
||||
|
||||
if (false == initialized_)
|
||||
{
|
||||
RL_HIST(atomic_load_event<T>) {this, T(), mo, false} RL_HIST_END();
|
||||
RL_ASSERT_IMPL(false, test_result_unitialized_access, "", info);
|
||||
}
|
||||
|
||||
bool aba;
|
||||
unsigned const index = (c.threadx_->*impl)(impl_, aba);
|
||||
|
||||
T const prev_value = value_;
|
||||
T const new_value = perform_rmw(rmw_type_t<type>(), prev_value, op);
|
||||
value_ = new_value;
|
||||
last_index_ = index;
|
||||
history_[index] = new_value;
|
||||
|
||||
typedef atomic_rmw_event<T, Y> atomic_rmw_event_t;
|
||||
RL_HIST(atomic_rmw_event_t) {RL_INFO, this, prev_value, op, new_value, mo, type} RL_HIST_END();
|
||||
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
RL_NOCOPY(generic_atomic);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic : public generic_atomic<T, false>
|
||||
{
|
||||
public:
|
||||
atomic()
|
||||
{
|
||||
}
|
||||
|
||||
/*explicit*/ atomic(T value)
|
||||
{
|
||||
this->store(value, mo_relaxed, $);
|
||||
}
|
||||
|
||||
atomic_proxy_const<T> operator () (debug_info_param info) const /*volatile*/
|
||||
{
|
||||
return atomic_proxy_const<T>(*this, info);
|
||||
}
|
||||
|
||||
atomic_proxy<T> operator () (debug_info_param info) /*volatile*/
|
||||
{
|
||||
return atomic_proxy<T>(*this, info);
|
||||
}
|
||||
|
||||
bool is_lock_free() const /*volatile*/
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class atomic_proxy<T>;
|
||||
friend class atomic_proxy_const<T>;
|
||||
|
||||
RL_NOCOPY(atomic);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
typedef atomic<bool> atomic_bool;
|
||||
typedef atomic<void*> atomic_address;
|
||||
|
||||
typedef atomic<char> atomic_char;
|
||||
typedef atomic<signed char> atomic_schar;
|
||||
typedef atomic<unsigned char> atomic_uchar;
|
||||
typedef atomic<short> atomic_short;
|
||||
typedef atomic<unsigned short> atomic_ushort;
|
||||
typedef atomic<int> atomic_int;
|
||||
typedef atomic<unsigned int> atomic_uint;
|
||||
typedef atomic<long> atomic_long;
|
||||
typedef atomic<unsigned long> atomic_ulong;
|
||||
typedef atomic<long long> atomic_llong;
|
||||
typedef atomic<unsigned long long> atomic_ullong;
|
||||
//typedef atomic<char16_t> atomic_char16_t;
|
||||
//typedef atomic<char32_t> atomic_char32_t;
|
||||
typedef atomic<wchar_t> atomic_wchar_t;
|
||||
|
||||
//typedef atomic<int_least8_t> atomic_int_least8_t;
|
||||
//typedef atomic<uint_least8_t> atomic_uint_least8_t;
|
||||
//typedef atomic<int_least16_t> atomic_int_least16_t;
|
||||
//typedef atomic<uint_least16_t> atomic_uint_least16_t;
|
||||
//typedef atomic<int_least32_t> atomic_int_least32_t;
|
||||
//typedef atomic<uint_least32_t> atomic_uint_least32_t;
|
||||
//typedef atomic<int_least64_t> atomic_int_least64_t;
|
||||
//typedef atomic<uint_least64_t> atomic_uint_least64_t;
|
||||
//typedef atomic<int_fast8_t> atomic_int_fast8_t;
|
||||
//typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
|
||||
//typedef atomic<int_fast16_t> atomic_int_fast16_t;
|
||||
//typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
|
||||
//typedef atomic<int_fast32_t> atomic_int_fast32_t;
|
||||
//typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
|
||||
//typedef atomic<int_fast64_t> atomic_int_fast64_t;
|
||||
//typedef atomic<uint_fast64_t> atomic_uint_fast64_t;
|
||||
typedef atomic<intptr_t> atomic_intptr_t;
|
||||
typedef atomic<uintptr_t> atomic_uintptr_t;
|
||||
typedef atomic<size_t> atomic_size_t;
|
||||
//typedef atomic<ssize_t> atomic_ssize_t;
|
||||
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
|
||||
//typedef atomic<intmax_t> atomic_intmax_t;
|
||||
//typedef atomic<uintmax_t> atomic_uintmax_t;
|
||||
|
||||
|
||||
|
||||
|
||||
template<thread_id_t thread_count>
|
||||
struct atomic_data_impl : atomic_data
|
||||
{
|
||||
typedef thread_info<thread_count> thread_info_t;
|
||||
|
||||
struct history_record
|
||||
{
|
||||
timestamp_t acq_rel_order_ [thread_count];
|
||||
timestamp_t first_seen_order_ [thread_count];
|
||||
|
||||
bool busy_;
|
||||
bool seq_cst_;
|
||||
thread_id_t thread_id_;
|
||||
timestamp_t acq_rel_timestamp_;
|
||||
};
|
||||
|
||||
static size_t const history_size = atomic_history_size;
|
||||
aligned<history_record> history_ [history_size];
|
||||
unsigned current_index_;
|
||||
waitset<thread_count> futex_ws_;
|
||||
sync_var<thread_count> futex_sync_;
|
||||
|
||||
atomic_data_impl()
|
||||
{
|
||||
current_index_ = 0;
|
||||
history_record& rec = history_[0];
|
||||
history_[atomic_history_size - 1].busy_ = false;
|
||||
|
||||
rec.busy_ = false;
|
||||
rec.seq_cst_ = false;
|
||||
rec.thread_id_ = (thread_id_t)-1;
|
||||
}
|
||||
|
||||
atomic_data_impl(thread_info_t& th)
|
||||
{
|
||||
current_index_ = 0;
|
||||
history_[atomic_history_size - 1].busy_ = false;
|
||||
|
||||
history_record& rec = history_[0];
|
||||
rec.busy_ = true;
|
||||
rec.seq_cst_ = false;
|
||||
rec.thread_id_ = th.index_;
|
||||
|
||||
th.own_acq_rel_order_ += 1;
|
||||
rec.acq_rel_timestamp_ = th.own_acq_rel_order_;
|
||||
|
||||
foreach<thread_count>(rec.acq_rel_order_, assign_zero);
|
||||
foreach<thread_count>(rec.first_seen_order_, assign<(timestamp_t)-1>);
|
||||
rec.first_seen_order_[th.index_] = th.own_acq_rel_order_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
148
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic_events.hpp
vendored
Normal file
148
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic_events.hpp
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_ATOMIC_EVENTS_HPP
|
||||
#define RL_ATOMIC_EVENTS_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "memory_order.hpp"
|
||||
#include "rmw.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
template<typename T> class atomic;
|
||||
template<typename T, bool strong_init> class generic_atomic;
|
||||
|
||||
template<typename T>
|
||||
struct atomic_add_type
|
||||
{
|
||||
typedef T type;
|
||||
typedef T output_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_add_type<T*>
|
||||
{
|
||||
typedef ptrdiff_t type;
|
||||
typedef void* output_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct atomic_cas_event
|
||||
{
|
||||
typedef typename atomic_add_type<T>::output_type type;
|
||||
|
||||
debug_info var_info_;
|
||||
void const* var_addr_;
|
||||
type cur_value_;
|
||||
type cmp_value_;
|
||||
type xchg_value_;
|
||||
memory_order mo_;
|
||||
bool success_;
|
||||
bool spurious_failure_;
|
||||
bool aba_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << "<" << std::hex << var_addr_ << std::dec << ">"
|
||||
<< " CAS "
|
||||
<< (success_ ? "succ " : "fail ")
|
||||
<< (spurious_failure_ ? "[SPURIOUSLY] " : "")
|
||||
<< (aba_ ? "[ABA] " : "")
|
||||
<< "orig=" << cur_value_
|
||||
<< ", cmp=" << cmp_value_
|
||||
<< ", xchg=" << xchg_value_
|
||||
<< ", order=" << format(mo_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct atomic_load_event
|
||||
{
|
||||
typedef typename atomic_add_type<T>::output_type type;
|
||||
|
||||
void const* var_addr_;
|
||||
type value_;
|
||||
memory_order mo_;
|
||||
bool not_current_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << "<" << std::hex << var_addr_ << std::dec << ">"
|
||||
<< " atomic load, value=" << value_
|
||||
<< (not_current_ ? " [NOT CURRENT]" : "")
|
||||
<< ", order=" << format(mo_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct atomic_store_event
|
||||
{
|
||||
typedef typename atomic_add_type<T>::output_type type;
|
||||
|
||||
void const* var_addr_;
|
||||
type prev_value_;
|
||||
type value_;
|
||||
memory_order mo_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << "<" << std::hex << var_addr_ << std::dec << ">"
|
||||
<< " atomic store, value=" << value_
|
||||
<< ", (prev value=" << prev_value_ << ")"
|
||||
<< ", order=" << format(mo_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T, typename Y>
|
||||
struct atomic_rmw_event
|
||||
{
|
||||
typedef typename atomic_add_type<T>::output_type type;
|
||||
|
||||
debug_info var_info_;
|
||||
void const* var_addr_;
|
||||
type prev_value_;
|
||||
Y op_value_;
|
||||
type new_value_;
|
||||
memory_order mo_;
|
||||
rmw_type_e type_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << "<" << std::hex << var_addr_ << std::dec << ">"
|
||||
<< " " << format(type_) << " "
|
||||
<< ", prev=" << prev_value_
|
||||
<< ", arg=" << op_value_
|
||||
<< ", new=" << new_value_
|
||||
<< ", order=" << format(mo_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
83
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic_fence.hpp
vendored
Normal file
83
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/atomic_fence.hpp
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_FENCE_HPP
|
||||
#define RL_FENCE_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "context.hpp"
|
||||
#include "memory_order.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
struct atomic_fence_event
|
||||
{
|
||||
memory_order mo_;
|
||||
bool is_thread_fence_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << (is_thread_fence_ ? "" : "compiler ")
|
||||
<< format(mo_) << " fence";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
RL_INLINE
|
||||
void atomic_thread_fence(memory_order mo, debug_info_param info)
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_VERIFY(false == c.invariant_executing);
|
||||
|
||||
switch (mo)
|
||||
{
|
||||
case mo_relaxed:
|
||||
RL_VERIFY(false);
|
||||
break;
|
||||
case mo_consume:
|
||||
case mo_acquire:
|
||||
c.atomic_thread_fence_acquire();
|
||||
break;
|
||||
case mo_release:
|
||||
c.atomic_thread_fence_release();
|
||||
break;
|
||||
case mo_acq_rel:
|
||||
c.atomic_thread_fence_acq_rel();
|
||||
break;
|
||||
case mo_seq_cst:
|
||||
c.atomic_thread_fence_seq_cst();
|
||||
break;
|
||||
}
|
||||
|
||||
RL_HIST(atomic_fence_event) {mo, true} RL_HIST_END();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
RL_INLINE
|
||||
void atomic_signal_fence(memory_order mo, debug_info_param info)
|
||||
{
|
||||
context& c = ctx();
|
||||
RL_HIST(atomic_fence_event) {mo, false} RL_HIST_END();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
57
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/backoff.hpp
vendored
Normal file
57
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/backoff.hpp
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_BACKOFF_HPP
|
||||
#define RL_BACKOFF_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "context_base.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
inline void yield(unsigned count, debug_info_param info)
|
||||
{
|
||||
ctx().yield(count, info);
|
||||
}
|
||||
|
||||
|
||||
template<unsigned factor_t, unsigned add_t>
|
||||
class backoff_t
|
||||
{
|
||||
public:
|
||||
backoff_t()
|
||||
: count_(1)
|
||||
{
|
||||
}
|
||||
|
||||
void yield(debug_info_param info)
|
||||
{
|
||||
rl::yield(count_, info);
|
||||
count_ = count_ * factor_t + add_t;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned count_;
|
||||
};
|
||||
|
||||
|
||||
typedef backoff_t<1, 0> backoff;
|
||||
typedef backoff_t<1, 1> linear_backoff;
|
||||
typedef backoff_t<2, 0> exp_backoff;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
144
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/base.hpp
vendored
Normal file
144
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/base.hpp
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_BASE_HPP
|
||||
#define RL_BASE_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "platform.hpp"
|
||||
|
||||
namespace rl
|
||||
{
|
||||
size_t const subsequent_timed_wait_limit = 4;
|
||||
}
|
||||
|
||||
#define RL_TEST
|
||||
|
||||
#ifdef RL_JAVA_MODE
|
||||
# define RL_GC
|
||||
# define RL_NO_MALLOC
|
||||
# define RL_JAVA_API
|
||||
# define RL_JAVA_MM
|
||||
#endif
|
||||
|
||||
#ifdef RL_CLI_MODE
|
||||
# define RL_GC
|
||||
# define RL_NO_MALLOC
|
||||
# define RL_CLI_API
|
||||
# define RL_CLI_MM
|
||||
#endif
|
||||
|
||||
#ifdef RL_POSIX_MODE
|
||||
# define RL_POSIX_API
|
||||
#endif
|
||||
|
||||
#ifdef RL_WIN_MODE
|
||||
# define RL_WIN_API
|
||||
#endif
|
||||
|
||||
#ifdef RL_CPP_MODE
|
||||
# define RL_CPP_API
|
||||
# define RL_CPP_MM
|
||||
#endif
|
||||
|
||||
#if defined(RL_JAVA_MM) || defined(RL_CLI_MM)
|
||||
# define RL_IMPROVED_SEQ_CST_FENCE
|
||||
# define RL_IMPROVED_SEQ_CST_RMW
|
||||
#endif
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
#define RL_NOCOPY(CLASS) \
|
||||
private: \
|
||||
CLASS(CLASS const&); \
|
||||
CLASS& operator = (CLASS const&);
|
||||
/**/
|
||||
|
||||
|
||||
template<typename T = void>
|
||||
class nocopy
|
||||
{
|
||||
nocopy(nocopy const&);
|
||||
nocopy& operator = (nocopy const&);
|
||||
|
||||
protected:
|
||||
nocopy() {}
|
||||
};
|
||||
|
||||
|
||||
template<size_t sz, size_t base = 4>
|
||||
struct align_pad
|
||||
{
|
||||
template<bool perfect, bool fit, int fake> struct helper
|
||||
{
|
||||
struct type { char pad [base - sz]; };
|
||||
};
|
||||
|
||||
template<int fake> struct helper<true, true, fake>
|
||||
{
|
||||
struct type {};
|
||||
};
|
||||
|
||||
template<bool perfect, int fake> struct helper<perfect, false, fake>
|
||||
{
|
||||
typedef typename align_pad<sz, base * 2>::type type;
|
||||
};
|
||||
|
||||
typedef typename helper<sz == base, sz <= base, 0>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct aligned : T, align_pad<sizeof(T)>::type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
T val(T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include "defs.hpp"
|
||||
|
||||
|
||||
#define RL_INFO ::rl::debug_info(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define $ RL_INFO
|
||||
|
||||
|
||||
#ifdef RL_DO_ASSERT
|
||||
# if RL_DO_ASSERT
|
||||
# define RL_DO_ASSERT_IMPL
|
||||
# endif
|
||||
#else
|
||||
# ifdef _DEBUG
|
||||
# define RL_DO_ASSERT_IMPL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define RL_INT3() __debugbreak(); abort()
|
||||
#else
|
||||
# define RL_INT3() abort()
|
||||
#endif
|
||||
|
||||
#ifdef RL_DO_ASSERT_IMPL
|
||||
# define RL_VERIFY(x) do { if (!((void)0, (x))) { \
|
||||
::rl::assert_failed(#x, $); RL_INT3(); } } while ((void)0, 0)
|
||||
#else
|
||||
# define RL_VERIFY(x) (void)0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
52
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli.hpp
vendored
Normal file
52
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli.hpp
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CLI_HPP
|
||||
#define RL_CLI_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "context_base.hpp"
|
||||
#include "atomic_fence.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
struct Thread
|
||||
{
|
||||
static void MemoryBarrier(debug_info_param info)
|
||||
{
|
||||
atomic_thread_fence(mo_seq_cst, info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T VolatileRead(generic_atomic<T, true> const& v, debug_info_param info)
|
||||
{
|
||||
return v.load(mo_acquire, info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void VolatileWrite(generic_atomic<T, true>& v, T x, debug_info_param info)
|
||||
{
|
||||
v.store(x, mo_release, info);
|
||||
}
|
||||
|
||||
static void SpinWait(int iterations, debug_info_param info)
|
||||
{
|
||||
ctx().yield(iterations, info);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CLI_INTERLOCKED_HPP
|
||||
#define RL_CLI_INTERLOCKED_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "atomic.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
struct Interlocked
|
||||
{
|
||||
template<typename T>
|
||||
static T Add(generic_atomic<T, true>& v, T x, debug_info_param info)
|
||||
{
|
||||
T result = v.rmw(rmw_type_t<rmw_type_add>(), x, mo_seq_cst, info) + x;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T CompareExchange(generic_atomic<T, true>& v, T xchg, T cmp, debug_info_param info)
|
||||
{
|
||||
v.compare_exchange(bool_t<false>(), cmp, xchg, mo_seq_cst, mo_seq_cst, info);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T Increment(generic_atomic<T, true>& v, debug_info_param info)
|
||||
{
|
||||
return Add(v, (T)1, info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T Decrement(generic_atomic<T, true>& v, debug_info_param info)
|
||||
{
|
||||
return Add(v, (T)-1, info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T Exchange(generic_atomic<T, true>& v, T x, debug_info_param info)
|
||||
{
|
||||
T result = v.rmw(rmw_type_t<rmw_type_swap>(), x, mo_seq_cst, info);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T Read(generic_atomic<T, true> const& v, debug_info_param info)
|
||||
{
|
||||
return v.load(mo_acquire, info);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
158
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli_var.hpp
vendored
Normal file
158
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli_var.hpp
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CLI_VAR_HPP
|
||||
#define RL_CLI_VAR_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "atomic.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
template<typename T> class nvar;
|
||||
|
||||
|
||||
template<typename T>
|
||||
class nvar_proxy
|
||||
{
|
||||
public:
|
||||
typedef typename atomic_add_type<T>::type add_type;
|
||||
template<typename Y> friend class nvar;
|
||||
|
||||
operator T () const
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
T operator = (T value)
|
||||
{
|
||||
store(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
T operator = (nvar_proxy const& r)
|
||||
{
|
||||
T const value = r.load();
|
||||
store(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T operator ++ (int)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator -- (int)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator ++ ()
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + 1);
|
||||
return tmp + 1;
|
||||
}
|
||||
|
||||
T operator -- ()
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - 1);
|
||||
return tmp - 1;
|
||||
}
|
||||
|
||||
T operator += (add_type value)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + value);
|
||||
return tmp + value;
|
||||
}
|
||||
|
||||
T operator -= (add_type value)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - value);
|
||||
return tmp - value;
|
||||
}
|
||||
|
||||
private:
|
||||
nvar<T>& var_;
|
||||
debug_info info_;
|
||||
|
||||
nvar_proxy(nvar<T>& var, debug_info_param info)
|
||||
: var_(var)
|
||||
, info_(info)
|
||||
{
|
||||
}
|
||||
|
||||
T load() const
|
||||
{
|
||||
return var_.load(mo_relaxed, info_);
|
||||
}
|
||||
|
||||
void store(T value)
|
||||
{
|
||||
var_.store(value, mo_relaxed, info_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class nvar : public generic_atomic<T, true>
|
||||
{
|
||||
public:
|
||||
typedef nvar_proxy<T> proxy_t;
|
||||
friend class nvar_proxy<T>;
|
||||
|
||||
nvar()
|
||||
{
|
||||
}
|
||||
|
||||
explicit nvar(T value)
|
||||
{
|
||||
this->store(value, mo_relaxed, $);
|
||||
}
|
||||
|
||||
nvar(nvar const& r)
|
||||
{
|
||||
T const value = r.load(mo_relaxed, $);
|
||||
this->store(value, mo_relaxed, $);
|
||||
}
|
||||
|
||||
nvar(proxy_t const& r)
|
||||
{
|
||||
T const value = r.load();
|
||||
this->store(value, mo_relaxed, r.info_);
|
||||
}
|
||||
|
||||
proxy_t operator () (debug_info_param info)
|
||||
{
|
||||
return proxy_t(*this, info);
|
||||
}
|
||||
|
||||
private:
|
||||
nvar& operator = (nvar const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
161
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli_volatile.hpp
vendored
Normal file
161
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/cli_volatile.hpp
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CLI_VOLATILE_HPP
|
||||
#define RL_CLI_VOLATILE_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "atomic.hpp"
|
||||
|
||||
|
||||
//!!! fix Java volatiles!
|
||||
// they must be modeled as seq_cst stores/loads
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
template<typename T> class nvolatile;
|
||||
|
||||
|
||||
template<typename T>
|
||||
class nvolatile_proxy
|
||||
{
|
||||
public:
|
||||
typedef typename atomic_add_type<T>::type add_type;
|
||||
template<typename Y> friend class nvolatile;
|
||||
|
||||
operator T () const
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
T operator = (T value)
|
||||
{
|
||||
store(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
T operator = (nvolatile_proxy const& r)
|
||||
{
|
||||
T const value = r.load();
|
||||
store(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T operator ++ (int)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator -- (int)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator ++ ()
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + 1);
|
||||
return tmp + 1;
|
||||
}
|
||||
|
||||
T operator -- ()
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - 1);
|
||||
return tmp - 1;
|
||||
}
|
||||
|
||||
T operator += (add_type value)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp + value);
|
||||
return tmp + value;
|
||||
}
|
||||
|
||||
T operator -= (add_type value)
|
||||
{
|
||||
T tmp = load();
|
||||
store(tmp - value);
|
||||
return tmp - value;
|
||||
}
|
||||
|
||||
private:
|
||||
nvolatile<T>& var_;
|
||||
debug_info info_;
|
||||
|
||||
nvolatile_proxy(nvolatile<T>& var, debug_info_param info)
|
||||
: var_(var)
|
||||
, info_(info)
|
||||
{
|
||||
}
|
||||
|
||||
T load() const
|
||||
{
|
||||
return var_.load(mo_acquire, info_);
|
||||
}
|
||||
|
||||
void store(T value)
|
||||
{
|
||||
var_.store(value, mo_release, info_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class nvolatile : public generic_atomic<T, true>
|
||||
{
|
||||
public:
|
||||
typedef nvolatile_proxy<T> proxy_t;
|
||||
friend class nvolatile_proxy<T>;
|
||||
|
||||
nvolatile()
|
||||
{
|
||||
}
|
||||
|
||||
explicit nvolatile(T value)
|
||||
{
|
||||
//??? whether here must be mo_relaxed or mo_release?
|
||||
this->store(value, mo_release, $);
|
||||
}
|
||||
|
||||
nvolatile(nvolatile const& r)
|
||||
{
|
||||
T const value = r.load(mo_acquire, $);
|
||||
//??? whether here must be mo_relaxed or mo_release?
|
||||
this->store(value, mo_release, $);
|
||||
}
|
||||
|
||||
nvolatile(proxy_t const& r)
|
||||
{
|
||||
T const value = r.var_.load(mo_acquire, r.info_);
|
||||
//??? whether here must be mo_relaxed or mo_release?
|
||||
this->store(value, mo_release, r.info_);
|
||||
}
|
||||
|
||||
proxy_t operator () (debug_info_param info)
|
||||
{
|
||||
return proxy_t(*this, info);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1291
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/context.hpp
vendored
Normal file
1291
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/context.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CONTEXT_ADDR_HASH_HPP
|
||||
#define RL_CONTEXT_ADDR_HASH_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
struct context_addr_hash_iface
|
||||
{
|
||||
virtual size_t get_addr_hash (void const* p) = 0;
|
||||
virtual ~context_addr_hash_iface () {} // to calm down g++
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename base_t, thread_id_t thread_count>
|
||||
class context_addr_hash_impl : protected base_t
|
||||
{
|
||||
public:
|
||||
context_addr_hash_impl(thread_id_t thread_count_param, test_params& params)
|
||||
: base_t(thread_count_param, params)
|
||||
{
|
||||
}
|
||||
|
||||
void iteration_begin()
|
||||
{
|
||||
base_t::iteration_begin();
|
||||
hash_map_.clear();
|
||||
hash_seq_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
struct entry
|
||||
{
|
||||
uintptr_t ptr_;
|
||||
size_t hash_;
|
||||
};
|
||||
typedef map<void const*, size_t>::type hash_map_t;
|
||||
hash_map_t hash_map_;
|
||||
size_t hash_seq_;
|
||||
|
||||
virtual size_t get_addr_hash (void const* p)
|
||||
{
|
||||
//!!! accept 'table size' to do 'hash % table_size'
|
||||
// will give more information for state exploration
|
||||
|
||||
hash_map_t::iterator iter (hash_map_.find(p));
|
||||
if (iter != hash_map_.end() && iter->first == p)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
//!!! distribute hashes more randomly, use rand()
|
||||
size_t hash = hash_seq_++;
|
||||
hash_map_.insert(std::make_pair(p, hash));
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
332
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/context_base.hpp
vendored
Normal file
332
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/tests/relacy/relacy/relacy/context_base.hpp
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CONTEXT_BASE_HPP
|
||||
#define RL_CONTEXT_BASE_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "history.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "test_result.hpp"
|
||||
#include "slab_allocator.hpp"
|
||||
#include "test_params.hpp"
|
||||
#include "random.hpp"
|
||||
#include "foreach.hpp"
|
||||
#include "thread_base.hpp"
|
||||
#include "context_addr_hash.hpp"
|
||||
|
||||
|
||||
#ifdef RL_DEBUGBREAK_ON_ASSERT
|
||||
# ifdef _MSC_VER
|
||||
# define RL_DEBUGBREAK_ON_ASSERT_IMPL {if (IsDebuggerPresent()) __debugbreak();}
|
||||
# else
|
||||
# define RL_DEBUGBREAK_ON_ASSERT_IMPL {__asm("int3");}
|
||||
# endif
|
||||
#else
|
||||
# define RL_DEBUGBREAK_ON_ASSERT_IMPL
|
||||
#endif
|
||||
|
||||
#ifdef RL_DEBUGBREAK_ON_FAILURE
|
||||
# ifdef _MSC_VER
|
||||
# define RL_DEBUGBREAK_ON_FAILURE_IMPL {if (IsDebuggerPresent()) __debugbreak();}
|
||||
# else
|
||||
# define RL_DEBUGBREAK_ON_FAILURE_IMPL {__asm("int3");}
|
||||
# endif
|
||||
#else
|
||||
# define RL_DEBUGBREAK_ON_FAILURE_IMPL
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
class thread_info_base;
|
||||
|
||||
struct atomic_data {};
|
||||
struct var_data
|
||||
{
|
||||
virtual void init(thread_info_base& th) = 0;
|
||||
virtual bool store(thread_info_base& th) = 0;
|
||||
virtual bool load(thread_info_base& th) = 0;
|
||||
virtual ~var_data() {} // just to calm down gcc
|
||||
};
|
||||
|
||||
struct generic_mutex_data;
|
||||
struct condvar_data;
|
||||
struct sema_data;
|
||||
struct event_data;
|
||||
|
||||
|
||||
struct user_msg_event
|
||||
{
|
||||
string msg_;
|
||||
|
||||
void output(std::ostream& s) const
|
||||
{
|
||||
s << msg_;
|
||||
}
|
||||
};
|
||||
|
||||
class context;
|
||||
|
||||
template<int fake = 0>
|
||||
struct context_holder
|
||||
{
|
||||
static context* instance_;
|
||||
|
||||
static long volatile ctx_seq;
|
||||
};
|
||||
|
||||
template<int fake>
|
||||
long volatile context_holder<fake>::ctx_seq = 0;
|
||||
|
||||
class context
|
||||
: public thread_local_context_iface
|
||||
, public context_addr_hash_iface
|
||||
, nocopy<>
|
||||
{
|
||||
public:
|
||||
static context& instance()
|
||||
{
|
||||
//!!! disabled for check in operator new RL_VERIFY(context_holder<>::instance_);
|
||||
return *context_holder<>::instance_;
|
||||
}
|
||||
|
||||
static bool is_instance()
|
||||
{
|
||||
return context_holder<>::instance_;
|
||||
}
|
||||
|
||||
virtual atomic_data* atomic_ctor(void* ctx) = 0;
|
||||
virtual void atomic_dtor(atomic_data* data) = 0;
|
||||
|
||||
virtual var_data* var_ctor() = 0;
|
||||
virtual void var_dtor(var_data* data) = 0;
|
||||
|
||||
virtual generic_mutex_data* mutex_ctor(bool is_rw, bool is_exclusive_recursive, bool is_shared_recursive, bool failing_try_lock) = 0;
|
||||
virtual void mutex_dtor(generic_mutex_data* m) = 0;
|
||||
|
||||
virtual condvar_data* condvar_ctor(bool allow_spurious_wakeups) = 0;
|
||||
virtual void condvar_dtor(condvar_data* cv) = 0;
|
||||
|
||||
virtual sema_data* sema_ctor(bool spurious_wakeups, unsigned initial_count, unsigned max_count) = 0;
|
||||
virtual void sema_dtor(sema_data* cv) = 0;
|
||||
|
||||
virtual event_data* event_ctor(bool manual_reset, bool initial_state) = 0;
|
||||
virtual void event_dtor(event_data* cv) = 0;
|
||||
|
||||
virtual void rl_global_fence() = 0;
|
||||
virtual void sched() = 0;
|
||||
virtual void yield(unsigned count, debug_info_param info) = 0;
|
||||
virtual void fail_test(char const* desc, test_result_e res, debug_info_param info) = 0;
|
||||
virtual void rl_until(char const* desc, debug_info_param info) = 0;
|
||||
|
||||
virtual void* alloc(size_t size, bool is_array, debug_info_param info) = 0;
|
||||
#ifdef RL_GC
|
||||
virtual void* alloc(size_t size, bool is_array, void(*dtor)(void*), debug_info_param info) = 0;
|
||||
#endif
|
||||
virtual void free(void* p, bool is_array, debug_info_param info) = 0;
|
||||
|
||||
virtual void* alloc(size_t size) = 0;
|
||||
virtual void free(void* p) = 0;
|
||||
virtual size_t prev_alloc_size() = 0;
|
||||
virtual void set_debug_info(debug_info_param info) = 0;
|
||||
|
||||
virtual void fiber_proc_impl(int thread_index) = 0;
|
||||
|
||||
virtual unpark_reason park_current_thread(bool is_timed,
|
||||
bool allow_spurious_wakeup,
|
||||
bool do_switch,
|
||||
debug_info_param info) = 0;
|
||||
virtual void unpark_thread(thread_id_t th, bool do_switch, debug_info_param info) = 0;
|
||||
virtual void switch_back(debug_info_param info) = 0;
|
||||
|
||||
virtual void atomic_thread_fence_acquire() = 0;
|
||||
virtual void atomic_thread_fence_release() = 0;
|
||||
virtual void atomic_thread_fence_acq_rel() = 0;
|
||||
virtual void atomic_thread_fence_seq_cst() = 0;
|
||||
|
||||
virtual unsigned rand(unsigned limit, sched_type t) = 0;
|
||||
|
||||
virtual win_waitable_object* create_thread(void*(*fn)(void*), void* ctx) = 0;
|
||||
|
||||
virtual unpark_reason wfmo_park(void** ws,
|
||||
win_waitable_object** wo,
|
||||
size_t count,
|
||||
bool wait_all,
|
||||
bool is_timed,
|
||||
debug_info_param info) = 0;
|
||||
|
||||
int get_errno();
|
||||
void set_errno(int value);
|
||||
|
||||
thread_info_base* threadx_;
|
||||
timestamp_t* seq_cst_fence_order_;
|
||||
|
||||
bool invariant_executing;
|
||||
|
||||
RL_INLINE bool collecting_history() const
|
||||
{
|
||||
return params_.collect_history && false == invariant_executing;
|
||||
}
|
||||
|
||||
template<typename event_t>
|
||||
void exec_log(debug_info_param info, event_t const& ev);
|
||||
|
||||
void exec_log_msg(debug_info_param info, char const* msg)
|
||||
{
|
||||
user_msg_event ev = {msg};
|
||||
exec_log(info, ev);
|
||||
}
|
||||
|
||||
bool is_random_sched() const
|
||||
{
|
||||
return is_random_sched_;
|
||||
}
|
||||
|
||||
unsigned get_ctx_seq() const
|
||||
{
|
||||
return ctx_seq_;
|
||||
}
|
||||
|
||||
void disable_preemption();
|
||||
void enable_preemption();
|
||||
|
||||
virtual thread_id_t get_thread_count() const = 0;
|
||||
|
||||
thread_id_t current_thread() const
|
||||
{
|
||||
return threadx_->index_;
|
||||
}
|
||||
|
||||
void iteration_begin()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
history_mgr history_;
|
||||
test_params& params_;
|
||||
unsigned disable_preemption_;
|
||||
int disable_alloc_;
|
||||
|
||||
context(thread_id_t thread_count, test_params& params)
|
||||
: history_(*params.output_stream, thread_count)
|
||||
, params_(params)
|
||||
, disable_alloc_(1)
|
||||
{
|
||||
RL_VERIFY(0 == context_holder<>::instance_);
|
||||
context_holder<>::instance_ = this;
|
||||
|
||||
is_random_sched_ = params_.search_type == random_scheduler_type;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
ctx_seq_ = _InterlockedExchangeAdd(&context_holder<>::ctx_seq, 1) + 1;
|
||||
#else
|
||||
ctx_seq_ = __sync_fetch_and_add(&context_holder<>::ctx_seq, 1) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~context()
|
||||
{
|
||||
RL_VERIFY(this == context_holder<>::instance_);
|
||||
context_holder<>::instance_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_random_sched_;
|
||||
unsigned ctx_seq_;
|
||||
};
|
||||
|
||||
|
||||
template<int fake>
|
||||
context* context_holder<fake>::instance_ = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
inline context& ctx()
|
||||
{
|
||||
return context::instance();
|
||||
}
|
||||
|
||||
inline bool is_ctx()
|
||||
{
|
||||
return context::is_instance();
|
||||
}
|
||||
|
||||
|
||||
inline int get_errno()
|
||||
{
|
||||
return ctx().get_errno();
|
||||
}
|
||||
|
||||
inline void set_errno(int value)
|
||||
{
|
||||
return ctx().set_errno(value);
|
||||
}
|
||||
|
||||
class preemption_disabler : nocopy<>
|
||||
{
|
||||
public:
|
||||
preemption_disabler(context& c)
|
||||
: c_(c)
|
||||
{
|
||||
c_.disable_preemption();
|
||||
}
|
||||
|
||||
~preemption_disabler()
|
||||
{
|
||||
c_.enable_preemption();
|
||||
}
|
||||
|
||||
private:
|
||||
context& c_;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#define RL_HIST_IMPL(C, INFO, TYPE) \
|
||||
do { \
|
||||
if (C.collecting_history()) { \
|
||||
rl::debug_info const& rl_info_c = INFO; \
|
||||
rl::context& rl_hist_c = C; \
|
||||
TYPE ev = \
|
||||
/**/
|
||||
|
||||
#define RL_HIST_END() \
|
||||
; \
|
||||
rl_hist_c.exec_log(rl_info_c, ev); \
|
||||
} \
|
||||
} while ((void)0, 0) \
|
||||
/**/
|
||||
|
||||
#define RL_HIST_CTX(TYPE) RL_HIST_IMPL((*this), info, TYPE)
|
||||
|
||||
#define RL_HIST(TYPE) RL_HIST_IMPL(c, info, TYPE)
|
||||
|
||||
#define RL_LOG(desc) rl::ctx().exec_log_msg(RL_INFO, desc)
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define RL_ASSERT_IMPL(x, res, str, info) do {if (!((void)0, (x))) {{RL_DEBUGBREAK_ON_ASSERT_IMPL} rl::ctx().fail_test(str, res, info);}} while ((void)0, 0)
|
||||
#else
|
||||
# define RL_ASSERT_IMPL(x, res, str, info) do {if (!((void)0, (x))) rl::ctx().fail_test(str, res, info);} while ((void)0, 0)
|
||||
#endif
|
||||
#define RL_ASSERT(x) RL_ASSERT_IMPL(x, rl::test_result_user_assert_failed, "assertion: " #x, RL_INFO)
|
||||
#define RL_UNTIL(x) do {if ((x)) rl::ctx().rl_until(#x, RL_INFO);} while ((void)0, 0)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CONTEXT_BASE_IMPL_HPP
|
||||
#define RL_CONTEXT_BASE_IMPL_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
/*
|
||||
inline void context::disable_history()
|
||||
{
|
||||
RL_VERIFY(threadx_);
|
||||
threadx_->disable_history_ += 1;
|
||||
}
|
||||
|
||||
inline void context::enable_history()
|
||||
{
|
||||
RL_VERIFY(threadx_);
|
||||
RL_VERIFY(threadx_->disable_history_);
|
||||
threadx_->disable_history_ -= 1;
|
||||
}
|
||||
*/
|
||||
|
||||
inline void context::disable_preemption()
|
||||
{
|
||||
disable_preemption_ += 1;
|
||||
}
|
||||
|
||||
inline void context::enable_preemption()
|
||||
{
|
||||
disable_preemption_ -= 1;
|
||||
}
|
||||
|
||||
inline int context::get_errno()
|
||||
{
|
||||
RL_VERIFY(threadx_);
|
||||
return threadx_->errno_;
|
||||
}
|
||||
|
||||
inline void context::set_errno(int value)
|
||||
{
|
||||
RL_VERIFY(threadx_);
|
||||
threadx_->errno_ = value;
|
||||
}
|
||||
|
||||
template<typename event_t>
|
||||
void context::exec_log(debug_info_param info, event_t const& ev)
|
||||
{
|
||||
RL_VERIFY(collecting_history());
|
||||
disable_alloc_ += 1;
|
||||
history_.exec_log(threadx_ ? threadx_->index_ : -1, info, ev, params_.output_history);
|
||||
disable_alloc_ -= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/* Relacy Race Detector
|
||||
* Copyright (c) 2008-2013, Dmitry S. Vyukov
|
||||
* All rights reserved.
|
||||
* This software is provided AS-IS with no warranty, either express or implied.
|
||||
* This software is distributed under a license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE in this distribution.
|
||||
*/
|
||||
|
||||
#ifndef RL_CONTEXT_BOUND_SCHEDULER_HPP
|
||||
#define RL_CONTEXT_BOUND_SCHEDULER_HPP
|
||||
#ifdef _MSC_VER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "base.hpp"
|
||||
#include "full_search_scheduler.hpp"
|
||||
#include "foreach.hpp"
|
||||
|
||||
|
||||
namespace rl
|
||||
{
|
||||
|
||||
|
||||
template<thread_id_t thread_count>
|
||||
struct context_bound_scheduler_thread_info : tree_search_scheduler_thread_info<thread_count>
|
||||
{
|
||||
unsigned sched_count_;
|
||||
unsigned forced_context_switch_count_;
|
||||
|
||||
void reset(test_params& params)
|
||||
{
|
||||
tree_search_scheduler_thread_info<thread_count>::reset(params);
|
||||
sched_count_ = 0;
|
||||
forced_context_switch_count_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<thread_id_t thread_count>
|
||||
class context_bound_scheduler
|
||||
: public tree_search_scheduler<context_bound_scheduler<thread_count>
|
||||
, context_bound_scheduler_thread_info<thread_count>, thread_count>
|
||||
{
|
||||
public:
|
||||
typedef tree_search_scheduler<context_bound_scheduler<thread_count>
|
||||
, context_bound_scheduler_thread_info<thread_count>, thread_count> base_t;
|
||||
typedef typename base_t::thread_info_t thread_info_t;
|
||||
typedef typename base_t::shared_context_t shared_context_t;
|
||||
|
||||
context_bound_scheduler(test_params& params, shared_context_t& ctx, thread_id_t dynamic_thread_count)
|
||||
: base_t(params, ctx, dynamic_thread_count)
|
||||
{
|
||||
}
|
||||
|
||||
thread_id_t iteration_begin_impl()
|
||||
{
|
||||
switches_remain_ = this->params_.context_bound;
|
||||
return base_t::iteration_begin_impl();
|
||||
}
|
||||
|
||||
bool can_switch(thread_info_t& t)
|
||||
{
|
||||
t.sched_count_ += 1;
|
||||
return switches_remain_ != 0;
|
||||
}
|
||||
|
||||
void on_switch(thread_info_t& t)
|
||||
{
|
||||
if (t.state_ == thread_state_running)
|
||||
{
|
||||
RL_VERIFY(switches_remain_);
|
||||
switches_remain_ -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.forced_context_switch_count_ += 1;
|
||||
}
|
||||
}
|
||||
|
||||
double iteration_count_approx()
|
||||
{
|
||||
return 1.0;
|
||||
/*
|
||||
iteration_t const P = thread_count;
|
||||
iteration_t const C0 = this->params_.context_bound;
|
||||
iteration_t total = 1;//factorial(P);// * power(P, P * C0);
|
||||
for (iteration_t i = 0; i != P - 1; ++i)
|
||||
total *= power(i + 1, C0 + 1);
|
||||
//if (C0)
|
||||
// total *= power(P - 1, P - 1);
|
||||
if (val(P) > 1)
|
||||
{
|
||||
for (iteration_t i = 0; i != P; ++i)
|
||||
{
|
||||
iteration_t const N = this->threads_[i].sched_count_;
|
||||
iteration_t const C = C0 + this->threads_[i].forced_context_switch_count_;
|
||||
//total *= (iteration_t)pow((double)(threads_[i].sched_count_ + 2) * (thread_count - 1), (int)(params_.context_bound + threads_[i].forced_context_switch_count_));
|
||||
total *= factorial(N, C) / factorial(C);
|
||||
//C$ += C + 1;
|
||||
//total *= (int)(params_.context_bound + threads_[i].forced_context_switch_count_));
|
||||
}
|
||||
//total *= factorial(C$);
|
||||
}
|
||||
else
|
||||
{
|
||||
total = 1;
|
||||
}
|
||||
//iteration_t total = (iteration_t)pow((double)sched_count / thread_count + 1, (int)(params_.context_bound * thread_count + forced_context_switch_mean_ + 0.5));
|
||||
//total *= thread_count;
|
||||
//total *= (iteration_t)pow((double)thread_count - 1, thread_count);
|
||||
for (size_t i = 0; i != this->stree_.size(); ++i)
|
||||
{
|
||||
if (this->stree_[i].type_ != sched_type_sched)
|
||||
{
|
||||
total *= this->stree_[i].count_;
|
||||
}
|
||||
}
|
||||
return (double)total;
|
||||
*/
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned switches_remain_;
|
||||
|
||||
template<typename T>
|
||||
static T factorial(T x, T i)
|
||||
{
|
||||
if (0 == i)
|
||||
return 1;
|
||||
T r = x;
|
||||
for (--i; i; --i)
|
||||
r *= x - i;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T factorial(T x)
|
||||
{
|
||||
if (0 == x)
|
||||
return 1;
|
||||
T r = x;
|
||||
for (T i = x - 1; i; --i)
|
||||
r *= i;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T power(T x, T y)
|
||||
{
|
||||
if (0 == y)
|
||||
return 1;
|
||||
T r = x;
|
||||
for (T i = y - 1; i; --i)
|
||||
r *= x;
|
||||
return r;
|
||||
}
|
||||
|
||||
RL_NOCOPY(context_bound_scheduler);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user