diff --git a/include/gp/ipc/bottleneck.hpp b/include/gp/ipc/bottleneck.hpp new file mode 100644 index 0000000..8928893 --- /dev/null +++ b/include/gp/ipc/bottleneck.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include "gp_config.hpp" + +namespace gp { + template + 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); + } + }; +} \ No newline at end of file diff --git a/include/gp/system/scheduling/simple_scheduling.hpp b/include/gp/system/scheduling/simple_scheduling.hpp index bd5abee..dc4a853 100644 --- a/include/gp/system/scheduling/simple_scheduling.hpp +++ b/include/gp/system/scheduling/simple_scheduling.hpp @@ -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 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; } diff --git a/include/gp/utils/allocators/bottleneck_allocator.hpp b/include/gp/utils/allocators/bottleneck_allocator.hpp new file mode 100644 index 0000000..80cc44a --- /dev/null +++ b/include/gp/utils/allocators/bottleneck_allocator.hpp @@ -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; + }; +} \ No newline at end of file