implemented hazard pointer management
This commit is contained in:
parent
0c65f14043
commit
74ad181227
112
memory/hp.hpp
Normal file
112
memory/hp.hpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#ifndef MEMGRAPH_MEMORY_HP_HPP
|
||||||
|
#define MEMGRAPH_MEMORY_HP_HPP
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cassert>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace memory
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr const size_t HP_SIZE = 128;
|
||||||
|
|
||||||
|
class HP
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// this object can't be copied or moved
|
||||||
|
HP(HP&) = delete;
|
||||||
|
HP(HP&&) = delete;
|
||||||
|
|
||||||
|
// grabs a singleton instance
|
||||||
|
static HP& get()
|
||||||
|
{
|
||||||
|
static HP hp;
|
||||||
|
return hp;
|
||||||
|
}
|
||||||
|
|
||||||
|
class reference
|
||||||
|
{
|
||||||
|
friend class HP;
|
||||||
|
public:
|
||||||
|
reference(reference&) = delete;
|
||||||
|
|
||||||
|
// this type shouldn't be copyable to avoid calling its destructor
|
||||||
|
// multiple times, but should be movable
|
||||||
|
reference(reference&& other)
|
||||||
|
{
|
||||||
|
this->idx = other.idx;
|
||||||
|
|
||||||
|
// set the index to a negative number to indicate that this
|
||||||
|
// index has been moved and that you should not free its
|
||||||
|
// hazard pointer
|
||||||
|
other.idx = -1;
|
||||||
|
}
|
||||||
|
// hazard pointer is cleared once reference goes out of scope
|
||||||
|
~reference()
|
||||||
|
{
|
||||||
|
// check if this reference was moved during its lifetime
|
||||||
|
if(idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& hp = HP::get();
|
||||||
|
hp.clear(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
reference(int64_t idx) : idx(idx) {}
|
||||||
|
int64_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class reference;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
reference insert(T* ptr)
|
||||||
|
{
|
||||||
|
auto p = reinterpret_cast<uintptr_t>(ptr);
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// try to find a free spot in the hazard pointer list
|
||||||
|
for(size_t i = 0; i < HP_SIZE; ++i)
|
||||||
|
{
|
||||||
|
auto hazard = ptr_list[i].load();
|
||||||
|
|
||||||
|
// if this spot isn't free, continue searching
|
||||||
|
if(hazard != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// try to take this spot, if we fail, then another thread has
|
||||||
|
// just taken it. continue searching for a new one
|
||||||
|
if(!ptr_list[i].compare_exchange_strong(hazard, p))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// found a free spot! return a reference to this spot so it
|
||||||
|
// can be cleared later
|
||||||
|
return reference(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we didn't find any free spots, sleep for a while and try again
|
||||||
|
// from the beginning, some other thread might have freed a spot
|
||||||
|
// while we were traversing the lsit.
|
||||||
|
usleep(250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HP()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < HP_SIZE; ++i)
|
||||||
|
ptr_list[i].store(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(reference& ref)
|
||||||
|
{
|
||||||
|
ptr_list[ref.idx].store(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<uintptr_t> ptr_list[HP_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user