General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

104 lines
2.0 KiB

#pragma once
#include "gp/system/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;
}
}
}
};
}