#pragma once
|
|
|
|
#include "gp/vfs/process_data.hpp"
|
|
|
|
#include <atomic>
|
|
|
|
namespace gp {
|
|
struct topic_list{
|
|
struct node{
|
|
std::atomic_bool is_locked;
|
|
gp::process_data* value;
|
|
std::atomic<struct node*> next;
|
|
|
|
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*>;
|
|
|
|
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) {
|
|
end.store(nullptr);
|
|
}
|
|
if(start.compare_exchange_strong(expected, replace)) {
|
|
return ptr;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// ONLY PUSH ACQUIRED NODES,
|
|
// RELEASE WHEN NO LONGER IN USE
|
|
bool try_push(node_ptr node) {
|
|
auto ed = end.load();
|
|
if(ed) {
|
|
if(ed->try_acquire()) {
|
|
node->next.store(ed);
|
|
if(end.compare_exchange_strong(ed, node)) {
|
|
ed->release();
|
|
return true;
|
|
} else {
|
|
ed->release();
|
|
return false;
|
|
}
|
|
} else return false;
|
|
} else {
|
|
if(end.compare_exchange_strong(ed, node)) {
|
|
start.store(node);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|