Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
FORMUS3IC_LAS3
/
embb
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
a3c62f0c
authored
Mar 25, 2015
by
Tobias Fuchs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
containers_cpp: fixes in LlxScx, added unit test for LlxScx
parent
a425b12e
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
116 additions
and
158 deletions
+116
-158
containers_cpp/include/embb/containers/internal/fixed_size_list.h
+1
-1
containers_cpp/include/embb/containers/internal/primitives/llx_scx-inl.h
+47
-133
containers_cpp/include/embb/containers/primitives/llx_scx.h
+44
-17
containers_cpp/test/llx_scx_test.cc
+9
-4
containers_cpp/test/llx_scx_test.h
+12
-3
containers_cpp/test/main.cc
+3
-0
No files found.
containers_cpp/include/embb/containers/internal/fixed_size_list.h
View file @
a3c62f0c
...
@@ -75,7 +75,7 @@ class FixedSizeList {
...
@@ -75,7 +75,7 @@ class FixedSizeList {
size_t
capacity
size_t
capacity
/**< [IN] Capacity of the list */
/**< [IN] Capacity of the list */
);
);
/**
/**
* Copy constructor.
* Copy constructor.
*/
*/
...
...
containers_cpp/include/embb/containers/internal/primitives/llx_scx-inl.h
View file @
a3c62f0c
...
@@ -44,99 +44,8 @@ namespace embb {
...
@@ -44,99 +44,8 @@ namespace embb {
namespace
containers
{
namespace
containers
{
namespace
primitives
{
namespace
primitives
{
namespace
internal
{
template
<
typename
UserData
,
typename
ValuePool
>
unsigned
int
LlxScx
<
UserData
,
ValuePool
>::
ThreadId
()
{
#if 0
/**
* RAII-style implementation of a simplified hazard
* pointer scheme. SmartHazardPointer instances should
* reside only on the stack, never the heap, and T*
* values should reside only in the heap. A NodePtr can
* be automatically converted to a Node*, but an explicit
* constructor is needed to go the other way.
*
* Example:
* SmartHazardPointer<Node> shp = SmartHazardPointer(
* nodePool?>allocate());
* // assign via default copy constructor:
* *shp = Node(...);
*/
template< typename T >
class SmartHazardPointer {
public:
SmartHazardPointer(T ** node) {
while (true) {
ptr = *node;
table_->add(ptr);
// Full fence:
embb_atomic_memory_barrier();
T * reread = *node;
// @TODO: Prove practical wait-freedom
if (read == reread) {
return;
}
}
}
SmartHazardPointer(T * node) {
ptr = node;
}
/**
* Dereference operator.
*/
T * operator->() {
return ptr;
}
/**
* Dereference lvalue.
*/
T & operator*() {
return *ptr;
}
/**
* Equality test with regular pointer
*/
bool operator==(T * const other) {
return ptr == other;
}
/**
* Equality test with another SmartHazardPointer
*/
bool operator==(const SmartHazardPointer & other) {
return this->ptr == other->ptr;
}
/**
* Destructor, retires hazard pointer.
*/
~SmartHazardPointer() {
table_->remove(ptr);
}
/**
* Conversion to regular pointer.
*/
operator T*() {
return ptr;
}
private:
static HazardPointerTable * table_;
T * ptr;
};
#endif
}
// namespace internal
template
<
class
UserData
>
unsigned
int
LlxScx
<
UserData
>::
ThreadId
()
{
unsigned
int
thread_index
;
unsigned
int
thread_index
;
int
return_val
=
embb_internal_thread_index
(
&
thread_index
);
int
return_val
=
embb_internal_thread_index
(
&
thread_index
);
if
(
return_val
!=
EMBB_SUCCESS
)
if
(
return_val
!=
EMBB_SUCCESS
)
...
@@ -144,34 +53,33 @@ unsigned int LlxScx<UserData>::ThreadId() {
...
@@ -144,34 +53,33 @@ unsigned int LlxScx<UserData>::ThreadId() {
return
thread_index
;
return
thread_index
;
}
}
template
<
class
UserData
>
template
<
typename
UserData
,
typename
ValuePool
>
LlxScx
<
UserData
>::
LlxScx
(
size_t
max_links
)
LlxScx
<
UserData
,
ValuePool
>::
LlxScx
(
size_t
max_links
)
:
max_links_
(
max_links
)
{
:
max_links_
(
max_links
),
max_threads_
(
embb
::
base
::
Thread
::
GetThreadsMaxCount
()),
scx_record_list_pool_
(
max_threads_
)
{
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
llx_result_list_t
;
llx_result_list_t
;
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
ScxRecord_t
>
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
ScxRecord_t
>
scx_record_list_t
;
scx_record_list_t
;
unsigned
int
num_threads
=
embb
::
base
::
Thread
::
GetThreadsMaxCount
();
// Allocate a list of LLX results for every thread:
// Table in shared memory containing for each r in TryStoreConditional's
thread_llx_results_
=
static_cast
<
llx_result_list_t
*>
(
// dependent links, a copy of r's info value in this threads local table
// of LLX results.
scx_record_list_t
empty_scx_list
(
3
);
info_fields_
=
static_cast
<
scx_record_list_t
*>
(
embb
::
base
::
Allocation
::
AllocateCacheAligned
(
embb
::
base
::
Allocation
::
AllocateCacheAligned
(
num_threads
*
sizeof
(
empty_scx_lis
t
)));
max_threads_
*
sizeof
(
llx_result_list_
t
)));
}
}
template
<
class
UserData
>
template
<
typename
UserData
,
typename
ValuePool
>
LlxScx
<
UserData
>::~
LlxScx
()
{
LlxScx
<
UserData
,
ValuePool
>::~
LlxScx
()
{
embb
::
base
::
Allocation
::
FreeAligned
(
info_field
s_
);
embb
::
base
::
Allocation
::
FreeAligned
(
thread_llx_result
s_
);
}
}
template
<
class
UserData
>
template
<
typename
UserData
,
typename
ValuePool
>
bool
LlxScx
<
UserData
>::
TryLoadLinked
(
bool
LlxScx
<
UserData
,
ValuePool
>::
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
DataRecord_t
*
const
data_record
,
DataRecord_t
&
user_data
,
DataRecord_t
&
user_data
,
bool
&
finalized
)
{
bool
&
finalized
)
{
finalized
=
false
;
finalized
=
false
;
unsigned
int
thread_id
=
ThreadId
();
// Order of initialization matters:
// Order of initialization matters:
bool
marked_1
=
data_record
->
IsMarkedForFinalize
();
bool
marked_1
=
data_record
->
IsMarkedForFinalize
();
ScxRecord_t
*
curr_scx
=
data_record
->
ScxInfo
().
Load
();
ScxRecord_t
*
curr_scx
=
data_record
->
ScxInfo
().
Load
();
...
@@ -188,7 +96,7 @@ bool LlxScx<UserData>::TryLoadLinked(
...
@@ -188,7 +96,7 @@ bool LlxScx<UserData>::TryLoadLinked(
llx_result
.
data_record
=
data_record
;
llx_result
.
data_record
=
data_record
;
llx_result
.
scx_record
=
curr_scx
;
llx_result
.
scx_record
=
curr_scx
;
llx_result
.
user_data
=
user_data_local
;
llx_result
.
user_data
=
user_data_local
;
thread_llx_results_
.
Get
()
.
PushBack
(
llx_result
);
thread_llx_results_
[
thread_id
]
.
PushBack
(
llx_result
);
// Set return value:
// Set return value:
user_data
=
user_data_local
;
user_data
=
user_data_local
;
return
true
;
return
true
;
...
@@ -210,15 +118,15 @@ bool LlxScx<UserData>::TryLoadLinked(
...
@@ -210,15 +118,15 @@ bool LlxScx<UserData>::TryLoadLinked(
return
false
;
return
false
;
}
}
template
<
class
UserData
>
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
FieldType
>
template
<
typename
FieldType
>
bool
LlxScx
<
UserData
>::
TryStoreConditional
(
bool
LlxScx
<
UserData
,
ValuePool
>::
TryStoreConditional
(
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
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
)
{
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 *>
op_list_t;
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
ScxRecord_t
>
scx_
op_list_t
;
// Preconditions:
// Preconditions:
// 1. For each r in linked_deps, this thread has performed an invocation
// 1. For each r in linked_deps, this thread has performed an invocation
// I_r of LLX(r) linked to this SCX.
// I_r of LLX(r) linked to this SCX.
...
@@ -228,17 +136,18 @@ bool LlxScx<UserData>::TryStoreConditional(
...
@@ -228,17 +136,18 @@ bool LlxScx<UserData>::TryStoreConditional(
unsigned
int
thread_id
=
ThreadId
();
unsigned
int
thread_id
=
ThreadId
();
// Let info_fields be a table in shared memory containing for each r in V,
// Let info_fields be a table in shared memory containing for each r in V,
// a copy of r's info value in this threads local table of LLX results:
// a copy of r's info value in this threads local table of LLX results:
info_fields_
[
thread_id
].
clear
(
);
scx_op_list_t
*
info_fields
=
scx_record_list_pool_
.
Allocate
(
max_links_
);
dr_list_t
::
const_iterator
it
;
dr_list_t
::
const_iterator
it
;
dr_list_t
::
const_iterator
end
;
dr_list_t
::
const_iterator
end
;
end
=
linked_deps
.
end
();
end
=
linked_deps
.
end
();
// for each r in
V
...
// for each r in
linked_deps
...
for
(
it
=
linked_deps
.
begin
();
it
!=
end
;
++
it
)
{
for
(
it
=
linked_deps
.
begin
();
it
!=
end
;
++
it
)
{
// Find LLX result of r in thread-local table of LLX results:
// Find LLX result of r in thread-local table of LLX results:
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
llx_result_list
;
llx_result_list
;
llx_result_list
::
iterator
l_it
=
thread_llx_results_
.
Get
().
begin
();
llx_result_list
::
iterator
l_it
=
thread_llx_results_
[
thread_id
].
begin
();
llx_result_list
::
iterator
l_end
=
thread_llx_results_
.
Get
().
end
();
llx_result_list
::
iterator
l_end
=
thread_llx_results_
[
thread_id
].
end
();
// Find LLX result of r in thread-local LLX results:
for
(;
l_it
!=
l_end
&&
l_it
->
data_record
!=
*
it
;
++
l_it
);
for
(;
l_it
!=
l_end
&&
l_it
->
data_record
!=
*
it
;
++
l_it
);
if
(
l_it
==
l_end
)
{
if
(
l_it
==
l_end
)
{
// Missing LLX result for given linked data record, user did not
// Missing LLX result for given linked data record, user did not
...
@@ -246,9 +155,9 @@ bool LlxScx<UserData>::TryStoreConditional(
...
@@ -246,9 +155,9 @@ bool LlxScx<UserData>::TryStoreConditional(
EMBB_THROW
(
embb
::
base
::
ErrorException
,
EMBB_THROW
(
embb
::
base
::
ErrorException
,
"Missing preceding LLX on a data record used for SCX"
);
"Missing preceding LLX on a data record used for SCX"
);
}
}
//
... c
opy of r's info value in this threads local table of LLX results
//
C
opy of r's info value in this threads local table of LLX results
ScxRecord_t
scx_op
(
*
(
l_it
->
data_record
->
ScxInfo
().
Load
()));
ScxRecord_t
scx_op
(
*
(
l_it
->
data_record
->
ScxInfo
().
Load
()));
info_fields
_
[
thread_id
].
PushBack
(
scx_op
);
info_fields
->
PushBack
(
scx_op
);
}
}
// Announce SCX operation. Lists linked_deps and finalize_dep are
// Announce SCX operation. Lists linked_deps and finalize_dep are
// guaranteed to remain on the stack until this announced operation
// guaranteed to remain on the stack until this announced operation
...
@@ -263,27 +172,27 @@ bool LlxScx<UserData>::TryStoreConditional(
...
@@ -263,27 +172,27 @@ bool LlxScx<UserData>::TryStoreConditional(
// old value:
// old value:
reinterpret_cast
<
cas_t
>
(
field
->
Load
()),
reinterpret_cast
<
cas_t
>
(
field
->
Load
()),
// linked SCX operations:
// linked SCX operations:
&
info_fields_
[
thread_id
]
,
info_fields
,
// initial operation state:
// initial operation state:
OperationState
::
InProgress
);
OperationState
::
InProgress
);
return
scx
.
Help
();
return
scx
.
Help
();
}
}
template
<
class
UserData
>
template
<
typename
UserData
,
typename
ValuePool
>
bool
LlxScx
<
UserData
>::
TryValidateLink
(
bool
LlxScx
<
UserData
,
ValuePool
>::
TryValidateLink
(
const
DataRecord_t
&
field
)
{
const
DataRecord_t
&
field
)
{
return
true
;
// @TODO
return
true
;
// @TODO
}
}
// LlxScxRecord
// LlxScxRecord
template
<
class
UserData
>
template
<
typename
UserData
>
LlxScxRecord
<
UserData
>::
LlxScxRecord
()
LlxScxRecord
<
UserData
>::
LlxScxRecord
()
:
marked_for_finalize_
(
false
)
{
:
marked_for_finalize_
(
false
)
{
scx_op_
.
Store
(
&
dummy_scx
);
scx_op_
.
Store
(
&
dummy_scx
);
}
}
template
<
class
UserData
>
template
<
typename
UserData
>
LlxScxRecord
<
UserData
>::
LlxScxRecord
(
LlxScxRecord
<
UserData
>::
LlxScxRecord
(
const
UserData
&
user_data
)
const
UserData
&
user_data
)
:
user_data_
(
user_data
),
:
user_data_
(
user_data
),
...
@@ -293,24 +202,26 @@ LlxScxRecord<UserData>::LlxScxRecord(
...
@@ -293,24 +202,26 @@ LlxScxRecord<UserData>::LlxScxRecord(
// internal::ScxRecord
// internal::ScxRecord
template
<
class
DataRecord
>
template
<
typename
DataRecord
>
bool
internal
::
ScxRecord
<
DataRecord
>::
Help
()
{
bool
internal
::
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'
// complete, so that the data record can be unfrozen.
// complete, so that the data record can be unfrozen.
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord
*>
dr_list_t
;
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord
*>
dr_list_t
;
typedef
embb
::
containers
::
internal
::
FixedSizeList
<
self_t
>
op_list_t
;
// Freeze all data records in data_records to protect their
// Freeze all data records in data_records to protect their
// mutable fields from being changed by other SCXs:
// mutable fields from being changed by other SCXs:
dr_list_t
::
iterator
linked_it
=
linked_data_records_
->
begin
();
dr_list_t
::
iterator
linked_it
=
linked_data_records_
->
begin
();
dr_list_t
::
iterator
linked_end
=
linked_data_records_
->
end
();
dr_list_t
::
iterator
linked_end
=
linked_data_records_
->
end
();
for
(
unsigned
int
fieldIdx
=
0
;
op_list_t
::
iterator
scx_op_it
=
scx_ops_
->
begin
();
linked_it
!=
linked_end
;
op_list_t
::
iterator
scx_op_end
=
scx_ops_
->
end
();
++
linked_it
,
++
fieldIdx
)
{
for
(;
linked_it
!=
linked_end
&&
scx_op_it
!=
scx_op_end
;
++
linked_it
,
++
scx_op_it
)
{
DataRecord
*
r
=
*
linked_it
;
DataRecord
*
r
=
*
linked_it
;
// pointer indexed by r in this->info_fields:
// pointer indexed by r in this->info_fields:
ScxRecord
<
DataRecord
>
*
rinfo
=
&
info_fields_
[
fieldIdx
]
;
ScxRecord
<
DataRecord
>
*
rinfo
_exp
=
&
(
*
scx_op_it
)
;
if
(
!
r
->
ScxInfo
().
CompareAndSwap
(
rinfo
,
this
))
{
if
(
!
r
->
ScxInfo
().
CompareAndSwap
(
rinfo
_exp
,
this
))
{
if
(
r
->
ScxInfo
().
Load
()
!=
this
)
{
if
(
r
->
ScxInfo
().
Load
()
!=
this
)
{
// could not freeze r because it is frozen for
// could not freeze r because it is frozen for
// another SCX:
// another SCX:
...
@@ -331,10 +242,8 @@ bool internal::ScxRecord<DataRecord>::Help() {
...
@@ -331,10 +242,8 @@ bool internal::ScxRecord<DataRecord>::Help() {
// mark step:
// mark step:
dr_list_t
::
iterator
finalize_it
=
finalize_data_records_
->
begin
();
dr_list_t
::
iterator
finalize_it
=
finalize_data_records_
->
begin
();
dr_list_t
::
iterator
finalize_end
=
finalize_data_records_
->
end
();
dr_list_t
::
iterator
finalize_end
=
finalize_data_records_
->
end
();
for
(
unsigned
int
field_idx
=
finalize_range_
.
first
;
for
(;
finalize_it
!=
finalize_end
;
++
finalize_it
)
{
finalize_it
!=
finalize_end
;
(
*
finalize_it
)
->
MarkForFinalize
();
++
finalize_it
,
++
fieldRangeIdx
)
{
linked_data_records_
[
fieldRangeIdx
]
->
MarkForFinalize
();
}
}
// update CAS:
// update CAS:
cas_t
expected_old_value
=
old_value_
;
cas_t
expected_old_value
=
old_value_
;
...
@@ -347,6 +256,11 @@ bool internal::ScxRecord<DataRecord>::Help() {
...
@@ -347,6 +256,11 @@ bool internal::ScxRecord<DataRecord>::Help() {
return
true
;
return
true
;
}
}
template
<
typename
UserData
>
internal
::
ScxRecord
<
LlxScxRecord
<
UserData
>
>
LlxScxRecord
<
UserData
>::
dummy_scx
=
internal
::
ScxRecord
<
LlxScxRecord
<
UserData
>
>
();
}
// namespace primitives
}
// namespace primitives
}
// namespace containers
}
// namespace containers
}
// namespace embb
}
// namespace embb
...
...
containers_cpp/include/embb/containers/primitives/llx_scx.h
View file @
a3c62f0c
...
@@ -30,6 +30,8 @@
...
@@ -30,6 +30,8 @@
#include <embb/base/thread.h>
#include <embb/base/thread.h>
#include <embb/base/atomic.h>
#include <embb/base/atomic.h>
#include <embb/base/thread_specific_storage.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>
#include <embb/containers/internal/fixed_size_list.h>
namespace
embb
{
namespace
embb
{
...
@@ -42,7 +44,7 @@ namespace internal {
...
@@ -42,7 +44,7 @@ namespace internal {
* 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.
*/
*/
template
<
class
DataRecord
>
template
<
typename
DataRecord
>
class
ScxRecord
{
class
ScxRecord
{
private
:
private
:
...
@@ -66,11 +68,11 @@ class ScxRecord {
...
@@ -66,11 +68,11 @@ class ScxRecord {
*/
*/
ScxRecord
()
ScxRecord
()
:
linked_data_records_
(
0
),
:
linked_data_records_
(
0
),
finalize_data_records_
(
0
)
finalize_data_records_
(
0
)
,
new_value_
(
0
),
new_value_
(
0
),
old_value_
(
0
),
old_value_
(
0
),
scx_ops_
(
0
),
scx_ops_
(
0
),
state_
(
OperationState
::
Undefin
ed
),
state_
(
OperationState
::
Comitt
ed
),
all_frozen_
(
false
)
{
all_frozen_
(
false
)
{
field_
=
0
;
field_
=
0
;
}
}
...
@@ -84,7 +86,7 @@ class ScxRecord {
...
@@ -84,7 +86,7 @@ class ScxRecord {
embb
::
base
::
Atomic
<
cas_t
>
*
field
,
embb
::
base
::
Atomic
<
cas_t
>
*
field
,
cas_t
new_value
,
cas_t
new_value
,
cas_t
old_value
,
cas_t
old_value
,
embb
::
containers
::
internal
::
FixedSizeList
<
self_t
*
>
*
scx_ops
,
embb
::
containers
::
internal
::
FixedSizeList
<
self_t
>
*
scx_ops
,
OperationState
operation_state
)
OperationState
operation_state
)
:
linked_data_records_
(
&
linked_data_records
),
:
linked_data_records_
(
&
linked_data_records
),
finalize_data_records_
(
&
finalize_data_records
),
finalize_data_records_
(
&
finalize_data_records
),
...
@@ -143,7 +145,7 @@ class ScxRecord {
...
@@ -143,7 +145,7 @@ class ScxRecord {
* List of SCX operation descriptions associated with data records
* List of SCX operation descriptions associated with data records
* linked with this SCX operation.
* 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.
* Current state of this SCX record.
...
@@ -165,7 +167,7 @@ class ScxRecord {
...
@@ -165,7 +167,7 @@ class ScxRecord {
* 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.
*/
*/
template
<
class
UserData
>
template
<
typename
UserData
>
class
LlxScxRecord
{
class
LlxScxRecord
{
private
:
private
:
...
@@ -203,9 +205,12 @@ class LlxScxRecord {
...
@@ -203,9 +205,12 @@ class LlxScxRecord {
* Assignment operator.
* Assignment operator.
*/
*/
LlxScxRecord
&
operator
=
(
const
LlxScxRecord
&
rhs
)
{
LlxScxRecord
&
operator
=
(
const
LlxScxRecord
&
rhs
)
{
user_data_
=
rhs
.
user_data_
;
if
(
this
!=
&
rhs
)
{
scx_op_
.
Store
(
rhs
.
scx_info_
.
Load
());
user_data_
=
rhs
.
user_data_
;
marked_for_finalize_
=
rhs
.
marked_for_finalize_
;
scx_op_
.
Store
(
rhs
.
scx_op_
.
Load
());
marked_for_finalize_
=
rhs
.
marked_for_finalize_
;
}
return
*
this
;
}
}
/**
/**
...
@@ -299,10 +304,13 @@ class LlxScxRecord {
...
@@ -299,10 +304,13 @@ class LlxScxRecord {
* "Pragmatic Primitives for Non-blocking Data Structures"
* "Pragmatic Primitives for Non-blocking Data Structures"
* (Brown et al., 2013).
* (Brown et al., 2013).
*
*
* \tparam MaxLinks Maximum number of active LL-dependencies per thread
* \tparam UserData Type containing mutable fields
* \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
{
class
LlxScx
{
private
:
private
:
...
@@ -335,8 +343,7 @@ class LlxScx {
...
@@ -335,8 +343,7 @@ class LlxScx {
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
,
DataRecord_t
&
data
,
/**< [OUT] Atomic snapshot of \c NumMutableFields fields in data
/**< [OUT] Atomic snapshot of data record */
record at given index */
bool
&
finalized
bool
&
finalized
/**< [OUT] Indicating whether requested fields have been finalized */
/**< [OUT] Indicating whether requested fields have been finalized */
);
);
...
@@ -393,6 +400,11 @@ class LlxScx {
...
@@ -393,6 +400,11 @@ class LlxScx {
size_t
max_links_
;
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
* Shared table containing for each r in V, a copy of r's info
* value in this thread's local table of LLX results.
* value in this thread's local table of LLX results.
*
*
...
@@ -402,23 +414,38 @@ class LlxScx {
...
@@ -402,23 +414,38 @@ class LlxScx {
* r_i in V -> *ScxRecord(thread_llx_results_[r_i].data_record.ScxInfo())
* 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.
* Thread-specific list of LLX results performed by the thread.
*/
*/
embb
::
base
::
ThreadSpecificStorage
<
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
*
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
>
thread_llx_results_
;
thread_llx_results_
;
/**
/**
* Prevent default construction.
* Prevent default construction.
*/
*/
LlxScx
();
LlxScx
();
/**
/**
* Prevent copy construction.
* Prevent copy construction.
*/
*/
LlxScx
(
const
LlxScx
&
);
LlxScx
(
const
LlxScx
&
);
/**
/**
* Prevent assignment.
* Prevent assignment.
*/
*/
...
...
containers_cpp/test/llx_scx_test.cc
View file @
a3c62f0c
...
@@ -37,14 +37,13 @@ using embb::containers::primitives::LlxScxRecord;
...
@@ -37,14 +37,13 @@ using embb::containers::primitives::LlxScxRecord;
using
embb
::
containers
::
primitives
::
LlxScx
;
using
embb
::
containers
::
primitives
::
LlxScx
;
LlxScxTest
::
LlxScxTest
()
:
LlxScxTest
::
LlxScxTest
()
:
num_threads_
(
static_cast
<
int
>
num_threads_
(
(
partest
::
TestSuite
::
GetDefaultNumThreads
()))
{
static_cast
<
int
>
(
partest
::
TestSuite
::
GetDefaultNumThreads
()))
{
CreateUnit
(
"SerialTest"
).
Add
(
&
LlxScxTest
::
SerialTest
,
this
);
CreateUnit
(
"SerialTest"
).
Add
(
&
LlxScxTest
::
SerialTest
,
this
);
}
}
void
LlxScxTest
::
SerialTest
()
{
void
LlxScxTest
::
SerialTest
()
{
typedef
LlxScxTest
::
Node
Node
;
typedef
LlxScxTest
::
Node
Node
;
// Global:
// Global:
LlxScx
<
Node
>
llxscx
(
3
);
LlxScx
<
Node
>
llxscx
(
3
);
...
@@ -72,7 +71,7 @@ void LlxScxTest::SerialTest() {
...
@@ -72,7 +71,7 @@ void LlxScxTest::SerialTest() {
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
dr3
,
l3
,
finalized
));
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
dr3
,
l3
,
finalized
));
PT_ASSERT
(
!
finalized
);
PT_ASSERT
(
!
finalized
);
FixedSizeList
<
LlxScxRecord
<
Node
>
*
>
FixedSizeList
<
LlxScxRecord
<
Node
>
*
>
linked_deps
(
3
);
linked_deps
(
3
);
linked_deps
.
PushBack
(
&
dr1
);
linked_deps
.
PushBack
(
&
dr1
);
linked_deps
.
PushBack
(
&
dr2
);
linked_deps
.
PushBack
(
&
dr2
);
...
@@ -92,6 +91,12 @@ void LlxScxTest::SerialTest() {
...
@@ -92,6 +91,12 @@ void LlxScxTest::SerialTest() {
linked_deps
,
// V: dependencies, must be LL'd before
linked_deps
,
// V: dependencies, must be LL'd before
finalize_deps
// R: Subsequence of V to be finalized
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
}
// namespace test
...
...
containers_cpp/test/llx_scx_test.h
View file @
a3c62f0c
...
@@ -66,10 +66,19 @@ class LlxScxTest : public partest::TestCase {
...
@@ -66,10 +66,19 @@ class LlxScxTest : public partest::TestCase {
next_
.
Store
(
next_node
);
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
)
{
Node
&
operator
=
(
const
Node
&
rhs
)
{
count_
.
Store
(
rhs
.
count_
.
Load
());
if
(
this
!=
&
rhs
)
{
next_
.
Store
(
rhs
.
next_
.
Load
());
count_
.
Store
(
rhs
.
count_
.
Load
());
value_
=
rhs
.
value_
;
next_
.
Store
(
rhs
.
next_
.
Load
());
value_
=
rhs
.
value_
;
}
return
*
this
;
}
}
};
};
...
...
containers_cpp/test/main.cc
View file @
a3c62f0c
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
#include "./stack_test.h"
#include "./stack_test.h"
#include "./hazard_pointer_test.h"
#include "./hazard_pointer_test.h"
#include "./object_pool_test.h"
#include "./object_pool_test.h"
#include "./llx_scx_test.h"
#define COMMA ,
#define COMMA ,
...
@@ -55,6 +56,7 @@ using embb::containers::test::HazardPointerTest;
...
@@ -55,6 +56,7 @@ using embb::containers::test::HazardPointerTest;
using
embb
::
containers
::
test
::
QueueTest
;
using
embb
::
containers
::
test
::
QueueTest
;
using
embb
::
containers
::
test
::
StackTest
;
using
embb
::
containers
::
test
::
StackTest
;
using
embb
::
containers
::
test
::
ObjectPoolTest
;
using
embb
::
containers
::
test
::
ObjectPoolTest
;
using
embb
::
containers
::
test
::
LlxScxTest
;
PT_MAIN
(
"Data Structures C++"
)
{
PT_MAIN
(
"Data Structures C++"
)
{
unsigned
int
max_threads
=
static_cast
<
unsigned
int
>
(
unsigned
int
max_threads
=
static_cast
<
unsigned
int
>
(
...
@@ -70,6 +72,7 @@ PT_MAIN("Data Structures C++") {
...
@@ -70,6 +72,7 @@ PT_MAIN("Data Structures C++") {
PT_RUN
(
StackTest
<
LockFreeStack
<
int
>
>
);
PT_RUN
(
StackTest
<
LockFreeStack
<
int
>
>
);
PT_RUN
(
ObjectPoolTest
<
LockFreeTreeValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
ObjectPoolTest
<
LockFreeTreeValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
ObjectPoolTest
<
WaitFreeArrayValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
ObjectPoolTest
<
WaitFreeArrayValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
LlxScxTest
);
PT_EXPECT
(
embb_get_bytes_allocated
()
==
0
);
PT_EXPECT
(
embb_get_bytes_allocated
()
==
0
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment