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
92213745
authored
Apr 15, 2015
by
Tobias Fuchs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
containers_cpp: added comments on implementation of LlxScx
parent
3cf586b9
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
53 additions
and
25 deletions
+53
-25
containers_cpp/include/embb/containers/internal/llx_scx-inl.h
+35
-11
containers_cpp/test/llx_scx_test.cc
+18
-14
No files found.
containers_cpp/include/embb/containers/internal/llx_scx-inl.h
View file @
92213745
...
...
@@ -99,6 +99,11 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
// Order of initialization matters:
volatile
bool
marked_1
=
data_record
->
IsMarkedForFinalize
();
ScxRecord_t
*
curr_scx
=
data_record
->
ScxInfo
().
Load
();
// Guard active SCX record of this data record using guard 1.
// When calling help with this SCX record, it will be guarded
// using guard 0 again.
// This hazard pointer is validated in the nested if-block below.
hp
.
GuardPointer
(
1
,
curr_scx
);
volatile
OperationState
curr_state
=
curr_scx
->
State
();
bool
marked_2
=
data_record
->
IsMarkedForFinalize
();
if
(
curr_state
==
OperationState
::
Aborted
||
...
...
@@ -106,8 +111,11 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
// read mutable fields into local variable:
UserData
user_data_local
(
data_record
->
Data
());
if
(
data_record
->
ScxInfo
().
Load
()
==
curr_scx
)
{
// store <r, curr_scx, user_data_local> in
// the thread-specific table:
// Active SCX record of data record did not change.
// Store <r, curr_scx, user_data_local> in
// the thread-specific table.
// LLX results do not need to be guarded as they local to the
// thread.
LlxResult
llx_result
;
llx_result
.
data_record
=
data_record
;
llx_result
.
scx_record
=
curr_scx
;
...
...
@@ -118,16 +126,20 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
return
true
;
}
}
// Active SCX record of data record has been changed in between
if
(
marked_1
&&
(
curr_scx
->
State
()
==
OperationState
::
Comitted
||
(
curr_scx
->
State
()
==
OperationState
::
InProgress
&&
Help
(
curr_scx
))))
{
// Successfully completed active SCX:
// Successfully completed the data record's active SCX but failed to
// complete the LLX operation because the data record has been finalized:
finalized
=
true
;
return
false
;
}
if
(
data_record
->
ScxInfo
().
Load
()
->
State
()
==
OperationState
::
InProgress
)
{
// Help active SCX:
Help
(
data_record
->
ScxInfo
().
Load
());
// Help active SCX.
// This SCX record has been guarded above.
ScxRecord_t
*
data_record_scx
=
data_record
->
ScxInfo
().
Load
();
Help
(
data_record_scx
);
}
return
false
;
}
...
...
@@ -157,6 +169,7 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
// 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.
// Will be freed in Help() once the SCX operation has been completed.
// In brief: A list of the SCX record of all linked deps.
scx_op_list_t
*
info_fields
=
scx_record_list_pool_
.
Allocate
(
max_links_
);
if
(
info_fields
==
NULL
)
{
EMBB_THROW
(
embb
::
base
::
ErrorException
,
...
...
@@ -173,7 +186,7 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
llx_result_list
::
iterator
llx_result_it
;
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
data_record (r)
in thread-local LLX results:
for
(
llx_result_it
=
thread_llx_results_
[
thread_id
]
->
begin
();
llx_result_it
!=
llx_result_end
&&
llx_result_it
->
data_record
!=
*
it
;
...
...
@@ -193,6 +206,9 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
// Announce SCX operation. Lists linked_deps and finalize_dep are
// guaranteed to remain on the stack until this announced operation
// is completed, so no allocation/pool is necessary.
// The SCX operation description must be allocated from a pool as
// LLX data records might reference it after this operation has been
// completed.
ScxRecord_t
new_scx
(
linked_deps
,
finalize_deps
,
...
...
@@ -202,17 +218,21 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
cas_value
,
// old value:
cas_field
->
Load
(),
// li
nked SCX operations:
// li
st of the SCX record of all linked deps
info_fields
,
// initial operation state:
OperationState
::
InProgress
);
// Allocate from pool as this operation description is global:
ScxRecord_t
*
scx
=
scx_record_pool_
.
Allocate
(
new_scx
);
// Try to complete the operation. It will also be helped in failing
// TryLoadLinked operations.
bool
result
=
Help
(
scx
);
hp
.
GuardPointer
(
0
,
NULL
);
hp
.
GuardPointer
(
1
,
NULL
);
// Release all load-links this SCX operation depended on
ClearLinks
();
hp
.
EnqueuePointerForDeletion
(
scx
);
// Release guards, but do not enqueue instance scx for deletion as it
// is still referenced in data records.
hp
.
GuardPointer
(
0
,
NULL
);
hp
.
GuardPointer
(
1
,
NULL
);;
return
result
;
}
...
...
@@ -247,7 +267,9 @@ bool LlxScx<UserData, ValuePool>::Help(
ScxRecord
<
DataRecord_t
>
*
rinfo_old
=
*
scx_op_it
;
hp
.
GuardPointer
(
1
,
rinfo_old
);
// Try to freeze the data record by setting its SCX info field
// to this SCX operation description:
// to this SCX operation description.
// r->ScxInfo() is not an ABA hazard as it is local to instance scx
// which is already guarded.
if
(
r
->
ScxInfo
().
CompareAndSwap
(
rinfo_old
,
scx
))
{
// Do not try to delete the sentinel scx record:
if
(
rinfo_old
!=
&
DataRecord_t
::
DummyScx
)
{
...
...
@@ -279,6 +301,8 @@ bool LlxScx<UserData, ValuePool>::Help(
}
// update CAS:
cas_t
expected_old_value
=
scx
->
old_value_
;
// scx->old_value_ is not an ABA hazard as it is local to the instance
// scx which is already guarded.
scx
->
field_
->
CompareAndSwap
(
expected_old_value
,
scx
->
new_value_
);
// Commit step.
// Finalizes all r in data_records within finalize range and
...
...
containers_cpp/test/llx_scx_test.cc
View file @
92213745
...
...
@@ -63,28 +63,30 @@ void LlxScxTest::ParallelTest() {
int
return_val
=
embb_internal_thread_index
(
&
thread_index
);
if
(
return_val
!=
EMBB_SUCCESS
)
EMBB_THROW
(
embb
::
base
::
ErrorException
,
"Could not get thread id!"
);
// Threads try to append n nodes to a linked list in parallel
for
(
char
value
=
'a'
;
value
<=
'p'
;)
{
// Every thread adds every character from 'a' to 'z' into an ordered
// linked list
for
(
char
value
=
'a'
;
value
<=
'z'
;)
{
// Find node to append new element on:
internal
::
LlxScxRecord
<
Node
>
*
node
=
&
head_llx
;
internal
::
LlxScxRecord
<
Node
>
*
next
=
node
->
Data
().
next_
;
while
(
next
!=
0
&&
next
->
Data
().
value_
<
value
)
{
node
=
next
;
next
=
next
->
Data
().
next_
;
internal
::
LlxScxRecord
<
Node
>
*
node
_rec
=
&
head_llx
;
internal
::
LlxScxRecord
<
Node
>
*
next
_rec
=
node_rec
->
Data
().
next_
;
while
(
next
_rec
!=
0
&&
next_rec
->
Data
().
value_
<
value
)
{
node
_rec
=
next_rec
;
next
_rec
=
next_rec
->
Data
().
next_
;
}
Node
n
;
Node
n
ode
;
bool
finalized
;
// LLX on node the new element will be appended to:
if
(
!
llxscx_
.
TryLoadLinked
(
node
,
n
,
finalized
))
{
if
(
!
llxscx_
.
TryLoadLinked
(
node
_rec
,
node
,
finalized
))
{
continue
;
}
if
(
n
.
next_
==
next
)
{
PT_ASSERT_MSG
(
!
finalized
,
"No node should be finalized"
);
if
(
node
.
next_
==
next_rec
)
{
// Pointer still valid after LLX, try to append new node
internal
::
FixedSizeList
<
LlxScxRecord
<
Node
>
*>
linked_deps
(
1
);
internal
::
FixedSizeList
<
LlxScxRecord
<
Node
>
*>
finalize_deps
(
0
);
linked_deps
.
PushBack
(
node
);
linked_deps
.
PushBack
(
node
_rec
);
// Create new node:
Node
new_node
(
static_cast
<
int
>
(
thread_index
),
value
,
next
);
Node
new_node
(
static_cast
<
int
>
(
thread_index
),
value
,
next
_rec
);
internal
::
LlxScxRecord
<
Node
>
*
new_node_ptr
=
new
internal
::
LlxScxRecord
<
Node
>
(
new_node
);
// Convert node pointer to size_t:
...
...
@@ -92,7 +94,7 @@ void LlxScxTest::ParallelTest() {
// 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_
));
&
(
node
_rec
->
Data
().
next_
));
// Call SCX:
bool
element_inserted
=
llxscx_
.
TryStoreConditional
(
...
...
@@ -119,7 +121,9 @@ void LlxScxTest::ParallelTestPost() {
node
=
next
;
next
=
next
->
Data
().
next_
;
}
PT_ASSERT_EQ_MSG
(
static_cast
<
size_t
>
(
16
*
num_threads_
),
values
.
size
(),
// Check if every character from 'a' to 'z' has been added to the
// linked list in the correct order
PT_ASSERT_EQ_MSG
(
static_cast
<
size_t
>
(
26
*
num_threads_
),
values
.
size
(),
"Unexpected size of result list"
);
}
...
...
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