Commit fb4b4604 by Tobias Fuchs

containers_cpp: added specialization of LLX/SCX for pointer types, added another simple unit test

parent 763326c7
...@@ -24,25 +24,19 @@ ...@@ -24,25 +24,19 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_INL_H_ #ifndef EMBB_CONTAINERS_INTERNAL_LLX_SCX_INL_H_
#define EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_INL_H_ #define EMBB_CONTAINERS_INTERNAL_LLX_SCX_INL_H_
#include <embb/containers/primitives/llx_scx.h> #include <embb/containers/internal/llx_scx.h>
#include <embb/base/thread.h> #include <embb/base/thread.h>
#include <embb/base/atomic.h> #include <embb/base/atomic.h>
#include <embb/base/memory_allocation.h> #include <embb/base/memory_allocation.h>
#include <vector> #include <vector>
#include <stdarg.h> #include <stdarg.h>
/**
* Implementation of the LX/STX primitive as presented in
* "Pragmatic Primitives for Non-blocking Data Structures"
* (Brown et al., 2013).
*/
namespace embb { namespace embb {
namespace containers { namespace containers {
namespace primitives { namespace internal {
template< typename UserData, typename ValuePool > template< typename UserData, typename ValuePool >
unsigned int LlxScx<UserData, ValuePool>::ThreadId() { unsigned int LlxScx<UserData, ValuePool>::ThreadId() {
...@@ -89,7 +83,7 @@ LlxScx<UserData, ValuePool>::~LlxScx() { ...@@ -89,7 +83,7 @@ LlxScx<UserData, ValuePool>::~LlxScx() {
template< typename UserData, typename ValuePool > template< typename UserData, typename ValuePool >
bool LlxScx<UserData, ValuePool>::TryLoadLinked( bool LlxScx<UserData, ValuePool>::TryLoadLinked(
DataRecord_t * const data_record, DataRecord_t * const data_record,
DataRecord_t & user_data, UserData & user_data,
bool & finalized) { bool & finalized) {
finalized = false; finalized = false;
unsigned int thread_id = ThreadId(); unsigned int thread_id = ThreadId();
...@@ -132,7 +126,7 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked( ...@@ -132,7 +126,7 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
template< typename UserData, typename ValuePool > template< typename UserData, typename ValuePool >
bool LlxScx<UserData, ValuePool>::TryLoadLinked( bool LlxScx<UserData, ValuePool>::TryLoadLinked(
DataRecord_t * const data_record, DataRecord_t * const data_record,
DataRecord_t & user_data) { UserData & user_data) {
bool finalized; bool finalized;
return TryLoadLinked(data_record, user_data, finalized); return TryLoadLinked(data_record, user_data, finalized);
} }
...@@ -144,6 +138,51 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional( ...@@ -144,6 +138,51 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
FieldType value, FieldType value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps, embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps) { embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps) {
embb::base::Atomic<cas_t> * cas_field =
reinterpret_cast<embb::base::Atomic<cas_t> *>(field);
cas_t cas_value = static_cast<cas_t>(value);
return TryStoreConditionalCAS(cas_field, cas_value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
template< typename FieldType >
bool LlxScx<UserData, ValuePool>::TryStoreConditional(
embb::base::Atomic<FieldType*> * field,
FieldType * value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps) {
embb::base::Atomic<cas_t> * cas_field =
reinterpret_cast<embb::base::Atomic<cas_t> *>(field);
cas_t cas_value = reinterpret_cast<cas_t>(value);
return TryStoreConditionalCAS(cas_field, cas_value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
template< typename FieldType >
bool LlxScx<UserData, ValuePool>::TryStoreConditional(
embb::base::Atomic<FieldType> * field,
FieldType value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps) {
embb::containers::internal::FixedSizeList<DataRecord_t *> finalize_deps(0);
return TryStoreConditional(field, value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
template< typename FieldType >
bool LlxScx<UserData, ValuePool>::TryStoreConditional(
embb::base::Atomic<FieldType*> * field,
FieldType * value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps) {
embb::containers::internal::FixedSizeList<DataRecord_t *> finalize_deps(0);
return TryStoreConditional(field, value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
bool LlxScx<UserData, ValuePool>::TryStoreConditionalCAS(
embb::base::Atomic<cas_t> * cas_field,
cas_t cas_value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps) {
typedef embb::containers::internal::FixedSizeList<DataRecord_t *> dr_list_t; typedef embb::containers::internal::FixedSizeList<DataRecord_t *> dr_list_t;
typedef embb::containers::internal::FixedSizeList<ScxRecord_t *> scx_op_list_t; typedef embb::containers::internal::FixedSizeList<ScxRecord_t *> scx_op_list_t;
// Preconditions: // Preconditions:
...@@ -184,11 +223,11 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional( ...@@ -184,11 +223,11 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
linked_deps, linked_deps,
finalize_deps, finalize_deps,
// target field: // target field:
reinterpret_cast<embb::base::Atomic<cas_t> *>(field), cas_field,
// new value: // new value:
reinterpret_cast<cas_t>(value), cas_value,
// old value: // old value:
reinterpret_cast<cas_t>(field->Load()), cas_field->Load(),
// linked SCX operations: // linked SCX operations:
info_fields, info_fields,
// initial operation state: // initial operation state:
...@@ -199,16 +238,6 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional( ...@@ -199,16 +238,6 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
} }
template< typename UserData, typename ValuePool > template< typename UserData, typename ValuePool >
template< typename FieldType >
bool LlxScx<UserData, ValuePool>::TryStoreConditional(
embb::base::Atomic<FieldType> * field,
FieldType value,
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps) {
embb::containers::internal::FixedSizeList<DataRecord_t *> finalize_deps(0);
return TryStoreConditional(field, value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
bool LlxScx<UserData, ValuePool>::TryValidateLink( bool LlxScx<UserData, ValuePool>::TryValidateLink(
const DataRecord_t & field) { const DataRecord_t & field) {
return true; // @TODO return true; // @TODO
...@@ -233,7 +262,7 @@ LlxScxRecord<UserData>::LlxScxRecord( ...@@ -233,7 +262,7 @@ LlxScxRecord<UserData>::LlxScxRecord(
// internal::ScxRecord // internal::ScxRecord
template< typename DataRecord > template< typename DataRecord >
bool internal::ScxRecord<DataRecord>::Help() { bool ScxRecord<DataRecord>::Help() {
// We ensure that an SCX S does not change a data record // We ensure that an SCX S does not change a data record
// while it is frozen for another SCX S'. Instead, S uses // while it is frozen for another SCX S'. Instead, S uses
// the information in the SCX record of S' to help S' // the information in the SCX record of S' to help S'
...@@ -291,12 +320,12 @@ bool internal::ScxRecord<DataRecord>::Help() { ...@@ -291,12 +320,12 @@ bool internal::ScxRecord<DataRecord>::Help() {
} }
template< typename UserData > template< typename UserData >
internal::ScxRecord< LlxScxRecord<UserData> > ScxRecord< LlxScxRecord<UserData> >
LlxScxRecord<UserData>::dummy_scx = LlxScxRecord<UserData>::dummy_scx =
internal::ScxRecord< LlxScxRecord<UserData> >(); ScxRecord< LlxScxRecord<UserData> >();
} // namespace primitives } // namespace internal
} // namespace containers } // namespace containers
} // namespace embb } // namespace embb
#endif // EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_INL_H_ #endif // EMBB_CONTAINERS_INTERNAL_LLX_SCX_INL_H_
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_H_ #ifndef EMBB_CONTAINERS_INTERNAL_LLX_SCX_H_
#define EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_H_ #define EMBB_CONTAINERS_INTERNAL_LLX_SCX_H_
#include <embb/base/thread.h> #include <embb/base/thread.h>
#include <embb/base/atomic.h> #include <embb/base/atomic.h>
...@@ -36,13 +36,177 @@ ...@@ -36,13 +36,177 @@
namespace embb { namespace embb {
namespace containers { namespace containers {
namespace primitives {
namespace internal { namespace internal {
#ifdef DOXYGEN
/**
* Wraps user-defined data with fields required for LLX/SCX algorithm.
* Mutable fields must each be contained in a single word.
*/
template< typename UserData >
class LlxScxRecord {
public:
/**
* Default constructor.
*/
LlxScxRecord();
/**
* Constructor. Creates an instance of \c DataRecord_t wrapping a user
* data object.
*/
LlxScxRecord(const UserData & user_data);
/**
* Copy constructor
*/
LlxScxRecord(const LlxScxRecord & other);
/**
* Assignment operator.
*/
LlxScxRecord & operator=(const LlxScxRecord & rhs);
/**
* Destructor.
*/
~LlxScxRecord();
/**
* Returns user data payload of this LLX/SCX record
*/
UserData & Data();
/**
* Allows pointer semantics, returns user data payload of this
* LLX/SCX record
*/
UserData * operator*();
/**
* Allows pointer semantics, returns user data payload of this
* LLX/SCX record
*/
UserData * operator->();
/**
* Whether this data record is marked for finalizing.
*/
bool IsMarkedForFinalize() const;
};
/**
* Multiword LL/SC
*
* Implementation of the LLX/STX primitive as presented in
* "Pragmatic Primitives for Non-blocking Data Structures"
* (Brown et al., 2013).
*
* \tparam UserData Type containing mutable fields
* \tparam ValuePool Type containing mutable fields
*/
template<
typename UserData,
typename ValuePool = embb::containers::LockFreeTreeValuePool< bool, false >
>
class LlxScx {
public:
/**
* Constructs a new instance of LlxScx.
*/
LlxScx(
size_t max_links
/**< [IN] Maximum number of links depending on a single SCX operation */
);
/**
* Destructor, frees memory.
*/
~LlxScx();
/**
* Tentatively performs an LLX (extended load-linked) operation on given
* LLX/SCX data record.
* Returns true and stores result in given reference variable on success,
* otherwise returns false.
*/
bool TryLoadLinked(
DataRecord_t * const data_record,
/**< [IN] Pointer to data record to load */
UserData & data,
/**< [OUT] Atomic snapshot of data record */
bool & finalized
/**< [OUT] Indicating whether requested fields have been finalized */
);
/**
* Tentatively performs an LLX (extended load-linked) operation on given
* LLX/SCX data record.
* Returns true and stores result in given reference variable on success,
* otherwise returns false.
*/
bool TryLoadLinked(
DataRecord_t * const data_record,
/**< [IN] Pointer to data record to load */
UserData & data
/**< [OUT] Atomic snapshot of data record */
);
/**
* Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record.
* Returns true if the given value has been stored successfully, otherwise
* false.
*/
template< typename FieldType >
bool TryStoreConditional(
embb::base::Atomic<FieldType> * field,
/**< [IN] Pointer to the field the value will be stored into */
FieldType value,
/**< [IN] Value to store */
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
/**< [IN] Data records linked to this store operation */
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps
/**< [IN] Data records to be finalized in this store operation */
);
/**
* Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record.
* Returns true if the given value has been stored successfully, otherwise
* false.
*/
template< typename FieldType >
bool TryStoreConditional(
embb::base::Atomic<FieldType> * field,
/**< [IN] Pointer to the field the value will be stored into */
FieldType value,
/**< [IN] Value to store */
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps
/**< [IN] Data records linked to this store operation */
);
/**
* Performs a VLX (extended validate link) operation on given LLX data
* record.
* Before calling this method, the given LLX/SCX record must have been
* linked via \c TryLoadLinked.
*
* \returns True if the calling thread's link obtained by its most recent
* invocation of SCX is still valid.
*/
bool TryValidateLink(
const DataRecord_t & data_record
/**< [IN] Linked data record to validate */
);
};
#else
/** /**
* SCX operation description. An SCX record contains all information * SCX operation description. An SCX record contains all information
* required to allow any process to complete a pending SCX operation. * required to allow any process to complete a pending SCX operation.
* This class is non-public.
*/ */
template< typename DataRecord > template< typename DataRecord >
class ScxRecord { class ScxRecord {
...@@ -163,8 +327,6 @@ class ScxRecord { ...@@ -163,8 +327,6 @@ class ScxRecord {
}; /* class ScxRecord */ }; /* class ScxRecord */
} // namespace internal
/** /**
* Wraps user-defined data with fields required for LLX/SCX algorithm. * Wraps user-defined data with fields required for LLX/SCX algorithm.
* Mutable fields must each be contained in a single word. * Mutable fields must each be contained in a single word.
...@@ -341,7 +503,7 @@ class LlxScx { ...@@ -341,7 +503,7 @@ class LlxScx {
bool TryLoadLinked( bool TryLoadLinked(
DataRecord_t * const data_record, DataRecord_t * const data_record,
/**< [IN] Pointer to data record to load */ /**< [IN] Pointer to data record to load */
DataRecord_t & data, UserData & data,
/**< [OUT] Atomic snapshot of data record */ /**< [OUT] Atomic snapshot of data record */
bool & finalized bool & finalized
/**< [OUT] Indicating whether requested fields have been finalized */ /**< [OUT] Indicating whether requested fields have been finalized */
...@@ -356,7 +518,7 @@ class LlxScx { ...@@ -356,7 +518,7 @@ class LlxScx {
bool TryLoadLinked( bool TryLoadLinked(
DataRecord_t * const data_record, DataRecord_t * const data_record,
/**< [IN] Pointer to data record to load */ /**< [IN] Pointer to data record to load */
DataRecord_t & data UserData & data
/**< [OUT] Atomic snapshot of data record */ /**< [OUT] Atomic snapshot of data record */
); );
...@@ -378,6 +540,18 @@ class LlxScx { ...@@ -378,6 +540,18 @@ class LlxScx {
/**< [IN] Data records to be finalized in this store operation */ /**< [IN] Data records to be finalized in this store operation */
); );
template< typename FieldType >
bool TryStoreConditional(
embb::base::Atomic<FieldType *> * field,
/**< [IN] Pointer to the field the value will be stored into */
FieldType * value,
/**< [IN] Value to store */
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
/**< [IN] Data records linked to this store operation */
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps
/**< [IN] Data records to be finalized in this store operation */
);
/** /**
* Tentatively performs a single-record Store-Conditional operation on * Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record. * given LLX/SCX data record.
...@@ -394,15 +568,24 @@ class LlxScx { ...@@ -394,15 +568,24 @@ class LlxScx {
/**< [IN] Data records linked to this store operation */ /**< [IN] Data records linked to this store operation */
); );
template< typename FieldType >
bool TryStoreConditional(
embb::base::Atomic<FieldType*> * field,
/**< [IN] Pointer to the field the value will be stored into */
FieldType * value,
/**< [IN] Value to store */
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps
/**< [IN] Data records linked to this store operation */
);
/** /**
* Performs a VLX (extended validate link) operation on given LLX data * Performs a VLX (extended validate link) operation on given LLX data
* record. * record.
* Returns true if the calling thread's link obtained by its most recent * Before calling this method, the given LLX/SCX record must have been
* invocation of SCX is still valid. * linked via \c TryLoadLinked.
* *
* Precondition: * \returns True if the calling thread's link obtained by its most recent
* - for each data record r in data_records, the active thread * invocation of SCX is still valid.
* has performed and r.LLX linked to this VLX.
*/ */
bool TryValidateLink( bool TryValidateLink(
const DataRecord_t & data_record const DataRecord_t & data_record
...@@ -433,13 +616,16 @@ class LlxScx { ...@@ -433,13 +616,16 @@ class LlxScx {
unsigned int max_threads_; unsigned int max_threads_;
/** /**
* Shared table containing for each r in V, a copy of r's info * Shared table containing for each r in V, a copy of r's info value in this
* value in this thread's local table of LLX results. * thread's local table of LLX results.
*/ */
embb::containers::ObjectPool< embb::containers::ObjectPool<
embb::containers::internal::FixedSizeList<ScxRecord_t *>, ValuePool > embb::containers::internal::FixedSizeList<ScxRecord_t *>, ValuePool >
scx_record_list_pool_; scx_record_list_pool_;
/**
* Pool for SCX records allocated in TryStoreConditional
*/
embb::containers::ObjectPool< ScxRecord_t, ValuePool > scx_record_pool_; embb::containers::ObjectPool< ScxRecord_t, ValuePool > scx_record_pool_;
/** /**
...@@ -463,12 +649,37 @@ class LlxScx { ...@@ -463,12 +649,37 @@ class LlxScx {
*/ */
LlxScx & operator=(const LlxScx &); LlxScx & operator=(const LlxScx &);
/**
* Actual implementation of StoreConditional operating on unified fields/values
* of type cas_t.
*/
bool TryStoreConditionalCAS(
embb::base::Atomic<cas_t> * cas_field,
/**< [IN] Pointer to the field the value will be stored into */
cas_t cas_value,
/**< [IN] Value to store */
embb::containers::internal::FixedSizeList<DataRecord_t *> & linked_deps,
/**< [IN] Data records linked to this store operation */
embb::containers::internal::FixedSizeList<DataRecord_t *> & finalize_deps
/**< [IN] Data records to be finalized in this store operation */
);
template < typename FieldType >
cas_t ToCASValue(FieldType value) {
return static_cast<cas_t>(value);
}
template < typename FieldType >
cas_t ToCASValue(FieldType * value) {
return reinterpret_cast<cas_t>(value);
}
}; };
#endif // DOXYGEN
} // namespace primitives } // namespace primitives
} // namespace containers } // namespace containers
} // namespace embb } // namespace embb
#include <embb/containers/internal/primitives/llx_scx-inl.h> #include <embb/containers/internal/llx_scx-inl.h>
#endif // EMBB_CONTAINERS_PRIMITIVES_LLX_SCX_H_ #endif // EMBB_CONTAINERS_INTERNAL_LLX_SCX_H_
\ No newline at end of file \ No newline at end of file
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
#include <llx_scx_test.h> #include <llx_scx_test.h>
#include <embb/containers/internal/fixed_size_list.h> #include <embb/containers/internal/fixed_size_list.h>
#include <embb/containers/primitives/llx_scx.h> #include <embb/containers/internal/llx_scx.h>
namespace embb { namespace embb {
namespace containers { namespace containers {
namespace test { namespace test {
using embb::containers::internal::FixedSizeList; using embb::containers::internal::FixedSizeList;
using embb::containers::primitives::LlxScxRecord; using embb::containers::internal::LlxScxRecord;
using embb::containers::primitives::LlxScx; using embb::containers::internal::LlxScx;
LlxScxTest::LlxScxTest() : LlxScxTest::LlxScxTest() :
num_threads_( num_threads_(
...@@ -42,7 +42,8 @@ LlxScxTest::LlxScxTest() : ...@@ -42,7 +42,8 @@ LlxScxTest::LlxScxTest() :
llxscx_(3), llxscx_(3),
tail(0, '-'), tail(0, '-'),
head(0, '-', Node::node_ptr_t(&tail)) { head(0, '-', Node::node_ptr_t(&tail)) {
CreateUnit("SerialTest").Add(&LlxScxTest::SerialTest, this); CreateUnit("SerialArrayTest").Add(&LlxScxTest::SerialArrayTest, this);
CreateUnit("SerialListTest").Add(&LlxScxTest::SerialListTest, this);
CreateUnit("ParallelTest").Add(&LlxScxTest::ParallelTest, this); CreateUnit("ParallelTest").Add(&LlxScxTest::ParallelTest, this);
} }
...@@ -57,7 +58,39 @@ void LlxScxTest::ParallelTest() { ...@@ -57,7 +58,39 @@ void LlxScxTest::ParallelTest() {
// Threads try to append n nodes to a linked list in parallel // Threads try to append n nodes to a linked list in parallel
} }
void LlxScxTest::SerialTest() { void LlxScxTest::SerialArrayTest() {
typedef int Payload;
typedef embb::base::Atomic<size_t> AtomicField;
// LLX/SCX with maximum of 3 active load-links in every thread:
LlxScx<Payload> llxscx(3);
// Atomic<size_t> not assignable, TryStoreConditional requires
// a specialization for atomics that uses a.Store(b.Load()).
AtomicField field(23);
// Initialize
LlxScxRecord< Payload > * my_list =
new LlxScxRecord<Payload>[10];
for (int i = 0; i != 10; ++i) {
my_list[i] = i;
}
Payload l1, l2;
PT_ASSERT(llxscx.TryLoadLinked(&my_list[0], l1));
PT_ASSERT(llxscx.TryLoadLinked(&my_list[5], l2));
FixedSizeList< LlxScxRecord<Payload> * >
links(2);
links.PushBack(&my_list[0]);
links.PushBack(&my_list[5]);
// Try to store new value depending on links:
size_t a = 42;
PT_ASSERT(llxscx.TryStoreConditional(&field, a, links));
// New value should have been changed successfully:
PT_ASSERT_EQ(field.Load(), a);
}
void LlxScxTest::SerialListTest() {
typedef LlxScxTest::Node Node; typedef LlxScxTest::Node Node;
// Global: // Global:
LlxScx<Node> llxscx(3); LlxScx<Node> llxscx(3);
...@@ -77,17 +110,17 @@ void LlxScxTest::SerialTest() { ...@@ -77,17 +110,17 @@ void LlxScxTest::SerialTest() {
dr2->next_.Store(&dr3); dr2->next_.Store(&dr3);
// Thread-local: // Thread-local:
LlxScxRecord<Node> l1, l2, l3; Node l1, l2, l3;
bool finalized; bool finalized;
PT_ASSERT(llxscx.TryLoadLinked(&dr1, l1, finalized)); PT_ASSERT(llxscx.TryLoadLinked(&dr1, l1, finalized));
PT_ASSERT(!finalized); PT_ASSERT(!finalized);
PT_ASSERT_EQ(l1->value_, dr1->value_); PT_ASSERT_EQ(l1.value_, dr1->value_);
PT_ASSERT(llxscx.TryLoadLinked(&dr2, l2, finalized)); PT_ASSERT(llxscx.TryLoadLinked(&dr2, l2, finalized));
PT_ASSERT(!finalized); PT_ASSERT(!finalized);
PT_ASSERT_EQ(l2->value_, dr2->value_); PT_ASSERT_EQ(l2.value_, dr2->value_);
PT_ASSERT(llxscx.TryLoadLinked(&dr3, l3, finalized)); PT_ASSERT(llxscx.TryLoadLinked(&dr3, l3, finalized));
PT_ASSERT(!finalized); PT_ASSERT(!finalized);
PT_ASSERT_EQ(l3->value_, dr3->value_); PT_ASSERT_EQ(l3.value_, dr3->value_);
FixedSizeList< LlxScxRecord<Node> * > FixedSizeList< LlxScxRecord<Node> * >
linked_deps(3); linked_deps(3);
...@@ -103,7 +136,7 @@ void LlxScxTest::SerialTest() { ...@@ -103,7 +136,7 @@ void LlxScxTest::SerialTest() {
LlxScxRecord<Node> new_node(n3); LlxScxRecord<Node> new_node(n3);
PT_ASSERT( PT_ASSERT(
llxscx.TryStoreConditional<LlxScxRecord<Node> *>( llxscx.TryStoreConditional(
&n2.next_, // fld: field to update &n2.next_, // fld: field to update
&new_node, // new value &new_node, // new value
linked_deps, // V: dependencies, must be LL'd before linked_deps, // V: dependencies, must be LL'd before
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define CONTAINERS_CPP_TEST_LLX_SCX_TEST_H_ #define CONTAINERS_CPP_TEST_LLX_SCX_TEST_H_
#include <partest/partest.h> #include <partest/partest.h>
#include <embb/containers/primitives/llx_scx.h> #include <embb/containers/internal/llx_scx.h>
namespace embb { namespace embb {
namespace containers { namespace containers {
...@@ -39,10 +39,10 @@ class LlxScxTest : public partest::TestCase { ...@@ -39,10 +39,10 @@ class LlxScxTest : public partest::TestCase {
private: private:
class Node { class Node {
public: public:
typedef primitives::LlxScxRecord<Node> * node_ptr_t; typedef internal::LlxScxRecord<Node> * node_ptr_t;
public: public:
embb::base::Atomic<primitives::LlxScxRecord<Node> *> next_; embb::base::Atomic<internal::LlxScxRecord<Node> *> next_;
embb::base::Atomic<int> count_; embb::base::Atomic<int> count_;
char value_; char value_;
...@@ -88,11 +88,12 @@ class LlxScxTest : public partest::TestCase { ...@@ -88,11 +88,12 @@ class LlxScxTest : public partest::TestCase {
LlxScxTest(); LlxScxTest();
private: private:
void SerialTest(); void SerialArrayTest();
void SerialListTest();
void ParallelTest(); void ParallelTest();
int num_threads_; int num_threads_;
primitives::LlxScx<Node> llxscx_; internal::LlxScx<Node> llxscx_;
Node tail; Node tail;
Node head; Node head;
}; };
......
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