From 406308a8105af9f1674904ac7fbdf33cba5e686c Mon Sep 17 00:00:00 2001 From: brige Date: Tue, 3 Dec 2024 22:44:07 +0800 Subject: [PATCH] add ipc source --- Thirdparty/libipc/include/libipc/export.h | 54 -- src/CMakeLists.txt | 3 +- src/Ipc/ipclib.h | 10 +- src/Ipc/libipc/buffer.cpp | 87 +++ src/Ipc/libipc/buffer.h | 67 ++ src/Ipc/libipc/circ/elem_array.h | 141 ++++ src/Ipc/libipc/circ/elem_def.h | 109 +++ src/Ipc/libipc/condition.h | 38 ++ src/Ipc/libipc/def.h | 73 ++ src/Ipc/libipc/ipc.cpp | 778 ++++++++++++++++++++++ src/Ipc/libipc/ipc.h | 199 ++++++ src/Ipc/libipc/memory/alloc.h | 424 ++++++++++++ src/Ipc/libipc/memory/allocator_wrapper.h | 121 ++++ src/Ipc/libipc/memory/resource.h | 110 +++ src/Ipc/libipc/memory/wrapper.h | 327 +++++++++ src/Ipc/libipc/mutex.h | 38 ++ src/Ipc/libipc/platform/detail.h | 136 ++++ src/Ipc/libipc/platform/platform.cpp1 | 3 + src/Ipc/libipc/platform/win/condition.h | 119 ++++ src/Ipc/libipc/platform/win/get_sa.h | 35 + src/Ipc/libipc/platform/win/mutex.h | 98 +++ src/Ipc/libipc/platform/win/semaphore.h | 74 ++ src/Ipc/libipc/platform/win/shm_win.cpp | 140 ++++ src/Ipc/libipc/platform/win/to_tchar.h | 74 ++ src/Ipc/libipc/policy.h | 25 + src/Ipc/libipc/pool_alloc.cpp | 17 + src/Ipc/libipc/pool_alloc.h | 102 +++ src/Ipc/libipc/prod_cons.h | 433 ++++++++++++ src/Ipc/libipc/queue.h | 223 +++++++ src/Ipc/libipc/rw_lock.h | 171 +++++ src/Ipc/libipc/semaphore.h | 36 + src/Ipc/libipc/shm.cpp | 113 ++++ src/Ipc/libipc/shm.h | 58 ++ src/Ipc/libipc/sync/condition.cpp | 77 +++ src/Ipc/libipc/sync/mutex.cpp | 77 +++ src/Ipc/libipc/sync/semaphore.cpp | 71 ++ src/Ipc/libipc/sync/waiter.cpp | 22 + src/Ipc/libipc/utility/concept.h | 29 + src/Ipc/libipc/utility/id_pool.h | 103 +++ src/Ipc/libipc/utility/log.h | 39 ++ src/Ipc/libipc/utility/pimpl.h | 64 ++ src/Ipc/libipc/utility/scope_guard.h | 64 ++ src/Ipc/libipc/utility/utility.h | 64 ++ src/Ipc/libipc/waiter.h | 87 +++ 44 files changed, 5072 insertions(+), 61 deletions(-) delete mode 100644 Thirdparty/libipc/include/libipc/export.h create mode 100644 src/Ipc/libipc/buffer.cpp create mode 100644 src/Ipc/libipc/buffer.h create mode 100644 src/Ipc/libipc/circ/elem_array.h create mode 100644 src/Ipc/libipc/circ/elem_def.h create mode 100644 src/Ipc/libipc/condition.h create mode 100644 src/Ipc/libipc/def.h create mode 100644 src/Ipc/libipc/ipc.cpp create mode 100644 src/Ipc/libipc/ipc.h create mode 100644 src/Ipc/libipc/memory/alloc.h create mode 100644 src/Ipc/libipc/memory/allocator_wrapper.h create mode 100644 src/Ipc/libipc/memory/resource.h create mode 100644 src/Ipc/libipc/memory/wrapper.h create mode 100644 src/Ipc/libipc/mutex.h create mode 100644 src/Ipc/libipc/platform/detail.h create mode 100644 src/Ipc/libipc/platform/platform.cpp1 create mode 100644 src/Ipc/libipc/platform/win/condition.h create mode 100644 src/Ipc/libipc/platform/win/get_sa.h create mode 100644 src/Ipc/libipc/platform/win/mutex.h create mode 100644 src/Ipc/libipc/platform/win/semaphore.h create mode 100644 src/Ipc/libipc/platform/win/shm_win.cpp create mode 100644 src/Ipc/libipc/platform/win/to_tchar.h create mode 100644 src/Ipc/libipc/policy.h create mode 100644 src/Ipc/libipc/pool_alloc.cpp create mode 100644 src/Ipc/libipc/pool_alloc.h create mode 100644 src/Ipc/libipc/prod_cons.h create mode 100644 src/Ipc/libipc/queue.h create mode 100644 src/Ipc/libipc/rw_lock.h create mode 100644 src/Ipc/libipc/semaphore.h create mode 100644 src/Ipc/libipc/shm.cpp create mode 100644 src/Ipc/libipc/shm.h create mode 100644 src/Ipc/libipc/sync/condition.cpp create mode 100644 src/Ipc/libipc/sync/mutex.cpp create mode 100644 src/Ipc/libipc/sync/semaphore.cpp create mode 100644 src/Ipc/libipc/sync/waiter.cpp create mode 100644 src/Ipc/libipc/utility/concept.h create mode 100644 src/Ipc/libipc/utility/id_pool.h create mode 100644 src/Ipc/libipc/utility/log.h create mode 100644 src/Ipc/libipc/utility/pimpl.h create mode 100644 src/Ipc/libipc/utility/scope_guard.h create mode 100644 src/Ipc/libipc/utility/utility.h create mode 100644 src/Ipc/libipc/waiter.h diff --git a/Thirdparty/libipc/include/libipc/export.h b/Thirdparty/libipc/include/libipc/export.h deleted file mode 100644 index 884f2fc..0000000 --- a/Thirdparty/libipc/include/libipc/export.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#if defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT) - -# define IPC_DECL_EXPORT Q_DECL_EXPORT -# define IPC_DECL_IMPORT Q_DECL_IMPORT - -#else // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT) - -/* - * Compiler & system detection for IPC_DECL_EXPORT & IPC_DECL_IMPORT. - * Not using QtCore cause it shouldn't depend on Qt. -*/ - -#if defined(_MSC_VER) -# define IPC_DECL_EXPORT __declspec(dllexport) -# define IPC_DECL_IMPORT __declspec(dllimport) -#elif defined(__ARMCC__) || defined(__CC_ARM) -# if defined(ANDROID) || defined(__linux__) || defined(__linux) -# define IPC_DECL_EXPORT __attribute__((visibility("default"))) -# define IPC_DECL_IMPORT __attribute__((visibility("default"))) -# else -# define IPC_DECL_EXPORT __declspec(dllexport) -# define IPC_DECL_IMPORT __declspec(dllimport) -# endif -#elif defined(__GNUC__) -# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \ - defined(WIN64) || defined(_WIN64) || defined(__WIN64__) -# define IPC_DECL_EXPORT __declspec(dllexport) -# define IPC_DECL_IMPORT __declspec(dllimport) -# else -# define IPC_DECL_EXPORT __attribute__((visibility("default"))) -# define IPC_DECL_IMPORT __attribute__((visibility("default"))) -# endif -#else -# define IPC_DECL_EXPORT __attribute__((visibility("default"))) -# define IPC_DECL_IMPORT __attribute__((visibility("default"))) -#endif - -#endif // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT) - -/* - * Define IPC_EXPORT for exporting function & class. -*/ - -#ifndef IPC_EXPORT -#if defined(LIBIPC_LIBRARY_SHARED_BUILDING__) -# define IPC_EXPORT IPC_DECL_EXPORT -#elif defined(LIBIPC_LIBRARY_SHARED_USING__) -# define IPC_EXPORT IPC_DECL_IMPORT -#else -# define IPC_EXPORT -#endif -#endif /*IPC_EXPORT*/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4db7f78..b6bed94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ SET( INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/Ipc ${Thirdparty}/glfw/include ${Thirdparty}/glew/include ${Thirdparty}/glm @@ -68,8 +69,6 @@ target_link_libraries( glfw3 debug spdlogd optimized spdlog - debug ipcd - optimized ipc ) diff --git a/src/Ipc/ipclib.h b/src/Ipc/ipclib.h index 77eb18f..6f3ffb3 100644 --- a/src/Ipc/ipclib.h +++ b/src/Ipc/ipclib.h @@ -9,12 +9,12 @@ extern "C" { typedef void(__stdcall *ReaderCallbackFunc)(const char* data, unsigned int size); - IPC_EXPORT bool __stdcall initialize(const char* sender_name, const char* receiver_name); - IPC_EXPORT void __stdcall uninitialize(); + bool __stdcall initialize(const char* sender_name, const char* receiver_name); + void __stdcall uninitialize(); - IPC_EXPORT bool __stdcall listen(); - IPC_EXPORT bool __stdcall send(const char* data, unsigned int size); - IPC_EXPORT bool __stdcall setReaderCallback(ReaderCallbackFunc callback); + bool __stdcall listen(); + bool __stdcall send(const char* data, unsigned int size); + bool __stdcall setReaderCallback(ReaderCallbackFunc callback); #ifdef __cplusplus } diff --git a/src/Ipc/libipc/buffer.cpp b/src/Ipc/libipc/buffer.cpp new file mode 100644 index 0000000..0ac0fa7 --- /dev/null +++ b/src/Ipc/libipc/buffer.cpp @@ -0,0 +1,87 @@ +#include "libipc/buffer.h" +#include "libipc/utility/pimpl.h" + +#include + +namespace ipc { + +bool operator==(buffer const & b1, buffer const & b2) { + return (b1.size() == b2.size()) && (std::memcmp(b1.data(), b2.data(), b1.size()) == 0); +} + +bool operator!=(buffer const & b1, buffer const & b2) { + return !(b1 == b2); +} + +class buffer::buffer_ : public pimpl { +public: + void* p_; + std::size_t s_; + void* a_; + buffer::destructor_t d_; + + buffer_(void* p, std::size_t s, buffer::destructor_t d, void* a) + : p_(p), s_(s), a_(a), d_(d) { + } + + ~buffer_() { + if (d_ == nullptr) return; + d_((a_ == nullptr) ? p_ : a_, s_); + } +}; + +buffer::buffer() + : buffer(nullptr, 0, nullptr, nullptr) { +} + +buffer::buffer(void* p, std::size_t s, destructor_t d) + : p_(p_->make(p, s, d, nullptr)) { +} + +buffer::buffer(void* p, std::size_t s, destructor_t d, void* additional) + : p_(p_->make(p, s, d, additional)) { +} + +buffer::buffer(void* p, std::size_t s) + : buffer(p, s, nullptr) { +} + +buffer::buffer(char const & c) + : buffer(const_cast(&c), 1) { +} + +buffer::buffer(buffer&& rhs) + : buffer() { + swap(rhs); +} + +buffer::~buffer() { + p_->clear(); +} + +void buffer::swap(buffer& rhs) { + std::swap(p_, rhs.p_); +} + +buffer& buffer::operator=(buffer rhs) { + swap(rhs); + return *this; +} + +bool buffer::empty() const noexcept { + return (impl(p_)->p_ == nullptr) || (impl(p_)->s_ == 0); +} + +void* buffer::data() noexcept { + return impl(p_)->p_; +} + +void const * buffer::data() const noexcept { + return impl(p_)->p_; +} + +std::size_t buffer::size() const noexcept { + return impl(p_)->s_; +} + +} // namespace ipc diff --git a/src/Ipc/libipc/buffer.h b/src/Ipc/libipc/buffer.h new file mode 100644 index 0000000..5362114 --- /dev/null +++ b/src/Ipc/libipc/buffer.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include + +#include "libipc/def.h" + +namespace ipc { + +class buffer { +public: + using destructor_t = void (*)(void*, std::size_t); + + buffer(); + + buffer(void* p, std::size_t s, destructor_t d); + buffer(void* p, std::size_t s, destructor_t d, void* additional); + buffer(void* p, std::size_t s); + + template + explicit buffer(byte_t const (& data)[N]) + : buffer(data, sizeof(data)) { + } + explicit buffer(char const & c); + + buffer(buffer&& rhs); + ~buffer(); + + void swap(buffer& rhs); + buffer& operator=(buffer rhs); + + bool empty() const noexcept; + + void * data() noexcept; + void const * data() const noexcept; + + template + T get() const { return T(data()); } + + std::size_t size() const noexcept; + + std::tuple to_tuple() { + return std::make_tuple(data(), size()); + } + + std::tuple to_tuple() const { + return std::make_tuple(data(), size()); + } + + std::vector to_vector() const { + return { + get(), + get() + size() + }; + } + + friend bool operator==(buffer const & b1, buffer const & b2); + friend bool operator!=(buffer const & b1, buffer const & b2); + +private: + class buffer_; + buffer_* p_; +}; + +} // namespace ipc diff --git a/src/Ipc/libipc/circ/elem_array.h b/src/Ipc/libipc/circ/elem_array.h new file mode 100644 index 0000000..0759613 --- /dev/null +++ b/src/Ipc/libipc/circ/elem_array.h @@ -0,0 +1,141 @@ +#pragma once + +#include // std::atomic +#include +#include +#include + +#include "libipc/def.h" +#include "libipc/rw_lock.h" + +#include "libipc/circ/elem_def.h" +#include "libipc/platform/detail.h" + +namespace ipc { +namespace circ { + +template +class elem_array : public ipc::circ::conn_head { +public: + using base_t = ipc::circ::conn_head; + using policy_t = Policy; + using cursor_t = decltype(std::declval().cursor()); + using elem_t = typename policy_t::template elem_t; + + enum : std::size_t { + head_size = sizeof(base_t) + sizeof(policy_t), + data_size = DataSize, + elem_max = (std::numeric_limits>::max)() + 1, // default is 255 + 1 + elem_size = sizeof(elem_t), + block_size = elem_size * elem_max + }; + +private: + policy_t head_; + elem_t block_[elem_max] {}; + + /** + * \remarks 'warning C4348: redefinition of default parameter' with MSVC. + * \see + * - https://stackoverflow.com/questions/12656239/redefinition-of-default-template-parameter + * - https://developercommunity.visualstudio.com/content/problem/425978/incorrect-c4348-warning-in-nested-template-declara.html + */ + template ::is_multi_producer*/> + struct sender_checker; + + template + struct sender_checker { + constexpr static bool connect() noexcept { + // always return true + return true; + } + constexpr static void disconnect() noexcept {} + }; + + template + struct sender_checker { + bool connect() noexcept { + return !flag_.test_and_set(std::memory_order_acq_rel); + } + void disconnect() noexcept { + flag_.clear(); + } + + private: + // in shm, it should be 0 whether it's initialized or not. + std::atomic_flag flag_ = ATOMIC_FLAG_INIT; + }; + + template ::is_multi_consumer*/> + struct receiver_checker; + + template + struct receiver_checker { + constexpr static cc_t connect(base_t &conn) noexcept { + return conn.connect(); + } + constexpr static cc_t disconnect(base_t &conn, cc_t cc_id) noexcept { + return conn.disconnect(cc_id); + } + }; + + template + struct receiver_checker : protected sender_checker { + cc_t connect(base_t &conn) noexcept { + return sender_checker::connect() ? conn.connect() : 0; + } + cc_t disconnect(base_t &conn, cc_t cc_id) noexcept { + sender_checker::disconnect(); + return conn.disconnect(cc_id); + } + }; + + sender_checker ::is_multi_producer> s_ckr_; + receiver_checker::is_multi_consumer> r_ckr_; + + // make these be private + using base_t::connect; + using base_t::disconnect; + +public: + bool connect_sender() noexcept { + return s_ckr_.connect(); + } + + void disconnect_sender() noexcept { + return s_ckr_.disconnect(); + } + + cc_t connect_receiver() noexcept { + return r_ckr_.connect(*this); + } + + cc_t disconnect_receiver(cc_t cc_id) noexcept { + return r_ckr_.disconnect(*this, cc_id); + } + + cursor_t cursor() const noexcept { + return head_.cursor(); + } + + template + bool push(Q* que, F&& f) { + return head_.push(que, std::forward(f), block_); + } + + template + bool force_push(Q* que, F&& f) { + return head_.force_push(que, std::forward(f), block_); + } + + template + bool pop(Q* que, cursor_t* cur, F&& f, R&& out) { + if (cur == nullptr) return false; + return head_.pop(que, *cur, std::forward(f), std::forward(out), block_); + } +}; + +} // namespace circ +} // namespace ipc diff --git a/src/Ipc/libipc/circ/elem_def.h b/src/Ipc/libipc/circ/elem_def.h new file mode 100644 index 0000000..4fd5797 --- /dev/null +++ b/src/Ipc/libipc/circ/elem_def.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include + +#include "libipc/def.h" +#include "libipc/rw_lock.h" + +#include "libipc/platform/detail.h" + +namespace ipc { +namespace circ { + +using u1_t = ipc::uint_t<8>; +using u2_t = ipc::uint_t<32>; + +/** only supports max 32 connections in broadcast mode */ +using cc_t = u2_t; + +constexpr u1_t index_of(u2_t c) noexcept { + return static_cast(c); +} + +class conn_head_base { +protected: + std::atomic cc_{0}; // connections + ipc::spin_lock lc_; + std::atomic constructed_{false}; + +public: + void init() { + /* DCLP */ + if (!constructed_.load(std::memory_order_acquire)) { + IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lc_); + if (!constructed_.load(std::memory_order_relaxed)) { + ::new (this) conn_head_base; + constructed_.store(true, std::memory_order_release); + } + } + } + + conn_head_base() = default; + conn_head_base(conn_head_base const &) = delete; + conn_head_base &operator=(conn_head_base const &) = delete; + + cc_t connections(std::memory_order order = std::memory_order_acquire) const noexcept { + return this->cc_.load(order); + } +}; + +template ::is_broadcast> +class conn_head; + +template +class conn_head : public conn_head_base { +public: + cc_t connect() noexcept { + for (unsigned k = 0;; ipc::yield(k)) { + cc_t curr = this->cc_.load(std::memory_order_acquire); + cc_t next = curr | (curr + 1); // find the first 0, and set it to 1. + if (next == 0) { + // connection-slot is full. + return 0; + } + if (this->cc_.compare_exchange_weak(curr, next, std::memory_order_release)) { + return next ^ curr; // return connected id + } + } + } + + cc_t disconnect(cc_t cc_id) noexcept { + return this->cc_.fetch_and(~cc_id, std::memory_order_acq_rel) & ~cc_id; + } + + std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept { + cc_t cur = this->cc_.load(order); + cc_t cnt; // accumulates the total bits set in cc + for (cnt = 0; cur; ++cnt) cur &= cur - 1; + return cnt; + } +}; + +template +class conn_head : public conn_head_base { +public: + cc_t connect() noexcept { + return this->cc_.fetch_add(1, std::memory_order_relaxed) + 1; + } + + cc_t disconnect(cc_t cc_id) noexcept { + if (cc_id == ~static_cast(0u)) { + // clear all connections + this->cc_.store(0, std::memory_order_relaxed); + return 0u; + } + else { + return this->cc_.fetch_sub(1, std::memory_order_relaxed) - 1; + } + } + + std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept { + return this->connections(order); + } +}; + +} // namespace circ +} // namespace ipc diff --git a/src/Ipc/libipc/condition.h b/src/Ipc/libipc/condition.h new file mode 100644 index 0000000..2191f2d --- /dev/null +++ b/src/Ipc/libipc/condition.h @@ -0,0 +1,38 @@ +#pragma once + +#include // std::uint64_t + +#include "libipc/def.h" +#include "libipc/mutex.h" + +namespace ipc { +namespace sync { + +class condition { + condition(condition const &) = delete; + condition &operator=(condition const &) = delete; + +public: + condition(); + explicit condition(char const *name); + ~condition(); + + void const *native() const noexcept; + void *native() noexcept; + + bool valid() const noexcept; + + bool open(char const *name) noexcept; + void close() noexcept; + + bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept; + bool notify(ipc::sync::mutex &mtx) noexcept; + bool broadcast(ipc::sync::mutex &mtx) noexcept; + +private: + class condition_; + condition_* p_; +}; + +} // namespace sync +} // namespace ipc diff --git a/src/Ipc/libipc/def.h b/src/Ipc/libipc/def.h new file mode 100644 index 0000000..45cd780 --- /dev/null +++ b/src/Ipc/libipc/def.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include // std::numeric_limits +#include +#include + +namespace ipc { + +// types + +using byte_t = std::uint8_t; + +template +struct uint; + +template <> struct uint<8 > { using type = std::uint8_t ; }; +template <> struct uint<16> { using type = std::uint16_t; }; +template <> struct uint<32> { using type = std::uint32_t; }; +template <> struct uint<64> { using type = std::uint64_t; }; + +template +using uint_t = typename uint::type; + +// constants + +enum : std::uint32_t { + invalid_value = (std::numeric_limits::max)(), + default_timeout = 100, // ms +}; + +enum : std::size_t { + data_length = 64, + large_msg_limit = data_length, + large_msg_align = 1024, + large_msg_cache = 32, +}; + +enum class relat { // multiplicity of the relationship + single, + multi +}; + +enum class trans { // transmission + unicast, + broadcast +}; + +// producer-consumer policy flag + +template +struct wr {}; + +template +struct relat_trait; + +template +struct relat_trait> { + constexpr static bool is_multi_producer = (Rp == relat::multi); + constexpr static bool is_multi_consumer = (Rc == relat::multi); + constexpr static bool is_broadcast = (Ts == trans::broadcast); +}; + +template