Browse Source

Added bottleneck implementation

channel
Ludovic 'Archivist' Lagouardette 3 years ago
parent
commit
c9e7e9b05e
3 changed files with 124 additions and 23 deletions
  1. +53
    -0
      include/gp/ipc/bottleneck.hpp
  2. +13
    -23
      include/gp/system/scheduling/simple_scheduling.hpp
  3. +58
    -0
      include/gp/utils/allocators/bottleneck_allocator.hpp

+ 53
- 0
include/gp/ipc/bottleneck.hpp View File

@ -0,0 +1,53 @@
#pragma once
#include <atomic>
#include "gp_config.hpp"
namespace gp {
template<typename T>
class lock_guard {
T& ref;
public:
lock_guard(T& _ref)
: ref(_ref)
{
ref.lock();
}
~lock_guard() {
ref.unlock();
}
};
/**
* @brief A fast mutual exclusion handler WITHOUT deadlock detection
*/
class fast_bottleneck {
std::atomic_bool flag;
public:
fast_bottleneck() = default;
fast_bottleneck(fast_bottleneck&) = delete;
fast_bottleneck(fast_bottleneck&&) = delete;
void lock() {
while(not try_lock());
}
[[nodiscard]] bool try_lock() {
bool f = false;
bool t = true;
return flag.compare_exchange_strong(f,t,std::memory_order::acquire);
}
void unlock() {
gp_config::assertion(try_unlock(), "Unlocking failed in fast_bottleneck: potential double unlocking issue");
}
[[nodiscard]] bool try_unlock() {
bool f = false;
bool t = true;
return flag.compare_exchange_strong(t,f,std::memory_order::release);
}
};
}

+ 13
- 23
include/gp/system/scheduling/simple_scheduling.hpp View File

@ -1,43 +1,33 @@
#pragma once
#include "gp/system/system.hpp"
// TODO: implement unsafe_bottleneck to use in the locked list
#include "gp/ipc/bottleneck.hpp"
#include "gp/system/system.hpp"
namespace gp{
namespace system {
class simple_scheduling : public gp::system::scheduling_scheme {
struct locked_circular_buffer {
std::atomic_bool lock;
gp::array<gp::system::task_queue::node_ptr, gp_config::limits::max_processes> processes;
size_t read_idx = 0;
size_t write_idx = 0;
fast_bottleneck lock;
void push(gp::system::task_queue::node_ptr node) {
bool t = true;
bool f = false;
while(not lock.compare_exchange_strong(f,t)){}
{
gp_config::assertion((write_idx + 1)%processes.size() != read_idx, "bad push to circular buffer");
processes[write_idx] = node;
write_idx=(write_idx+1)%processes.size();
}
while(not lock.compare_exchange_strong(t,f)){}
auto guard = lock_guard(lock);
gp_config::assertion((write_idx + 1)%processes.size() != read_idx, "bad push to circular buffer");
processes[write_idx] = node;
write_idx=(write_idx+1)%processes.size();
}
gp::system::task_queue::node_ptr pop() {
bool t = true;
bool f = false;
gp::system::task_queue::node_ptr ret;
while(not lock.compare_exchange_strong(f,t)){}
{
if(read_idx == write_idx) {
ret = nullptr;
} else {
ret = processes[read_idx];
read_idx=(read_idx+1)%processes.size();
}
auto guard = lock_guard(lock);
if(read_idx == write_idx) {
ret = nullptr;
} else {
ret = processes[read_idx];
read_idx=(read_idx+1)%processes.size();
}
while(not lock.compare_exchange_strong(t,f)){}
return ret;
}

+ 58
- 0
include/gp/utils/allocators/bottleneck_allocator.hpp View File

@ -0,0 +1,58 @@
#pragma once
#include "gp/utils/allocators/allocator.hpp"
#include "gp/ipc/bottleneck.hpp"
namespace gp {
class bottleneck_allocator_front : public allocator {
allocator& backend;
fast_bottleneck lock;
public:
bottleneck_allocator_front(allocator& _backend)
: backend(_backend)
, lock()
{}
/**
* @brief Allocates memory, THREAD SAFE
*
* @param sz the amount of bytes to allocate
*
* @return the allocated memory as a pointer on success
* @return nullptr if it failed allocating
*/
virtual void* allocate(size_t sz) {
auto guard = lock_guard(lock);
return backend.allocate(sz);
}
/**
* @brief Deallocates memory, THREAD SAFE
*
* @param ptr the memory to deallocate
*
* @return true if the memory was successfully deallocated
* @return false if the memory was not deallocated
*/
virtual bool deallocate(void* ptr) {
auto guard = lock_guard(lock);
return backend.deallocate(ptr);
}
/**
* @brief Tries to reallocate memory, THREAD SAFE
*
* @param ptr The memory to reallocate
* @param sz The new size we want to give the memory
*
* @return true if reallocation was successful
* @return false if the reallocation failed
*/
virtual bool try_reallocate(void* ptr, size_t sz) {
auto guard = lock_guard(lock);
return backend.try_reallocate(ptr, sz);
}
virtual ~bottleneck_allocator_front() = default;
};
}

Loading…
Cancel
Save