#pragma once
|
|
|
|
#include "gp/vfs/process_data.hpp"
|
|
|
|
#include <atomic>
|
|
#include <new>
|
|
|
|
namespace gp {
|
|
struct topic_list{
|
|
struct node{
|
|
alignas(gp_config::limits::hardware_constructive_interference_size) std::atomic_bool is_locked;
|
|
gp::process_data* value;
|
|
alignas(gp_config::limits::hardware_constructive_interference_size) std::atomic<struct node*> next;
|
|
|
|
node()
|
|
{
|
|
is_locked = false;
|
|
value = nullptr;
|
|
next = nullptr;
|
|
}
|
|
|
|
node(node&& v)
|
|
{
|
|
v.try_acquire();
|
|
is_locked = false;
|
|
value = gp::move(v.value);
|
|
next = v.next.load();
|
|
}
|
|
|
|
bool try_acquire() noexcept {
|
|
bool expected = false;
|
|
return !(is_locked.compare_exchange_strong(expected, true));
|
|
}
|
|
|
|
void release() noexcept {
|
|
is_locked.store(false);
|
|
}
|
|
};
|
|
|
|
using node_ptr = struct node*;
|
|
using node_ptr_rep = std::atomic<struct node*>;
|
|
|
|
topic_list()
|
|
: start{nullptr}
|
|
, end{nullptr}
|
|
{}
|
|
|
|
node_ptr_rep start;
|
|
node_ptr_rep end;
|
|
|
|
// NODES ARE ACQUIRED ON POP
|
|
node_ptr try_pop() {
|
|
auto ptr = start.load();
|
|
if(!ptr) return nullptr;
|
|
|
|
if(ptr->try_acquire()) {
|
|
auto replace = ptr->next.load();
|
|
auto expected = ptr;
|
|
if(end.load() == ptr) {
|
|
replace = nullptr;
|
|
}
|
|
if(start.compare_exchange_strong(expected, replace)) {
|
|
end.store(nullptr);
|
|
return ptr;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// ONLY PUSH ACQUIRED NODES,
|
|
// RELEASE WHEN NO LONGER IN USE
|
|
bool try_push(node_ptr node) {
|
|
node->next.store(nullptr);
|
|
auto ed = end.load();
|
|
if(ed) {
|
|
if(ed->try_acquire()) {
|
|
auto old_ed = ed;
|
|
node->next.store(ed);
|
|
|
|
if(end.compare_exchange_strong(ed, node)) {
|
|
node->release();
|
|
old_ed->release();
|
|
return true;
|
|
} else {
|
|
node->release();
|
|
old_ed->release();
|
|
return false;
|
|
}
|
|
} else return false;
|
|
} else {
|
|
if(end.compare_exchange_strong(ed, node)) {
|
|
start.store(node);
|
|
node->release();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|