diff --git a/containers_cpp/include/embb/containers/internal/llx_scx-inl.h b/containers_cpp/include/embb/containers/internal/llx_scx-inl.h index 1375cbe..76b3bc0 100644 --- a/containers_cpp/include/embb/containers/internal/llx_scx-inl.h +++ b/containers_cpp/include/embb/containers/internal/llx_scx-inl.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace embb { namespace containers { @@ -104,7 +105,7 @@ bool LlxScx::TryLoadLinked( // 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(); + volatile OperationState curr_state = curr_scx->state; bool marked_2 = data_record->IsMarkedForFinalize(); if (curr_state == OperationState::Aborted || (curr_state == OperationState::Comitted && !marked_2)) { @@ -128,14 +129,14 @@ bool LlxScx::TryLoadLinked( } // 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)))) { + (curr_scx->state == OperationState::Comitted || + (curr_scx->state == OperationState::InProgress && Help(curr_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) { + if (data_record->ScxInfo().Load()->state == OperationState::InProgress) { // Help active SCX. // This SCX record has been guarded above. ScxRecord_t * data_record_scx = data_record->ScxInfo().Load(); @@ -157,8 +158,12 @@ bool LlxScx::TryStoreConditional( cas_t cas_value, embb::containers::internal::FixedSizeList & linked_deps, embb::containers::internal::FixedSizeList & finalize_deps) { - typedef embb::containers::internal::FixedSizeList dr_list_t; - typedef embb::containers::internal::FixedSizeList scx_op_list_t; + typedef embb::containers::internal::FixedSizeList + dr_list_t; + typedef embb::containers::internal::FixedSizeList + scx_op_list_t; + typedef embb::containers::internal::FixedSizeList + llx_result_list_t; // Preconditions: // 1. For each r in linked_deps, this thread has performed an invocation // I_r of LLX(r) linked to this SCX. @@ -168,30 +173,28 @@ bool LlxScx::TryStoreConditional( unsigned int thread_id = ThreadId(); // 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, "Could not allocate SCX record list"); } - dr_list_t::const_iterator it; + dr_list_t::const_iterator data_record; dr_list_t::const_iterator end; end = linked_deps.end(); // 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) { - typedef embb::containers::internal::FixedSizeList - llx_result_list; - llx_result_list::iterator llx_result_it; - llx_result_list::iterator llx_result_end; - llx_result_end = thread_llx_results_[thread_id]->end(); + for (data_record = linked_deps.begin(); data_record != end; ++data_record) { + llx_result_list_t::iterator llx_result_it = + thread_llx_results_[thread_id]->begin(); + llx_result_list_t::iterator llx_result_end = + thread_llx_results_[thread_id]->end(); // 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; - ++llx_result_it); - if (llx_result_it->data_record != *it) { + while (llx_result_it != llx_result_end && + llx_result_it->data_record != *data_record) { + ++llx_result_it; + } + if (llx_result_it->data_record != *data_record) { // Missing LLX result for given linked data record, user did not // load-link a data record this SCX depends on. EMBB_THROW(embb::base::ErrorException, @@ -238,8 +241,37 @@ bool LlxScx::TryStoreConditional( template< typename UserData, typename ValuePool > bool LlxScx::TryValidateLink( - const DataRecord_t & field) { - return true; // @TODO + embb::containers::internal::FixedSizeList & linked_deps) { + typedef embb::containers::internal::FixedSizeList + dr_list_t; + typedef embb::containers::internal::FixedSizeList + llx_result_list_t; + unsigned int thread_id = ThreadId(); + // Iterate over given list of data records V: + dr_list_t::iterator linked_it = linked_deps.begin(); + dr_list_t::iterator linked_end = linked_deps.end(); + // For each r in V ... + for (; linked_it != linked_end; ++linked_it) { + llx_result_list_t::iterator llx_result_it = + thread_llx_results_[thread_id]->begin(); + llx_result_list_t::iterator llx_result_end = + thread_llx_results_[thread_id]->end(); + // Find LLX result of data_record (r) in thread-local LLX results: + while (llx_result_it != llx_result_end && + llx_result_it->data_record != *linked_it) { + ++llx_result_it; + } + if (llx_result_it->data_record != *linked_it) { + // Missing LLX result for given linked data record, user did not + // load-link a data record this SCX depends on. + EMBB_THROW(embb::base::ErrorException, + "Missing preceding LLX on a data record used as SCX dependency"); + } + if (llx_result_it->scx_record != (*linked_it)->ScxInfo()) { + return false; + } + } + return true; } // ScxRecord @@ -257,10 +289,10 @@ bool LlxScx::Help( // Freeze all data records in data_records (i.e. reserve them for this // SCX operation) to protect their mutable fields from being changed by // other SCXs: - dr_list_t::iterator linked_it = scx->linked_data_records_->begin(); - dr_list_t::iterator linked_end = scx->linked_data_records_->end(); - op_list_t::iterator scx_op_it = scx->scx_ops_->begin(); - op_list_t::iterator scx_op_end = scx->scx_ops_->end(); + dr_list_t::iterator linked_it = scx->linked_data_records->begin(); + dr_list_t::iterator linked_end = scx->linked_data_records->end(); + op_list_t::iterator scx_op_it = scx->scx_ops->begin(); + op_list_t::iterator scx_op_end = scx->scx_ops->end(); for (; linked_it != linked_end && scx_op_it != scx_op_end; ++linked_it, ++scx_op_it) { DataRecord_t * r = *linked_it; @@ -278,44 +310,44 @@ bool LlxScx::Help( } else { if (r->ScxInfo().Load() != scx) { // could not freeze r because it is frozen for another SCX: - if (scx->all_frozen_) { + if (scx->all_frozen) { // SCX already completed by any other thread: return true; } // Atomically unfreeze all nodes frozen for this SCX (see LLX): - scx->state_ = ScxRecord_t::Aborted; + scx->state = ScxRecord_t::Aborted; return false; } } } // finished freezing data records - assert(scx->state_ == ScxRecord_t::InProgress || - scx->state_ == ScxRecord_t::Comitted); + assert(scx->state == ScxRecord_t::InProgress || + scx->state == ScxRecord_t::Comitted); // frozen step: - scx->all_frozen_ = true; + scx->all_frozen = true; // mark step: - dr_list_t::iterator finalize_it = scx->finalize_data_records_->begin(); - dr_list_t::iterator finalize_end = scx->finalize_data_records_->end(); + dr_list_t::iterator finalize_it = scx->finalize_data_records->begin(); + dr_list_t::iterator finalize_end = scx->finalize_data_records->end(); for (; finalize_it != finalize_end; ++finalize_it) { (*finalize_it)->MarkForFinalize(); } // update CAS: - cas_t expected_old_value = scx->old_value_; + 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_); + scx->field->CompareAndSwap(expected_old_value, scx->new_value); // Commit step. // Finalizes all r in data_records within finalize range and // unfreezes all r in data_records outside of finalize range. // Linearization point of this operation. - scx->state_ = ScxRecord_t::Comitted; + scx->state = ScxRecord_t::Comitted; return true; } template< typename UserData, typename ValuePool > void LlxScx::DeleteOperationCallback( ScxRecord_t * scx_record) { - scx_record_list_pool_.Free(scx_record->scx_ops_); + scx_record_list_pool_.Free(scx_record->scx_ops); scx_record_pool_.Free(scx_record); } diff --git a/containers_cpp/include/embb/containers/internal/llx_scx.h b/containers_cpp/include/embb/containers/internal/llx_scx.h index 5d0976c..26c0625 100644 --- a/containers_cpp/include/embb/containers/internal/llx_scx.h +++ b/containers_cpp/include/embb/containers/internal/llx_scx.h @@ -68,14 +68,14 @@ class ScxRecord { * Default constructor, creates sentinel instance of ScxRecord. */ ScxRecord() - : linked_data_records_(0), - finalize_data_records_(0), - new_value_(0), - old_value_(0), - scx_ops_(0), - state_(OperationState::Comitted), - all_frozen_(false) { - field_ = 0; + : linked_data_records(0), + finalize_data_records(0), + new_value(0), + old_value(0), + scx_ops(0), + state(OperationState::Comitted), + all_frozen(false) { + field = 0; } /** @@ -86,76 +86,72 @@ class ScxRecord { linked_data_records, FixedSizeList & finalize_data_records, - embb::base::Atomic * field, + embb::base::Atomic * target_field, cas_t new_value, cas_t old_value, FixedSizeList * scx_ops, OperationState operation_state) - : linked_data_records_(&linked_data_records), - finalize_data_records_(&finalize_data_records), - new_value_(new_value), - old_value_(old_value), - scx_ops_(scx_ops), - state_(operation_state), - all_frozen_(false) { - field_ = field; + : linked_data_records(&linked_data_records), + finalize_data_records(&finalize_data_records), + new_value(new_value), + old_value(old_value), + scx_ops(scx_ops), + state(operation_state), + all_frozen(false) { + field = target_field; } - OperationState State() const { - return state_; - } - public: /** * Sequence of load-linked data records for this SCX operation. * Named 'V' in original publication. */ const FixedSizeList * - linked_data_records_; + linked_data_records; /** * Sequence of data records to be finalized in this SCX operation. * Named 'R' in original publication. */ const FixedSizeList * - finalize_data_records_; + finalize_data_records; /** * Pointer to a mutable field of a data record in data_records the * new value is to be stored. * Named 'fld' in original publication. */ - embb::base::Atomic * field_; + embb::base::Atomic * field; /** * Value to be written in field referenced by field_index. * Required to be compatible with atomic operations. */ - cas_t new_value_; + cas_t new_value; /** * Value previously read from field referenced by field_index. * Required to be compatible with atomic operations. */ - cas_t old_value_; + cas_t old_value; /** * List of SCX operation descriptions associated with data records * linked with this SCX operation. */ - FixedSizeList * scx_ops_; + FixedSizeList * scx_ops; /** * Current state of this SCX record. */ - OperationState state_; + OperationState state; /** * Whether all fields are currently frozen, initially false. * Set to true after all data records in data_records V have * been frozen for the SCX. */ - bool all_frozen_; + bool all_frozen; }; /* class ScxRecord */ @@ -223,7 +219,7 @@ class LlxScxRecord { UserData & Data() { return user_data_; } - +/* UserData * operator*() { return &user_data_; } @@ -231,7 +227,7 @@ class LlxScxRecord { UserData * operator->() { return &user_data_; } - +*/ /** * A data record r is frozen for an SCX-record U if r.info points to * U and either U.state is InProgress, or U.state is Committed and r @@ -369,17 +365,17 @@ class LlxScx { ); /** - * Performs a VLX (extended validate link) operation on given LLX data - * record. - * Before calling this method, the given LLX/SCX record must have been + * Performs a VLX (extended validate link) operation on list of given LLX + * data records. + * Before calling this method, the given LLX/SCX records 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. + * \returns True if the calling thread's links obtained by its most recent + * invocations of SCX is still valid. */ bool TryValidateLink( - const DataRecord_t & data_record - /**< [IN] Linked data record to validate */ + embb::containers::internal::FixedSizeList & linked_deps + /**< [IN] Linked data records to validate */ ); private: diff --git a/containers_cpp/test/llx_scx_test.cc b/containers_cpp/test/llx_scx_test.cc index 8328508..bb80eea 100644 --- a/containers_cpp/test/llx_scx_test.cc +++ b/containers_cpp/test/llx_scx_test.cc @@ -157,6 +157,8 @@ void LlxScxTest::SerialArrayTest() { links.PushBack(&r2); links.PushBack(&r3); + PT_ASSERT(llxscx.TryValidateLink(links)); + FixedSizeList< LlxScxRecord * > finalize_links(1); finalize_links.PushBack(&r3); @@ -169,6 +171,8 @@ void LlxScxTest::SerialArrayTest() { finalize_links)); // New value should have been changed successfully: PT_ASSERT_EQ(field.Load(), a); + + PT_ASSERT(!llxscx.TryValidateLink(links)); } } // namespace test