Commit a32ff6eb by Christian Kern

Fixed bug due to Hazard Pointer.

HelpScan was implemented wrong -> Scan could be executed be different threads the same time -> FixedSize lists got messed up -> program tried to return wrong pointers to the object pool -> segfault or hang

Moreover, added assertion that checks that only one thread concurrently enters scan, for avoiding these kind of bugs in the future.
parent 53072afc
...@@ -144,11 +144,20 @@ template< typename GuardType > ...@@ -144,11 +144,20 @@ template< typename GuardType >
HazardPointerThreadEntry<GuardType>:: HazardPointerThreadEntry<GuardType>::
HazardPointerThreadEntry(GuardType undefined_guard, int guards_per_thread, HazardPointerThreadEntry(GuardType undefined_guard, int guards_per_thread,
size_t max_size_retired_list) : size_t max_size_retired_list) :
#ifdef EMBB_DEBUG
who_is_scanning(-1),
#endif
undefined_guard(undefined_guard), undefined_guard(undefined_guard),
guards_per_thread(guards_per_thread), guards_per_thread(guards_per_thread),
max_size_retired_list(max_size_retired_list), max_size_retired_list(max_size_retired_list),
retired_list(max_size_retired_list), retired_list(max_size_retired_list),
retired_list_temp(max_size_retired_list), retired_list_temp(max_size_retired_list),
// initially, each potential thread is active... if that is not the case
// another thread could call "HelpScan", and block this thread in making
// progress.
// Still, threads can be leave the hazard pointer processing (deactivation),
// but this can only be done once, i.e., this is not revertable...
is_active(1),
hazard_pointer_list_temp(embb::base::Thread::GetThreadsMaxCount() * hazard_pointer_list_temp(embb::base::Thread::GetThreadsMaxCount() *
guards_per_thread) { guards_per_thread) {
// Initialize guarded pointer list // Initialize guarded pointer list
...@@ -190,7 +199,7 @@ GuardPointer(int guardNumber, GuardType pointerToGuard) { ...@@ -190,7 +199,7 @@ GuardPointer(int guardNumber, GuardType pointerToGuard) {
template< typename GuardType > template< typename GuardType >
void HazardPointerThreadEntry<GuardType>::SetActive(bool active) { void HazardPointerThreadEntry<GuardType>::SetActive(bool active) {
if (active == true) if (active == true)
is_active = 1; is_active = 1;
else else
is_active = 0; is_active = 0;
} }
...@@ -231,16 +240,9 @@ HazardPointer< GuardType >::GetHazardPointerElementForCurrentThread() { ...@@ -231,16 +240,9 @@ HazardPointer< GuardType >::GetHazardPointerElementForCurrentThread() {
// stop operating, and the others are responsible for his retired // stop operating, and the others are responsible for his retired
// list. // list.
// int expected = false;
HazardPointerThreadEntry_t* current_thread_entry = HazardPointerThreadEntry_t* current_thread_entry =
&hazard_pointer_thread_entry_array[GetCurrentThreadIndex()]; &hazard_pointer_thread_entry_array[GetCurrentThreadIndex()];
// If not active, activate it
if (!current_thread_entry->IsActive()) {
current_thread_entry->SetActive(true);
active_hazard_pointer++;
}
return hazard_pointer_thread_entry_array[GetCurrentThreadIndex()]; return hazard_pointer_thread_entry_array[GetCurrentThreadIndex()];
} }
...@@ -270,6 +272,16 @@ void HazardPointer< GuardType >::HelpScan() { ...@@ -270,6 +272,16 @@ void HazardPointer< GuardType >::HelpScan() {
template< typename GuardType > template< typename GuardType >
void HazardPointer< GuardType >:: void HazardPointer< GuardType >::
Scan(HazardPointerThreadEntry_t* currentHazardPointerEntry) { Scan(HazardPointerThreadEntry_t* currentHazardPointerEntry) {
#ifdef EMBB_DEBUG
// scan should only be executed by one thread at a time, otherwise we have
// a bug... this assertions checks that
int expected = -1;
if (!currentHazardPointerEntry->GetScanningThread().CompareAndSwap(
expected, GetCurrentThreadIndex()))
{
assert(false);
}
#endif
// In this function, we compute the intersection between local retired // In this function, we compute the intersection between local retired
// pointers and all hazard pointers. This intersection cannot be deleted and // pointers and all hazard pointers. This intersection cannot be deleted and
// forms the new local retired pointers list. // forms the new local retired pointers list.
...@@ -320,6 +332,10 @@ Scan(HazardPointerThreadEntry_t* currentHazardPointerEntry) { ...@@ -320,6 +332,10 @@ Scan(HazardPointerThreadEntry_t* currentHazardPointerEntry) {
} }
currentHazardPointerEntry->SetRetired( currentHazardPointerEntry->SetRetired(
currentHazardPointerEntry->GetRetiredTemp()); currentHazardPointerEntry->GetRetiredTemp());
#ifdef EMBB_DEBUG
currentHazardPointerEntry->GetScanningThread().Store(-1);
#endif
} }
template< typename GuardType > template< typename GuardType >
...@@ -335,7 +351,8 @@ HazardPointer< GuardType >::HazardPointer( ...@@ -335,7 +351,8 @@ HazardPointer< GuardType >::HazardPointer(
GuardType undefined_guard, int guards_per_thread) : GuardType undefined_guard, int guards_per_thread) :
undefined_guard(undefined_guard), undefined_guard(undefined_guard),
guards_per_thread(guards_per_thread), guards_per_thread(guards_per_thread),
active_hazard_pointer(0), //initially, all potential hazard pointers are active...
active_hazard_pointer(embb::base::Thread::GetThreadsMaxCount()),
free_guard_callback(free_guard_callback) { free_guard_callback(free_guard_callback) {
hazard_pointers = embb::base::Thread::GetThreadsMaxCount(); hazard_pointers = embb::base::Thread::GetThreadsMaxCount();
...@@ -388,6 +405,7 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion( ...@@ -388,6 +405,7 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion(
if (IsThresholdExceeded()) { if (IsThresholdExceeded()) {
HazardPointerThreadEntry_t* currentHazardPointerEntry = HazardPointerThreadEntry_t* currentHazardPointerEntry =
&GetHazardPointerElementForCurrentThread(); &GetHazardPointerElementForCurrentThread();
Scan(currentHazardPointerEntry); Scan(currentHazardPointerEntry);
// Help deactivated threads to clean their retired nodes. // Help deactivated threads to clean their retired nodes.
......
...@@ -169,7 +169,17 @@ class FixedSizeList { ...@@ -169,7 +169,17 @@ class FixedSizeList {
*/ */
template< typename GuardType > template< typename GuardType >
class HazardPointerThreadEntry { class HazardPointerThreadEntry {
private:
#ifdef EMBB_DEBUG
public:
embb::base::Atomic<int>& GetScanningThread()
{
return who_is_scanning;
}
private:
embb::base::Atomic<int> who_is_scanning;
#endif
private:
/** /**
* Value of the undefined guard (means that no guard is set). * Value of the undefined guard (means that no guard is set).
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment