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
56a22c45
authored
Mar 31, 2015
by
Tobias Fuchs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
containers_cpp: split LLX/SCX into core implementation and convenience interface
parent
746bd2fc
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
742 additions
and
415 deletions
+742
-415
containers_cpp/include/embb/containers/internal/llx_scx-inl.h
+31
-75
containers_cpp/include/embb/containers/internal/llx_scx.h
+18
-251
containers_cpp/include/embb/containers/internal/multiword_ll_sc-inl.h
+145
-0
containers_cpp/include/embb/containers/multiword_ll_sc.h
+500
-0
containers_cpp/test/llx_scx_test.cc
+46
-83
containers_cpp/test/llx_scx_test.h
+0
-1
containers_cpp/test/main.cc
+1
-4
containers_cpp/test/multiset_test.h
+1
-1
No files found.
containers_cpp/include/embb/containers/internal/llx_scx-inl.h
View file @
56a22c45
...
@@ -31,8 +31,6 @@
...
@@ -31,8 +31,6 @@
#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 <stdarg.h>
namespace
embb
{
namespace
embb
{
namespace
containers
{
namespace
containers
{
...
@@ -124,61 +122,7 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
...
@@ -124,61 +122,7 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
}
}
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
UserData
,
typename
ValuePool
>
bool
LlxScx
<
UserData
,
ValuePool
>::
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
UserData
&
user_data
)
{
bool
finalized
;
return
TryLoadLinked
(
data_record
,
user_data
,
finalized
);
}
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
=
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
(
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
,
embb
::
base
::
Atomic
<
cas_t
>
*
cas_field
,
cas_t
cas_value
,
cas_t
cas_value
,
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
,
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
,
...
@@ -193,28 +137,40 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditionalCAS(
...
@@ -193,28 +137,40 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditionalCAS(
// any I_r was linearized.
// any I_r was linearized.
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.
// Will be freed in Help() once the SCX operation has been completed.
scx_op_list_t
*
info_fields
=
scx_record_list_pool_
.
Allocate
(
max_links_
);
scx_op_list_t
*
info_fields
=
scx_record_list_pool_
.
Allocate
(
max_links_
);
if
(
info_fields
==
NULL
)
{
EMBB_THROW
(
embb
::
base
::
ErrorException
,
"Could not allocate SCX record list"
);
}
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 linked_deps ...
// Copy SCX operation of all LLX results of link dependencies into a list.
// For each r in linked_deps ...
for
(
it
=
linked_deps
.
begin
();
it
!=
end
;
++
it
)
{
for
(
it
=
linked_deps
.
begin
();
it
!=
end
;
++
it
)
{
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_
[
thread_id
]
->
begin
();
llx_result_list
::
iterator
llx_result_it
;
llx_result_list
::
iterator
l_end
=
thread_llx_results_
[
thread_id
]
->
end
();
llx_result_list
::
iterator
llx_result_end
;
llx_result_end
=
thread_llx_results_
[
thread_id
]
->
end
();
// Find LLX result of r in thread-local LLX results:
// Find LLX result of r in thread-local LLX results:
for
(;
l_it
!=
l_end
&&
l_it
->
data_record
!=
*
it
;
++
l_it
);
for
(
llx_result_it
=
thread_llx_results_
[
thread_id
]
->
begin
();
if
(
l_it
==
l_end
)
{
llx_result_it
!=
llx_result_end
&&
llx_result_it
->
data_record
!=
*
it
;
++
llx_result_it
);
if
(
llx_result_it
==
llx_result_end
)
{
// Missing LLX result for given linked data record, user did not
// Missing LLX result for given linked data record, user did not
// load-link a data record this SCX depends on.
// load-link a data record this SCX depends on.
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
as SCX dependency
"
);
}
}
// Copy SCX operation from LLX result of link dependency into list:
info_fields
->
PushBack
(
info_fields
->
PushBack
(
l_it
->
data_record
->
ScxInfo
().
Load
());
l
lx_result
_it
->
data_record
->
ScxInfo
().
Load
());
}
}
// Clear thread-local list of LLX results
thread_llx_results_
[
thread_id
]
->
clear
();
thread_llx_results_
[
thread_id
]
->
clear
();
// 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
...
@@ -267,23 +223,23 @@ bool LlxScx<UserData, ValuePool>::Help(
...
@@ -267,23 +223,23 @@ bool LlxScx<UserData, ValuePool>::Help(
ScxRecord
<
DataRecord_t
>
*
rinfo_old
=
*
scx_op_it
;
ScxRecord
<
DataRecord_t
>
*
rinfo_old
=
*
scx_op_it
;
// Try to freeze the data record by setting its SCX info field
// Try to freeze the data record by setting its SCX info field
// to this SCX operation description:
// to this SCX operation description:
if
(
!
r
->
ScxInfo
().
CompareAndSwap
(
rinfo_old
,
scx
))
{
if
(
r
->
ScxInfo
().
CompareAndSwap
(
rinfo_old
,
scx
))
{
// Do not try to delete the sentinel scx record:
if
(
rinfo_old
!=
&
DataRecord_t
::
DummyScx
)
{
scx_record_list_pool_
.
Free
(
rinfo_old
->
scx_ops_
);
scx_record_pool_
.
Free
(
rinfo_old
);
}
}
else
{
if
(
r
->
ScxInfo
().
Load
()
!=
scx
)
{
if
(
r
->
ScxInfo
().
Load
()
!=
scx
)
{
// could not freeze r because it is frozen for another SCX:
// could not freeze r because it is frozen for another SCX:
if
(
scx
->
all_frozen_
)
{
if
(
scx
->
all_frozen_
)
{
// SCX already completed:
// SCX already completed
by any other thread
:
return
true
;
return
true
;
}
}
// Atomically unfreeze all nodes frozen for this SCX (see LLX):
// Atomically unfreeze all nodes frozen for this SCX (see LLX):
scx
->
state_
=
ScxRecord_t
::
Aborted
;
scx
->
state_
=
ScxRecord_t
::
Aborted
;
return
false
;
return
false
;
}
}
}
else
{
// Do not try to delete the sentinel scx record:
if
(
rinfo_old
->
field_
!=
0
)
{
scx_record_list_pool_
.
Free
(
rinfo_old
->
scx_ops_
);
scx_record_pool_
.
Free
(
rinfo_old
);
}
}
}
}
}
// finished freezing data records
// finished freezing data records
...
@@ -313,7 +269,7 @@ bool LlxScx<UserData, ValuePool>::Help(
...
@@ -313,7 +269,7 @@ bool LlxScx<UserData, ValuePool>::Help(
template
<
typename
UserData
>
template
<
typename
UserData
>
LlxScxRecord
<
UserData
>::
LlxScxRecord
()
LlxScxRecord
<
UserData
>::
LlxScxRecord
()
:
marked_for_finalize_
(
false
)
{
:
marked_for_finalize_
(
false
)
{
scx_op_
.
Store
(
&
dummy_s
cx
);
scx_op_
.
Store
(
&
DummyS
cx
);
}
}
template
<
typename
UserData
>
template
<
typename
UserData
>
...
@@ -321,12 +277,12 @@ LlxScxRecord<UserData>::LlxScxRecord(
...
@@ -321,12 +277,12 @@ LlxScxRecord<UserData>::LlxScxRecord(
const
UserData
&
user_data
)
const
UserData
&
user_data
)
:
user_data_
(
user_data
),
:
user_data_
(
user_data
),
marked_for_finalize_
(
false
)
{
marked_for_finalize_
(
false
)
{
scx_op_
.
Store
(
&
dummy_s
cx
);
scx_op_
.
Store
(
&
DummyS
cx
);
}
}
template
<
typename
UserData
>
template
<
typename
UserData
>
ScxRecord
<
LlxScxRecord
<
UserData
>
>
ScxRecord
<
LlxScxRecord
<
UserData
>
>
LlxScxRecord
<
UserData
>::
dummy_scx
=
LlxScxRecord
<
UserData
>::
DummyScx
=
ScxRecord
<
LlxScxRecord
<
UserData
>
>
();
ScxRecord
<
LlxScxRecord
<
UserData
>
>
();
}
// namespace internal
}
// namespace internal
...
...
containers_cpp/include/embb/containers/internal/llx_scx.h
View file @
56a22c45
...
@@ -39,171 +39,6 @@ namespace embb {
...
@@ -39,171 +39,6 @@ namespace embb {
namespace
containers
{
namespace
containers
{
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.
...
@@ -335,10 +170,11 @@ class LlxScxRecord {
...
@@ -335,10 +170,11 @@ class LlxScxRecord {
typedef
internal
::
ScxRecord
<
self_t
>
ScxRecord_t
;
typedef
internal
::
ScxRecord
<
self_t
>
ScxRecord_t
;
typedef
typename
ScxRecord_t
::
OperationState
OperationState
;
typedef
typename
ScxRecord_t
::
OperationState
OperationState
;
public
:
/**
/**
* The dummy SCX record always has state = Aborted.
* The dummy SCX record always has state = Aborted.
*/
*/
static
ScxRecord_t
dummy_s
cx
;
static
ScxRecord_t
DummyS
cx
;
public
:
public
:
/**
/**
...
@@ -472,7 +308,7 @@ class LlxScx {
...
@@ -472,7 +308,7 @@ class LlxScx {
private
:
private
:
typedef
size_t
cas_t
;
typedef
size_t
cas_t
;
typedef
LlxScxRecord
<
UserData
>
DataRecord_t
;
typedef
LlxScxRecord
<
UserData
>
DataRecord_t
;
typedef
internal
::
ScxRecord
<
LlxScxRecord
<
UserData
>
>
ScxRecord_t
;
typedef
internal
::
ScxRecord
<
LlxScxRecord
<
UserData
>
>
ScxRecord_t
;
typedef
typename
ScxRecord_t
::
OperationState
OperationState
;
typedef
typename
ScxRecord_t
::
OperationState
OperationState
;
...
@@ -506,41 +342,17 @@ class LlxScx {
...
@@ -506,41 +342,17 @@ class LlxScx {
);
);
/**
/**
* Tentatively performs an LLX (extended load-linked) operation on given
* Actual implementation of StoreConditional operating on unified fields/values
* LLX/SCX data record.
* of type cas_t.
* 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
* Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record.
* given LLX/SCX data record.
* Returns true if the given value has been stored successfully, otherwise
* Returns true if the given value has been stored successfully, otherwise
* false.
* 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 */
);
template
<
typename
FieldType
>
bool
TryStoreConditional
(
bool
TryStoreConditional
(
embb
::
base
::
Atomic
<
FieldType
*>
*
field
,
embb
::
base
::
Atomic
<
cas_t
>
*
cas_
field
,
/**< [IN] Pointer to the field the value will be stored into */
/**< [IN] Pointer to the field the value will be stored into */
FieldType
*
value
,
cas_t
cas_
value
,
/**< [IN] Value to store */
/**< [IN] Value to store */
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
,
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
,
/**< [IN] Data records linked to this store operation */
/**< [IN] Data records linked to this store operation */
...
@@ -549,32 +361,6 @@ class LlxScx {
...
@@ -549,32 +361,6 @@ class LlxScx {
);
);
/**
/**
* 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 */
);
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.
* Before calling this method, the given LLX/SCX record must have been
* Before calling this method, the given LLX/SCX record must have been
...
@@ -589,7 +375,10 @@ class LlxScx {
...
@@ -589,7 +375,10 @@ class LlxScx {
);
);
private
:
private
:
/**
* Result of a Load-Linked operation, to be stored in thread-specific
* array range within thread_llx_results_.
*/
typedef
struct
{
typedef
struct
{
DataRecord_t
*
data_record
;
DataRecord_t
*
data_record
;
ScxRecord_t
*
scx_record
;
ScxRecord_t
*
scx_record
;
...
@@ -602,6 +391,11 @@ class LlxScx {
...
@@ -602,6 +391,11 @@ class LlxScx {
unsigned
int
ThreadId
();
unsigned
int
ThreadId
();
/**
/**
* Help complete an SCX operation referenced by the given SCX record
*/
bool
Help
(
ScxRecord_t
*
scx
);
/**
* Maximum number of active links created via TryLoadLinked per thread.
* Maximum number of active links created via TryLoadLinked per thread.
*/
*/
size_t
max_links_
;
size_t
max_links_
;
...
@@ -616,7 +410,7 @@ class LlxScx {
...
@@ -616,7 +410,7 @@ class LlxScx {
* 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_
;
/**
/**
...
@@ -627,7 +421,7 @@ class LlxScx {
...
@@ -627,7 +421,7 @@ class LlxScx {
/**
/**
* Thread-specific list of LLX results performed by the thread.
* Thread-specific list of LLX results performed by the thread.
*/
*/
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
**
embb
::
containers
::
internal
::
FixedSizeList
<
LlxResult
>
**
thread_llx_results_
;
thread_llx_results_
;
/**
/**
...
@@ -645,35 +439,8 @@ class LlxScx {
...
@@ -645,35 +439,8 @@ class LlxScx {
*/
*/
LlxScx
&
operator
=
(
const
LlxScx
&
);
LlxScx
&
operator
=
(
const
LlxScx
&
);
bool
Help
(
ScxRecord_t
*
scx
);
/**
* 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
...
...
containers_cpp/include/embb/containers/internal/multiword_ll_sc-inl.h
0 → 100644
View file @
56a22c45
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/
#ifndef EMBB_CONTAINERS_INTERNAL_MULTIWORD_LL_SC_INL_H_
#define EMBB_CONTAINERS_INTERNAL_MULTIWORD_LL_SC_INL_H_
#include <embb/containers/internal/multiword_ll_sc-inl.h>
#include <embb/containers/internal/fixed_size_list.h>
#include <embb/base/thread.h>
#include <embb/base/atomic.h>
namespace
embb
{
namespace
containers
{
namespace
internal
{
template
<
typename
UserData
,
typename
ValuePool
>
MultiwordLLSC
<
UserData
,
ValuePool
>::
MultiwordLLSC
(
size_t
max_links
)
:
llx_scx_
(
max_links
)
{
}
template
<
typename
UserData
,
typename
ValuePool
>
MultiwordLLSC
<
UserData
,
ValuePool
>::~
MultiwordLLSC
()
{
}
template
<
typename
UserData
,
typename
ValuePool
>
bool
MultiwordLLSC
<
UserData
,
ValuePool
>::
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
UserData
&
user_data
,
bool
&
finalized
)
{
return
llx_scx_
.
TryLoadLinked
(
data_record
,
user_data
,
finalized
);
}
template
<
typename
UserData
,
typename
ValuePool
>
bool
MultiwordLLSC
<
UserData
,
ValuePool
>::
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
UserData
&
user_data
)
{
bool
finalized
;
return
llx_scx_
.
TryLoadLinked
(
data_record
,
user_data
,
finalized
);
}
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
FieldType
>
bool
MultiwordLLSC
<
UserData
,
ValuePool
>::
TryStoreConditional
(
Link
&
linked_dep
,
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
FieldType
value
)
{
embb
::
containers
::
internal
::
FixedSizeList
<
Link
*>
linked_deps
(
1
);
linked_deps
.
PushBack
(
&
linked_dep
);
embb
::
containers
::
internal
::
FixedSizeList
<
Link
*>
finalize_deps
(
0
);
embb
::
base
::
Atomic
<
cas_t
>
*
cas_field
=
reinterpret_cast
<
embb
::
base
::
Atomic
<
cas_t
>
*>
(
field
);
cas_t
cas_value
=
ToCASValue
(
value
);
return
llx_scx_
.
TryStoreConditional
(
cas_field
,
cas_value
,
linked_deps
,
finalize_deps
);
}
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
FieldType
>
bool
MultiwordLLSC
<
UserData
,
ValuePool
>::
TryStoreConditional
(
Link
&
linked_dep_1
,
Link
&
linked_dep_2
,
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
FieldType
value
)
{
embb
::
containers
::
internal
::
FixedSizeList
<
Link
*>
linked_deps
(
2
);
linked_deps
.
PushBack
(
&
linked_dep_1
);
linked_deps
.
PushBack
(
&
linked_dep_2
);
embb
::
containers
::
internal
::
FixedSizeList
<
Link
*>
finalize_deps
(
0
);
embb
::
base
::
Atomic
<
cas_t
>
*
cas_field
=
reinterpret_cast
<
embb
::
base
::
Atomic
<
cas_t
>
*>
(
field
);
cas_t
cas_value
=
ToCASValue
(
value
);
return
llx_scx_
.
TryStoreConditional
(
cas_field
,
cas_value
,
linked_deps
,
finalize_deps
);
}
#if 0
template< typename UserData, typename ValuePool >
template< typename FieldType >
bool MultiwordLLSC<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 MultiwordLLSC<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 llx_scx_.TryStoreConditional(cas_field, cas_value, linked_deps, finalize_deps);
}
template< typename UserData, typename ValuePool >
template< typename FieldType >
bool MultiwordLLSC<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);
}
#endif
template
<
typename
UserData
,
typename
ValuePool
>
bool
MultiwordLLSC
<
UserData
,
ValuePool
>::
TryValidateLink
(
const
DataRecord_t
&
field
)
{
return
llx_scx_
.
TryValidateLink
(
field
);
}
}
// namespace internal
}
// namespace containers
}
// namespace embb
#endif // EMBB_CONTAINERS_INTERNAL_MULTIWORD_LL_SC_INL_H_
containers_cpp/include/embb/containers/multiword_ll_sc.h
0 → 100644
View file @
56a22c45
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/
#ifndef EMBB_CONTAINERS_MULTIWORD_LL_SC_H_
#define EMBB_CONTAINERS_MULTIWORD_LL_SC_H_
#include <embb/base/thread.h>
#include <embb/base/atomic.h>
#include <embb/base/function.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/llx_scx.h>
namespace
embb
{
namespace
containers
{
namespace
internal
{
#ifdef DOXYGEN
/**
* 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
MultiwordLLSC
{
public
:
/**
* Constructs a new instance of LlxScx.
*/
MultiwordLLSC
(
size_t
max_links
/**< [IN] Maximum number of links depending on a single SCX operation */
);
/**
* Destructor, frees memory.
*/
~
MultiwordLLSC
();
/**
* 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
/**
* 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
MultiwordLLSC
{
public
:
/**
* Wrapper of user-defined data for LLX/SCX operations
*/
typedef
internal
::
LlxScxRecord
<
UserData
>
Link
;
public
:
/**
* Constructs a new instance of LlxScx.
*/
MultiwordLLSC
(
size_t
max_links
/**< [IN] Maximum number of links depending on a single SCX operation */
);
/**
* Destructor, frees memory.
*/
~
MultiwordLLSC
();
/**
* 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
(
Link
*
const
link
,
/**< [IN] Data record to load-link */
UserData
&
data
,
/**< [OUT] Atomic snapshot of data record at the time the link has been
established */
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
(
Link
*
const
link
,
/**< [IN] Data record to load-link */
UserData
&
data
/**< [OUT] Atomic snapshot of data record at the time the link has been
established */
);
/**
* 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
(
Link
&
linked_dep
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
/**< [IN] Value to store */
);
/**
* 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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
/**< [IN] Value to store */
);
/**
* 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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_3
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
/**< [IN] Value to store */
);
/**
* 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
(
Link
&
linked_dep
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep
/**< [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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep
/**< [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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_3
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep
/**< [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
(
Link
&
linked_dep
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep_1
,
/**< [IN] Data record to be finalized in this store operation */
Link
&
finalize_dep_2
/**< [IN] Data record 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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep_1
,
/**< [IN] Data record to be finalized in this store operation */
Link
&
finalize_dep_2
/**< [IN] Data record 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
(
Link
&
linked_dep_1
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_2
,
/**< [IN] Data record linked to this store operation */
Link
&
linked_dep_3
,
/**< [IN] Data record linked to this store operation */
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN,OUT] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
Link
&
finalize_dep_1
,
/**< [IN] Data record to be finalized in this store operation */
Link
&
finalize_dep_2
/**< [IN] Data record to be finalized in this store operation */
);
#if 0
template< typename FieldType >
bool TryStoreConditional(
Link & linked_dep,
/**< [IN] Data record linked to this store operation */
embb::base::Atomic<FieldType *> * field,
/**< [IN] Pointer to the field the value will be stored into */
FieldType * value,
/**< [IN] Value to store */
Link & finalize_dep_1,
/**< [IN] Data record to be finalized in this store operation */
Link & finalize_dep_2
/**< [IN] Data record to be finalized in this store operation */
);
#endif
/**
* 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
Link
&
link
/**< [IN] Linked data record to validate */
);
private
:
/**
* Maximum number of threads engaging in operations on this LLX/SCX instance.
*/
unsigned
int
max_threads_
;
/**
* Core implementation of LLX/SCX algorithm
*/
internal
::
LlxScx
<
UserData
,
ValuePool
>
llx_scx_
;
/**
* Prevent default construction.
*/
MultiwordLLSC
();
/**
* Prevent copy construction.
*/
MultiwordLLSC
(
const
MultiwordLLSC
&
);
/**
* Prevent assignment.
*/
MultiwordLLSC
&
operator
=
(
const
MultiwordLLSC
&
);
/**
* Convert given value to type compatible with CAS
*/
template
<
typename
FieldType
>
inline
cas_t
ToCASValue
(
FieldType
value
)
{
// Value punning: memcpy given value to type compatible with CAS
cas_t
return_value
;
FieldType
native_value
=
value
;
memcpy
(
&
return_value
,
&
native_value
,
sizeof
(
return_value
));
return
return_value
;
}
/**
* Convert value referenced by given pointer to type compatible with CAS
*/
template
<
typename
FieldType
>
inline
cas_t
ToCASValue
(
FieldType
*
value
)
{
// Value punning: memcpy value referenced by given pointer to type
// compatible with CAS
cas_t
return_value
;
memcpy
(
&
return_value
,
value
,
sizeof
(
return_value
));
return
return_value
;
}
template
<
typename
FieldType
>
inline
void
Assign
(
const
FieldType
&
source
,
FieldType
&
target
)
{
source
=
target
;
}
template
<
typename
FieldType
>
inline
void
Assign
(
const
embb
::
base
::
Atomic
<
FieldType
>
&
source
,
embb
::
base
::
Atomic
<
FieldType
>
&
target
)
{
target
.
Store
(
source
.
Load
());
}
};
#endif // DOXYGEN
}
// namespace primitives
}
// namespace containers
}
// namespace embb
#include <embb/containers/internal/llx_scx-inl.h>
#endif // EMBB_CONTAINERS_MULTIWORD_LL_SC_H_
\ No newline at end of file
containers_cpp/test/llx_scx_test.cc
View file @
56a22c45
...
@@ -27,6 +27,7 @@
...
@@ -27,6 +27,7 @@
#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/internal/llx_scx.h>
#include <embb/containers/internal/llx_scx.h>
// #include <embb/containers/multiword_ll_sc.h>
namespace
embb
{
namespace
embb
{
namespace
containers
{
namespace
containers
{
...
@@ -44,11 +45,11 @@ LlxScxTest::LlxScxTest() :
...
@@ -44,11 +45,11 @@ LlxScxTest::LlxScxTest() :
head
(
0
,
'-'
),
head
(
0
,
'-'
),
tail_llx
(
tail
),
tail_llx
(
tail
),
head_llx
(
head
)
{
head_llx
(
head
)
{
CreateUnit
(
"SerialArrayTest"
)
.
Add
(
&
LlxScxTest
::
SerialArrayTest
,
this
);
CreateUnit
(
"SerialArrayTest"
)
CreateUnit
(
"SerialListTest"
).
Add
(
&
LlxScxTest
::
SerialList
Test
,
this
);
.
Add
(
&
LlxScxTest
::
SerialArray
Test
,
this
);
//
CreateUnit("ParallelTest")
CreateUnit
(
"ParallelTest"
)
//
.Add(&LlxScxTest::ParallelTest, this)
.
Add
(
&
LlxScxTest
::
ParallelTest
,
this
)
//
.Post(&LlxScxTest::ParallelTestPost, this);
.
Post
(
&
LlxScxTest
::
ParallelTestPost
,
this
);
}
}
void
LlxScxTest
::
ParallelTest
()
{
void
LlxScxTest
::
ParallelTest
()
{
...
@@ -56,7 +57,6 @@ void LlxScxTest::ParallelTest() {
...
@@ -56,7 +57,6 @@ void LlxScxTest::ParallelTest() {
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
)
EMBB_THROW
(
embb
::
base
::
ErrorException
,
"Could not get thread id!"
);
EMBB_THROW
(
embb
::
base
::
ErrorException
,
"Could not get thread id!"
);
// Threads try to append n nodes to a linked list in parallel
// Threads try to append n nodes to a linked list in parallel
for
(
char
value
=
'a'
;
value
<=
'z'
;)
{
for
(
char
value
=
'a'
;
value
<=
'z'
;)
{
// Find node to append new element on:
// Find node to append new element on:
...
@@ -67,20 +67,31 @@ void LlxScxTest::ParallelTest() {
...
@@ -67,20 +67,31 @@ void LlxScxTest::ParallelTest() {
next
=
next
->
Data
().
next_
;
next
=
next
->
Data
().
next_
;
}
}
Node
n
;
Node
n
;
llxscx_
.
TryLoadLinked
(
node
,
n
);
bool
finalized
;
// LLX on node the new element will be appended to:
llxscx_
.
TryLoadLinked
(
node
,
n
,
finalized
);
if
(
n
.
next_
==
next
)
{
if
(
n
.
next_
==
next
)
{
// Pointer still valid after LLX,
call SCX(node, node.next, new_node)
// Pointer still valid after LLX,
try to append new node
internal
::
FixedSizeList
<
LlxScxRecord
<
Node
>
*>
linked_deps
(
1
);
internal
::
FixedSizeList
<
LlxScxRecord
<
Node
>
*>
linked_deps
(
1
);
internal
::
FixedSizeList
<
LlxScxRecord
<
Node
>
*>
finalize_deps
(
0
);
linked_deps
.
PushBack
(
node
);
linked_deps
.
PushBack
(
node
);
// Create new node:
// Create new node:
Node
new_node
(
static_cast
<
int
>
(
thread_index
),
value
);
Node
new_node
(
static_cast
<
int
>
(
thread_index
),
value
);
internal
::
LlxScxRecord
<
Node
>
*
new_node_ptr
=
internal
::
LlxScxRecord
<
Node
>
*
new_node_ptr
=
new
internal
::
LlxScxRecord
<
Node
>
(
new_node
);
new
internal
::
LlxScxRecord
<
Node
>
(
new_node
);
// Convert node pointer to size_t:
size_t
new_cas_value
=
reinterpret_cast
<
size_t
>
(
new_node_ptr
);
// Convert target field pointer to size_t*:
embb
::
base
::
Atomic
<
size_t
>
*
field_cas_ptr
=
reinterpret_cast
<
embb
::
base
::
Atomic
<
size_t
>
*
>
(
&
(
node
->
Data
().
next_
));
// Call SCX:
bool
element_inserted
=
bool
element_inserted
=
llxscx_
.
TryStoreConditional
(
llxscx_
.
TryStoreConditional
(
&
(
node
->
Data
().
next_
),
field_cas_ptr
,
new_node_ptr
,
new_cas_value
,
linked_deps
);
linked_deps
,
finalize_deps
);
if
(
element_inserted
)
{
if
(
element_inserted
)
{
// Value has been added to list, continue with next value
// Value has been added to list, continue with next value
++
value
;
++
value
;
...
@@ -109,88 +120,40 @@ void LlxScxTest::SerialArrayTest() {
...
@@ -109,88 +120,40 @@ void LlxScxTest::SerialArrayTest() {
// a specialization for atomics that uses a.Store(b.Load()).
// a specialization for atomics that uses a.Store(b.Load()).
AtomicField
field
(
23
);
AtomicField
field
(
23
);
LlxScxRecord
<
Payload
>
*
my_list
=
LlxScxRecord
<
Payload
>
r1
(
100
);
new
LlxScxRecord
<
Payload
>
[
10
];
LlxScxRecord
<
Payload
>
r2
(
200
);
for
(
int
i
=
0
;
i
!=
10
;
++
i
)
{
LlxScxRecord
<
Payload
>
r3
(
300
);
my_list
[
i
]
=
i
;
}
Payload
l1
,
l2
;
Payload
l1
,
l2
,
l3
;
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
my_list
[
0
],
l1
));
bool
finalized
;
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
my_list
[
5
],
l2
));
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
r1
,
l1
,
finalized
));
PT_ASSERT_EQ
(
100
,
l1
);
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
r2
,
l2
,
finalized
));
PT_ASSERT_EQ
(
200
,
l2
);
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
r3
,
l3
,
finalized
));
PT_ASSERT_EQ
(
300
,
l3
);
// links = { dr1, dr2, dr3 }
FixedSizeList
<
LlxScxRecord
<
Payload
>
*
>
links
(
3
);
links
.
PushBack
(
&
r1
);
links
.
PushBack
(
&
r2
);
links
.
PushBack
(
&
r3
);
FixedSizeList
<
LlxScxRecord
<
Payload
>
*
>
FixedSizeList
<
LlxScxRecord
<
Payload
>
*
>
links
(
2
);
finalize_links
(
1
);
links
.
PushBack
(
&
my_list
[
0
]);
finalize_links
.
PushBack
(
&
r3
);
links
.
PushBack
(
&
my_list
[
5
]);
// Try to store new value depending on links:
// Try to store new value depending on links:
size_t
a
=
42
;
size_t
a
=
42
;
PT_ASSERT
(
llxscx
.
TryStoreConditional
(
&
field
,
a
,
links
));
PT_ASSERT
(
llxscx
.
TryStoreConditional
(
&
field
,
a
,
links
,
finalize_links
));
// New value should have been changed successfully:
// New value should have been changed successfully:
PT_ASSERT_EQ
(
field
.
Load
(),
a
);
PT_ASSERT_EQ
(
field
.
Load
(),
a
);
}
}
void
LlxScxTest
::
SerialListTest
()
{
typedef
LlxScxTest
::
Node
Node
;
// Global:
LlxScx
<
Node
>
llxscx
(
3
);
// Multiset { a, b, b, c }
Node
n1
(
1
,
'a'
);
Node
n2
(
2
,
'b'
);
Node
n3
(
1
,
'c'
);
// V = { dr1, dr2, dr3 }
// R = { dr1, dr2 }
LlxScxRecord
<
Node
>
dr1
(
n1
);
LlxScxRecord
<
Node
>
dr2
(
n2
);
LlxScxRecord
<
Node
>
dr3
(
n3
);
dr1
->
next_
.
Store
(
&
dr2
);
dr2
->
next_
.
Store
(
&
dr3
);
// Thread-local:
Node
l1
,
l2
,
l3
;
bool
finalized
;
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
dr1
,
l1
,
finalized
));
PT_ASSERT
(
!
finalized
);
PT_ASSERT_EQ
(
l1
.
value_
,
dr1
->
value_
);
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
dr2
,
l2
,
finalized
));
PT_ASSERT
(
!
finalized
);
PT_ASSERT_EQ
(
l2
.
value_
,
dr2
->
value_
);
PT_ASSERT
(
llxscx
.
TryLoadLinked
(
&
dr3
,
l3
,
finalized
));
PT_ASSERT
(
!
finalized
);
PT_ASSERT_EQ
(
l3
.
value_
,
dr3
->
value_
);
FixedSizeList
<
LlxScxRecord
<
Node
>
*
>
linked_deps
(
3
);
linked_deps
.
PushBack
(
&
dr1
);
linked_deps
.
PushBack
(
&
dr2
);
linked_deps
.
PushBack
(
&
dr3
);
FixedSizeList
<
LlxScxRecord
<
Node
>
*
>
finalize_deps
(
2
);
finalize_deps
.
PushBack
(
&
dr2
);
finalize_deps
.
PushBack
(
&
dr3
);
typedef
LlxScxRecord
<
Node
>
*
field_t
;
LlxScxRecord
<
Node
>
new_node
(
n3
);
PT_ASSERT
(
llxscx
.
TryStoreConditional
(
&
n2
.
next_
,
// fld: field to update
&
new_node
,
// new value
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
}
// namespace test
}
// namespace containers
}
// namespace containers
}
// namespace embb
}
// namespace embb
containers_cpp/test/llx_scx_test.h
View file @
56a22c45
...
@@ -89,7 +89,6 @@ class LlxScxTest : public partest::TestCase {
...
@@ -89,7 +89,6 @@ class LlxScxTest : public partest::TestCase {
private
:
private
:
void
SerialArrayTest
();
void
SerialArrayTest
();
void
SerialListTest
();
void
ParallelTest
();
void
ParallelTest
();
void
ParallelTestPost
();
void
ParallelTestPost
();
...
...
containers_cpp/test/main.cc
View file @
56a22c45
...
@@ -41,7 +41,6 @@
...
@@ -41,7 +41,6 @@
#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"
#include "./llx_scx_test.h"
// #include "./multiset_test.h"
#define COMMA ,
#define COMMA ,
...
@@ -58,7 +57,6 @@ using embb::containers::test::QueueTest;
...
@@ -58,7 +57,6 @@ 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
;
using
embb
::
containers
::
test
::
LlxScxTest
;
// using embb::containers::test::MultisetTest;
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
>
(
...
@@ -75,7 +73,6 @@ PT_MAIN("Data Structures C++") {
...
@@ -75,7 +73,6 @@ PT_MAIN("Data Structures C++") {
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_RUN
(
LlxScxTest
);
//PT_RUN(MultisetTest);
PT_EXPECT
(
embb_get_bytes_allocated
()
==
0
);
PT_EXPECT
_EQ
(
embb_get_bytes_allocated
(),
static_cast
<
size_t
>
(
0
)
);
}
}
containers_cpp/test/multiset_test.h
View file @
56a22c45
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
#define CONTAINERS_CPP_TEST_MULTISET_TEST_H_
#define CONTAINERS_CPP_TEST_MULTISET_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
{
...
...
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