Commit a3c62f0c by Tobias Fuchs

containers_cpp: fixes in LlxScx, added unit test for LlxScx

parent a425b12e
......@@ -75,7 +75,7 @@ class FixedSizeList {
size_t capacity
/**< [IN] Capacity of the list */
);
/**
* Copy constructor.
*/
......
......@@ -30,6 +30,8 @@
#include <embb/base/thread.h>
#include <embb/base/atomic.h>
#include <embb/base/thread_specific_storage.h>
#include <embb/containers/object_pool.h>
#include <embb/containers/lock_free_tree_value_pool.h>
#include <embb/containers/internal/fixed_size_list.h>
namespace embb {
......@@ -42,7 +44,7 @@ namespace internal {
* SCX operation description. An SCX record contains all information
* required to allow any process to complete a pending SCX operation.
*/
template< class DataRecord >
template< typename DataRecord >
class ScxRecord {
private:
......@@ -66,11 +68,11 @@ class ScxRecord {
*/
ScxRecord()
: linked_data_records_(0),
finalize_data_records_(0)
finalize_data_records_(0),
new_value_(0),
old_value_(0),
scx_ops_(0),
state_(OperationState::Undefined),
state_(OperationState::Comitted),
all_frozen_(false) {
field_ = 0;
}
......@@ -84,7 +86,7 @@ class ScxRecord {
embb::base::Atomic<cas_t> * field,
cas_t new_value,
cas_t old_value,
embb::containers::internal::FixedSizeList<self_t *> * scx_ops,
embb::containers::internal::FixedSizeList<self_t> * scx_ops,
OperationState operation_state)
: linked_data_records_(&linked_data_records),
finalize_data_records_(&finalize_data_records),
......@@ -143,7 +145,7 @@ class ScxRecord {
* List of SCX operation descriptions associated with data records
* linked with this SCX operation.
*/
embb::containers::internal::FixedSizeList<self_t *> scx_ops_;
embb::containers::internal::FixedSizeList<self_t> * scx_ops_;
/**
* Current state of this SCX record.
......@@ -165,7 +167,7 @@ class ScxRecord {
* Wraps user-defined data with fields required for LLX/SCX algorithm.
* Mutable fields must each be contained in a single word.
*/
template< class UserData >
template< typename UserData >
class LlxScxRecord {
private:
......@@ -203,9 +205,12 @@ class LlxScxRecord {
* Assignment operator.
*/
LlxScxRecord & operator=(const LlxScxRecord & rhs) {
user_data_ = rhs.user_data_;
scx_op_.Store(rhs.scx_info_.Load());
marked_for_finalize_ = rhs.marked_for_finalize_;
if (this != &rhs) {
user_data_ = rhs.user_data_;
scx_op_.Store(rhs.scx_op_.Load());
marked_for_finalize_ = rhs.marked_for_finalize_;
}
return *this;
}
/**
......@@ -299,10 +304,13 @@ class LlxScxRecord {
* "Pragmatic Primitives for Non-blocking Data Structures"
* (Brown et al., 2013).
*
* \tparam MaxLinks Maximum number of active LL-dependencies per thread
* \tparam UserData Type containing mutable fields
* \tparam ValuePool Type containing mutable fields
*/
template< class UserData >
template<
typename UserData,
typename ValuePool = embb::containers::LockFreeTreeValuePool< bool, false >
>
class LlxScx {
private:
......@@ -335,8 +343,7 @@ class LlxScx {
DataRecord_t * const data_record,
/**< [IN] Pointer to data record to load */
DataRecord_t & data,
/**< [OUT] Atomic snapshot of \c NumMutableFields fields in data
record at given index */
/**< [OUT] Atomic snapshot of data record */
bool & finalized
/**< [OUT] Indicating whether requested fields have been finalized */
);
......@@ -393,6 +400,11 @@ class LlxScx {
size_t max_links_;
/**
* Maximum number of threads engaging in operations on this LLX/SCX instance.
*/
unsigned int max_threads_;
/**
* Shared table containing for each r in V, a copy of r's info
* value in this thread's local table of LLX results.
*
......@@ -402,23 +414,38 @@ class LlxScx {
* r_i in V -> *ScxRecord(thread_llx_results_[r_i].data_record.ScxInfo())
* }
*/
embb::containers::internal::FixedSizeList<ScxRecord_t> * info_fields_;
// embb::containers::internal::FixedSizeList<ScxRecord_t> * info_fields_;
/**
* Shared table containing for each r in V, a copy of r's info
* value in this thread's local table of LLX results.
*
* thread_id -> {
* r_1 in V -> *ScxRecord(thread_llx_results_[r_1].data_record.ScxInfo()),
* ...
* r_i in V -> *ScxRecord(thread_llx_results_[r_i].data_record.ScxInfo())
* }
*/
embb::containers::ObjectPool<
embb::containers::internal::FixedSizeList<ScxRecord_t>, ValuePool >
scx_record_list_pool_;
/**
* Thread-specific list of LLX results performed by the thread.
*/
embb::base::ThreadSpecificStorage<
embb::containers::internal::FixedSizeList<LlxResult> >
thread_llx_results_;
embb::containers::internal::FixedSizeList<LlxResult> *
thread_llx_results_;
/**
* Prevent default construction.
*/
LlxScx();
/**
* Prevent copy construction.
*/
LlxScx(const LlxScx &);
/**
* Prevent assignment.
*/
......
......@@ -37,14 +37,13 @@ using embb::containers::primitives::LlxScxRecord;
using embb::containers::primitives::LlxScx;
LlxScxTest::LlxScxTest() :
num_threads_(static_cast<int>
(partest::TestSuite::GetDefaultNumThreads())) {
num_threads_(
static_cast<int>(partest::TestSuite::GetDefaultNumThreads())) {
CreateUnit("SerialTest").Add(&LlxScxTest::SerialTest, this);
}
void LlxScxTest::SerialTest() {
typedef LlxScxTest::Node Node;
// Global:
LlxScx<Node> llxscx(3);
......@@ -72,7 +71,7 @@ void LlxScxTest::SerialTest() {
PT_ASSERT(llxscx.TryLoadLinked(&dr3, l3, finalized));
PT_ASSERT(!finalized);
FixedSizeList< LlxScxRecord<Node> * >
FixedSizeList< LlxScxRecord<Node> * >
linked_deps(3);
linked_deps.PushBack(&dr1);
linked_deps.PushBack(&dr2);
......@@ -92,6 +91,12 @@ void LlxScxTest::SerialTest() {
linked_deps, // V: dependencies, must be LL'd before
finalize_deps // R: Subsequence of V to be finalized
));
// Following LLX calls on finalized data records are
// expected to fail:
PT_ASSERT(!llxscx.TryLoadLinked(&dr2, l2, finalized));
PT_ASSERT(finalized);
PT_ASSERT(!llxscx.TryLoadLinked(&dr3, l3, finalized));
PT_ASSERT(finalized);
}
} // namespace test
......
......@@ -66,10 +66,19 @@ class LlxScxTest : public partest::TestCase {
next_.Store(next_node);
}
Node(const Node & other)
: value_(other.value_) {
next_.Store(other.next_.Load());
count_.Store(other.count_.Load());
}
Node & operator=(const Node & rhs) {
count_.Store(rhs.count_.Load());
next_.Store(rhs.next_.Load());
value_ = rhs.value_;
if (this != &rhs) {
count_.Store(rhs.count_.Load());
next_.Store(rhs.next_.Load());
value_ = rhs.value_;
}
return *this;
}
};
......
......@@ -40,6 +40,7 @@
#include "./stack_test.h"
#include "./hazard_pointer_test.h"
#include "./object_pool_test.h"
#include "./llx_scx_test.h"
#define COMMA ,
......@@ -55,6 +56,7 @@ using embb::containers::test::HazardPointerTest;
using embb::containers::test::QueueTest;
using embb::containers::test::StackTest;
using embb::containers::test::ObjectPoolTest;
using embb::containers::test::LlxScxTest;
PT_MAIN("Data Structures C++") {
unsigned int max_threads = static_cast<unsigned int>(
......@@ -70,6 +72,7 @@ PT_MAIN("Data Structures C++") {
PT_RUN(StackTest< LockFreeStack<int> >);
PT_RUN(ObjectPoolTest< LockFreeTreeValuePool<bool COMMA false > >);
PT_RUN(ObjectPoolTest< WaitFreeArrayValuePool<bool COMMA false> >);
PT_RUN(LlxScxTest);
PT_EXPECT(embb_get_bytes_allocated() == 0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment