This commit is contained in:
jiegeaiai 2024-11-27 01:43:42 +08:00
parent 4dddf79158
commit 8082b9b003
37 changed files with 1128 additions and 0 deletions

31
ipc.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32002.261
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipc", "ipc\ipc.vcxproj", "{439884C2-9C07-434F-8B84-B51378F4A83E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{439884C2-9C07-434F-8B84-B51378F4A83E}.Debug|x64.ActiveCfg = Debug|x64
{439884C2-9C07-434F-8B84-B51378F4A83E}.Debug|x64.Build.0 = Debug|x64
{439884C2-9C07-434F-8B84-B51378F4A83E}.Debug|x86.ActiveCfg = Debug|Win32
{439884C2-9C07-434F-8B84-B51378F4A83E}.Debug|x86.Build.0 = Debug|Win32
{439884C2-9C07-434F-8B84-B51378F4A83E}.Release|x64.ActiveCfg = Release|x64
{439884C2-9C07-434F-8B84-B51378F4A83E}.Release|x64.Build.0 = Release|x64
{439884C2-9C07-434F-8B84-B51378F4A83E}.Release|x86.ActiveCfg = Release|Win32
{439884C2-9C07-434F-8B84-B51378F4A83E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E136A803-5D70-4B88-B6DD-063E35B4710E}
EndGlobalSection
EndGlobal

68
ipc/3rdparty/include/libipc/buffer.h vendored Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <cstddef>
#include <tuple>
#include <vector>
#include <type_traits>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
class IPC_EXPORT 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 <std::size_t N>
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 <typename T>
T get() const { return T(data()); }
std::size_t size() const noexcept;
std::tuple<void*, std::size_t> to_tuple() {
return std::make_tuple(data(), size());
}
std::tuple<void const *, std::size_t> to_tuple() const {
return std::make_tuple(data(), size());
}
std::vector<byte_t> to_vector() const {
return {
get<byte_t const *>(),
get<byte_t const *>() + size()
};
}
friend IPC_EXPORT bool operator==(buffer const & b1, buffer const & b2);
friend IPC_EXPORT bool operator!=(buffer const & b1, buffer const & b2);
private:
class buffer_;
buffer_* p_;
};
} // namespace ipc

39
ipc/3rdparty/include/libipc/condition.h vendored Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint> // std::uint64_t
#include "libipc/export.h"
#include "libipc/def.h"
#include "libipc/mutex.h"
namespace ipc {
namespace sync {
class IPC_EXPORT 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() noexcept;
bool broadcast() noexcept;
private:
class condition_;
condition_* p_;
};
} // namespace sync
} // namespace ipc

68
ipc/3rdparty/include/libipc/def.h vendored Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <limits> // std::numeric_limits
#include <new>
#include <utility>
namespace ipc {
// types
using byte_t = std::uint8_t;
template <std::size_t N>
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 <std::size_t N>
using uint_t = typename uint<N>::type;
// constants
enum : std::uint32_t {
invalid_value = (std::numeric_limits<std::uint32_t>::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 <relat Rp, relat Rc, trans Ts>
struct wr {};
template <typename WR>
struct relat_trait;
template <relat Rp, relat Rc, trans Ts>
struct relat_trait<wr<Rp, Rc, Ts>> {
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 <template <typename> class Policy, typename Flag>
struct relat_trait<Policy<Flag>> : relat_trait<Flag> {};
} // namespace ipc

54
ipc/3rdparty/include/libipc/export.h vendored Normal file
View File

@ -0,0 +1,54 @@
#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*/

192
ipc/3rdparty/include/libipc/ipc.h vendored Normal file
View File

@ -0,0 +1,192 @@
#pragma once
#include <string>
#include "libipc/export.h"
#include "libipc/def.h"
#include "libipc/buffer.h"
#include "libipc/shm.h"
namespace ipc {
using handle_t = void*;
using buff_t = buffer;
enum : unsigned {
sender,
receiver
};
template <typename Flag>
struct IPC_EXPORT chan_impl {
static bool connect (ipc::handle_t * ph, char const * name, unsigned mode);
static bool reconnect (ipc::handle_t * ph, unsigned mode);
static void disconnect(ipc::handle_t h);
static void destroy (ipc::handle_t h);
static char const * name(ipc::handle_t h);
static std::size_t recv_count(ipc::handle_t h);
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm);
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
static buff_t recv(ipc::handle_t h, std::uint64_t tm);
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
static buff_t try_recv(ipc::handle_t h);
};
template <typename Flag>
class chan_wrapper {
private:
using detail_t = chan_impl<Flag>;
ipc::handle_t h_ = nullptr;
unsigned mode_ = ipc::sender;
bool connected_ = false;
public:
chan_wrapper() noexcept = default;
explicit chan_wrapper(char const * name, unsigned mode = ipc::sender)
: connected_{this->connect(name, mode)} {
}
chan_wrapper(chan_wrapper&& rhs) noexcept
: chan_wrapper{} {
swap(rhs);
}
~chan_wrapper() {
detail_t::destroy(h_);
}
void swap(chan_wrapper& rhs) noexcept {
std::swap(h_ , rhs.h_);
std::swap(mode_ , rhs.mode_);
std::swap(connected_, rhs.connected_);
}
chan_wrapper& operator=(chan_wrapper rhs) noexcept {
swap(rhs);
return *this;
}
char const * name() const noexcept {
return detail_t::name(h_);
}
ipc::handle_t handle() const noexcept {
return h_;
}
bool valid() const noexcept {
return (handle() != nullptr);
}
unsigned mode() const noexcept {
return mode_;
}
chan_wrapper clone() const {
return chan_wrapper { name(), mode_ };
}
/**
* Building handle, then try connecting with name & mode flags.
*/
bool connect(char const * name, unsigned mode = ipc::sender | ipc::receiver) {
if (name == nullptr || name[0] == '\0') return false;
detail_t::disconnect(h_); // clear old connection
return connected_ = detail_t::connect(&h_, name, mode_ = mode);
}
/**
* Try connecting with new mode flags.
*/
bool reconnect(unsigned mode) {
if (!valid()) return false;
if (connected_ && (mode_ == mode)) return true;
return connected_ = detail_t::reconnect(&h_, mode_ = mode);
}
void disconnect() {
if (!valid()) return;
detail_t::disconnect(h_);
connected_ = false;
}
std::size_t recv_count() const {
return detail_t::recv_count(h_);
}
bool wait_for_recv(std::size_t r_count, std::uint64_t tm = invalid_value) const {
return detail_t::wait_for_recv(h_, r_count, tm);
}
static bool wait_for_recv(char const * name, std::size_t r_count, std::uint64_t tm = invalid_value) {
return chan_wrapper(name).wait_for_recv(r_count, tm);
}
/**
* If timeout, this function would call 'force_push' to send the data forcibly.
*/
bool send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
return detail_t::send(h_, data, size, tm);
}
bool send(buff_t const & buff, std::uint64_t tm = default_timeout) {
return this->send(buff.data(), buff.size(), tm);
}
bool send(std::string const & str, std::uint64_t tm = default_timeout) {
return this->send(str.c_str(), str.size() + 1, tm);
}
/**
* If timeout, this function would just return false.
*/
bool try_send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
return detail_t::try_send(h_, data, size, tm);
}
bool try_send(buff_t const & buff, std::uint64_t tm = default_timeout) {
return this->try_send(buff.data(), buff.size(), tm);
}
bool try_send(std::string const & str, std::uint64_t tm = default_timeout) {
return this->try_send(str.c_str(), str.size() + 1, tm);
}
buff_t recv(std::uint64_t tm = invalid_value) {
return detail_t::recv(h_, tm);
}
buff_t try_recv() {
return detail_t::try_recv(h_);
}
};
template <relat Rp, relat Rc, trans Ts>
using chan = chan_wrapper<ipc::wr<Rp, Rc, Ts>>;
/**
* class route
*
* You could use one producer/server/sender for sending messages to a route,
* then all the consumers/clients/receivers which are receiving with this route,
* would receive your sent messages.
*
* A route could only be used in 1 to N
* (one producer/writer to multi consumers/readers)
*/
using route = chan<relat::single, relat::multi, trans::broadcast>;
/**
* class channel
*
* You could use multi producers/writers for sending messages to a channel,
* then all the consumers/readers which are receiving with this channel,
* would receive your sent messages.
*/
using channel = chan<relat::multi, relat::multi, trans::broadcast>;
} // namespace ipc

39
ipc/3rdparty/include/libipc/mutex.h vendored Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint> // std::uint64_t
#include <system_error>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace sync {
class IPC_EXPORT mutex {
mutex(mutex const &) = delete;
mutex &operator=(mutex const &) = delete;
public:
mutex();
explicit mutex(char const *name);
~mutex();
void const *native() const noexcept;
void *native() noexcept;
bool valid() const noexcept;
bool open(char const *name) noexcept;
void close() noexcept;
bool lock(std::uint64_t tm = ipc::invalid_value) noexcept;
bool try_lock() noexcept(false); // std::system_error
bool unlock() noexcept;
private:
class mutex_;
mutex_* p_;
};
} // namespace sync
} // namespace ipc

103
ipc/3rdparty/include/libipc/pool_alloc.h vendored Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#include <new>
#include <utility>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace mem {
class IPC_EXPORT pool_alloc {
public:
static void* alloc(std::size_t size);
static void free (void* p, std::size_t size);
};
////////////////////////////////////////////////////////////////
/// construct/destruct an object
////////////////////////////////////////////////////////////////
namespace detail {
template <typename T>
struct impl {
template <typename... P>
static T* construct(T* p, P&&... params) {
::new (p) T(std::forward<P>(params)...);
return p;
}
static void destruct(T* p) {
reinterpret_cast<T*>(p)->~T();
}
};
template <typename T, size_t N>
struct impl<T[N]> {
using type = T[N];
template <typename... P>
static type* construct(type* p, P&&... params) {
for (size_t i = 0; i < N; ++i) {
impl<T>::construct(&((*p)[i]), std::forward<P>(params)...);
}
return p;
}
static void destruct(type* p) {
for (size_t i = 0; i < N; ++i) {
impl<T>::destruct(&((*p)[i]));
}
}
};
} // namespace detail
template <typename T, typename... P>
T* construct(T* p, P&&... params) {
return detail::impl<T>::construct(p, std::forward<P>(params)...);
}
template <typename T, typename... P>
T* construct(void* p, P&&... params) {
return construct(static_cast<T*>(p), std::forward<P>(params)...);
}
template <typename T>
void destruct(T* p) {
return detail::impl<T>::destruct(p);
}
template <typename T>
void destruct(void* p) {
destruct(static_cast<T*>(p));
}
////////////////////////////////////////////////////////////////
/// general alloc/free
////////////////////////////////////////////////////////////////
inline void* alloc(std::size_t size) {
return pool_alloc::alloc(size);
}
template <typename T, typename... P>
T* alloc(P&&... params) {
return construct<T>(pool_alloc::alloc(sizeof(T)), std::forward<P>(params)...);
}
inline void free(void* p, std::size_t size) {
pool_alloc::free(p, size);
}
template <typename T>
void free(T* p) {
if (p == nullptr) return;
destruct(p);
pool_alloc::free(p, sizeof(T));
}
} // namespace mem
} // namespace ipc

171
ipc/3rdparty/include/libipc/rw_lock.h vendored Normal file
View File

@ -0,0 +1,171 @@
#pragma once
#include <atomic>
#include <thread>
#include <chrono>
#include <limits>
#include <type_traits>
#include <utility>
////////////////////////////////////////////////////////////////
/// Gives hint to processor that improves performance of spin-wait loops.
////////////////////////////////////////////////////////////////
#pragma push_macro("IPC_LOCK_PAUSE_")
#undef IPC_LOCK_PAUSE_
#if defined(_MSC_VER)
#include <windows.h> // YieldProcessor
/*
See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687419(v=vs.85).aspx
Not for intel c++ compiler, so ignore http://software.intel.com/en-us/forums/topic/296168
*/
# define IPC_LOCK_PAUSE_() YieldProcessor()
#elif defined(__GNUC__)
#if defined(__i386__) || defined(__x86_64__)
/*
See: Intel(R) 64 and IA-32 Architectures Software Developer's Manual V2
PAUSE-Spin Loop Hint, 4-57
http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.html?wapkw=instruction+set+reference
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__("pause")
#elif defined(__ia64__) || defined(__ia64)
/*
See: Intel(R) Itanium(R) Architecture Developer's Manual, Vol.3
hint - Performance Hint, 3:145
http://www.intel.com/content/www/us/en/processors/itanium/itanium-architecture-vol-3-manual.html
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("hint @pause")
#elif defined(__arm__)
/*
See: ARM Architecture Reference Manuals (YIELD)
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("yield")
#endif
#endif/*compilers*/
#if !defined(IPC_LOCK_PAUSE_)
/*
Just use a compiler fence, prevent compiler from optimizing loop
*/
# define IPC_LOCK_PAUSE_() std::atomic_signal_fence(std::memory_order_seq_cst)
#endif/*!defined(IPC_LOCK_PAUSE_)*/
////////////////////////////////////////////////////////////////
/// Yield to other threads
////////////////////////////////////////////////////////////////
namespace ipc {
template <typename K>
inline void yield(K& k) noexcept {
if (k < 4) { /* Do nothing */ }
else
if (k < 16) { IPC_LOCK_PAUSE_(); }
else
if (k < 32) { std::this_thread::yield(); }
else {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return;
}
++k;
}
template <std::size_t N = 32, typename K, typename F>
inline void sleep(K& k, F&& f) {
if (k < static_cast<K>(N)) {
std::this_thread::yield();
}
else {
static_cast<void>(std::forward<F>(f)());
return;
}
++k;
}
template <std::size_t N = 32, typename K>
inline void sleep(K& k) {
sleep<N>(k, [] {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
});
}
} // namespace ipc
#pragma pop_macro("IPC_LOCK_PAUSE_")
namespace ipc {
class spin_lock {
std::atomic<unsigned> lc_ { 0 };
public:
void lock(void) noexcept {
for (unsigned k = 0;
lc_.exchange(1, std::memory_order_acquire);
yield(k)) ;
}
void unlock(void) noexcept {
lc_.store(0, std::memory_order_release);
}
};
class rw_lock {
using lc_ui_t = unsigned;
std::atomic<lc_ui_t> lc_ { 0 };
enum : lc_ui_t {
w_mask = (std::numeric_limits<std::make_signed_t<lc_ui_t>>::max)(), // b 0111 1111
w_flag = w_mask + 1 // b 1000 0000
};
public:
rw_lock() = default;
rw_lock(const rw_lock&) = delete;
rw_lock& operator=(const rw_lock&) = delete;
rw_lock(rw_lock&&) = delete;
rw_lock& operator=(rw_lock&&) = delete;
void lock() noexcept {
for (unsigned k = 0;;) {
auto old = lc_.fetch_or(w_flag, std::memory_order_acq_rel);
if (!old) return; // got w-lock
if (!(old & w_flag)) break; // other thread having r-lock
yield(k); // other thread having w-lock
}
// wait for reading finished
for (unsigned k = 0;
lc_.load(std::memory_order_acquire) & w_mask;
yield(k)) ;
}
void unlock() noexcept {
lc_.store(0, std::memory_order_release);
}
void lock_shared() noexcept {
auto old = lc_.load(std::memory_order_acquire);
for (unsigned k = 0;;) {
// if w_flag set, just continue
if (old & w_flag) {
yield(k);
old = lc_.load(std::memory_order_acquire);
}
// otherwise try cas lc + 1 (set r-lock)
else if (lc_.compare_exchange_weak(old, old + 1, std::memory_order_release)) {
return;
}
// set r-lock failed, old has been updated
}
}
void unlock_shared() noexcept {
lc_.fetch_sub(1, std::memory_order_release);
}
};
} // namespace ipc

37
ipc/3rdparty/include/libipc/semaphore.h vendored Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <cstdint> // std::uint64_t
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace sync {
class IPC_EXPORT semaphore {
semaphore(semaphore const &) = delete;
semaphore &operator=(semaphore const &) = delete;
public:
semaphore();
explicit semaphore(char const *name, std::uint32_t count = 0);
~semaphore();
void const *native() const noexcept;
void *native() noexcept;
bool valid() const noexcept;
bool open(char const *name, std::uint32_t count = 0) noexcept;
void close() noexcept;
bool wait(std::uint64_t tm = ipc::invalid_value) noexcept;
bool post(std::uint32_t count = 1) noexcept;
private:
class semaphore_;
semaphore_* p_;
};
} // namespace sync
} // namespace ipc

59
ipc/3rdparty/include/libipc/shm.h vendored Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include "libipc/export.h"
namespace ipc {
namespace shm {
using id_t = void*;
enum : unsigned {
create = 0x01,
open = 0x02
};
IPC_EXPORT id_t acquire(char const * name, std::size_t size, unsigned mode = create | open);
IPC_EXPORT void * get_mem(id_t id, std::size_t * size);
IPC_EXPORT std::int32_t release(id_t id);
IPC_EXPORT void remove (id_t id);
IPC_EXPORT void remove (char const * name);
IPC_EXPORT std::int32_t get_ref(id_t id);
IPC_EXPORT void sub_ref(id_t id);
class IPC_EXPORT handle {
public:
handle();
handle(char const * name, std::size_t size, unsigned mode = create | open);
handle(handle&& rhs);
~handle();
void swap(handle& rhs);
handle& operator=(handle rhs);
bool valid() const noexcept;
std::size_t size () const noexcept;
char const * name () const noexcept;
std::int32_t ref() const noexcept;
void sub_ref() noexcept;
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
std::int32_t release();
void* get() const;
void attach(id_t);
id_t detach();
private:
class handle_;
handle_* p_;
};
} // namespace shm
} // namespace ipc

BIN
ipc/3rdparty/lib/ipc.lib vendored Normal file

Binary file not shown.

BIN
ipc/3rdparty/lib/ipc_o.lib vendored Normal file

Binary file not shown.

BIN
ipc/3rdparty/lib/ipcd.lib vendored Normal file

Binary file not shown.

BIN
ipc/3rdparty/lib/ipcd.pdb vendored Normal file

Binary file not shown.

103
ipc/Ipc.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "Ipc.h"
#include <functional>
#include "ReadCallback.h"
std::shared_ptr<Ipc> Ipc::create(const char* reader_name, const char* writer_name) {
struct Creator : public Ipc {
Creator(const char* reader_name, const char* writer_name) : Ipc(reader_name, writer_name) {}
~Creator() override = default;
};
return std::make_shared<Creator>(reader_name, writer_name);
}
Ipc::Ipc(const char* reader_name, const char* writer_name) noexcept
: reader_name_(reader_name)
, writer_name_(writer_name) {
sender_ = std::make_unique<ipc::channel>(reader_name_.c_str(), ipc::sender);
printf("%s, %s", reader_name, writer_name);
}
Ipc::~Ipc() {
stop();
}
bool Ipc::listen() {
if (reciver_stop_.load(std::memory_order_acquire)) {
return false;
}
reciver_stop_.store(false);
std::weak_ptr<Ipc> wThis = shared_from_this();
reciver_thread_ = std::move(std::thread(std::bind(&Ipc::doReciver, this, wThis)));
return true;
}
void Ipc::stop() {
if (!reciver_stop_.load(std::memory_order_acquire)) {
return;
}
reciver_stop_.store(true, std::memory_order_release);
sender_->disconnect();
receiver_->disconnect();
if (reciver_thread_.joinable()) {
reciver_thread_.join();
}
}
bool Ipc::send(const char* data, unsigned int size) {
if (!sender_) {
return false;
}
return sender_->send(data, size);
}
void Ipc::registReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
std::lock_guard<std::mutex> lock(mutex_);
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
if (reader_callbacks_.end() != itor) {
return;
}
reader_callbacks_.emplace_back(reader);
}
void Ipc::unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
std::lock_guard<std::mutex> lock(mutex_);
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
if (reader_callbacks_.end() != itor) {
return;
}
reader_callbacks_.erase(itor);
}
void Ipc::doReciver(std::weak_ptr<Ipc> wThis) {
std::shared_ptr<Ipc> self(wThis.lock());
if (!self) {
return;
}
receiver_ = std::make_unique<ipc::channel>(writer_name_.c_str(), ipc::receiver);
while (!reciver_stop_.load(std::memory_order_acquire)) {
ipc::buff_t buffer = receiver_->recv();
if (buffer.empty()) {
break;
}
const char* data = buffer.get<const char*>();
onReciveer(data, static_cast<unsigned int>(buffer.size()));
}
}
void Ipc::onReciveer(const char* buffer, unsigned int size) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& read : reader_callbacks_) {
read->onRead(buffer, size);
}
}

45
ipc/Ipc.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include <thread>
#include <libipc/ipc.h>
#include <memory>
#include <atomic>
#include <string>
#include <mutex>
class IReaderCallback;
class Ipc : public std::enable_shared_from_this<Ipc>{
public:
static std::shared_ptr<Ipc> create(const char* reader_name, const char* writer_name);
public:
virtual ~Ipc();
bool listen();
void stop();
bool send(const char* data, unsigned int size);
void registReadCallback(const std::shared_ptr<IReaderCallback>& reader);
void unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader);
protected:
Ipc(const char* reader_name, const char* writer_name) noexcept;
private:
void doReciver(std::weak_ptr<Ipc> wThis);
void onReciveer(const char* buffer, unsigned int size);
private:
std::string reader_name_;
std::string writer_name_;
std::unique_ptr<ipc::channel> sender_;
std::unique_ptr<ipc::channel> receiver_;
std::thread reciver_thread_;
std::atomic_bool reciver_stop_{false};
std::mutex mutex_;
using ReaderCallbackList = std::vector<std::shared_ptr<IReaderCallback>>;
ReaderCallbackList reader_callbacks_;
};

9
ipc/ReadCallback.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class IReaderCallback {
public:
virtual ~IReaderCallback() = default;
// read thread callback
virtual void onRead(const char* buffer, unsigned int size) = 0;
};

20
ipc/include/config.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#ifdef _IPC_EXPORT_
#ifdef WIN32
#define IPC_EXPORT __declspec( dllexport )
#endif // WIN32
#else
#ifdef WIN32
#define IPC_EXPORT __declspec( dllimport )
#endif // WIN32
#endif // _IPC_EXPORT_

21
ipc/include/ipclib.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
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();
IPC_EXPORT bool __stdcall listen();
IPC_EXPORT bool __stdcall send(const char* data, unsigned int size);
IPC_EXPORT bool __stdcall setReaderCallback(ReaderCallbackFunc callback);
#ifdef __cplusplus
}
#endif // __cplusplus

69
ipc/ipclib.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "include/ipclib.h"
#include <memory>
#include <assert.h>
#include "Ipc.h"
#include "ReadCallback.h"
class ReaderCallback : public IReaderCallback {
public:
ReaderCallback() = default;
~ReaderCallback() override = default;
void onRead(const char* buffer, unsigned int size) override {
printf("%s", buffer);
if (nullptr != m_readerCallbackFunc) {
m_readerCallbackFunc(buffer, size);
}
}
void setCallback(ReaderCallbackFunc func) {
m_readerCallbackFunc = func;
}
private:
ReaderCallback(const ReaderCallback&) = delete;
ReaderCallback operator= (const ReaderCallback&) = delete;
private:
ReaderCallbackFunc m_readerCallbackFunc{nullptr};
};
std::shared_ptr<Ipc> g_ipc;
std::shared_ptr<ReaderCallback> g_readCallback;
bool __stdcall initialize(const char* sender_name, const char* receiver_name) {
assert(!g_ipc);
g_ipc = Ipc::create(sender_name, receiver_name);
return true;
}
void __stdcall uninitialize() {
assert(g_ipc);
g_ipc->stop();
if (g_readCallback) {
g_ipc->unregistReadCallback(g_readCallback);
g_readCallback.reset();
}
g_ipc.reset();
}
bool __stdcall listen() {
assert(g_ipc);
return g_ipc->listen();
}
bool __stdcall send(const char* data, unsigned int size) {
assert(g_ipc);
return g_ipc->send(data, size);
}
bool __stdcall setReaderCallback(ReaderCallbackFunc callback) {
assert(g_ipc);
if (!g_readCallback) {
g_readCallback = std::make_shared<ReaderCallback>();
g_ipc->registReadCallback(g_readCallback);
}
g_readCallback->setCallback(callback);
return true;
}

BIN
x64/Debug/ipc.dll Normal file

Binary file not shown.

BIN
x64/Debug/ipc.exp Normal file

Binary file not shown.

BIN
x64/Debug/ipc.lib Normal file

Binary file not shown.

BIN
x64/Debug/ipc.pdb Normal file

Binary file not shown.

BIN
x64/Debug/ipcd.dll Normal file

Binary file not shown.

BIN
x64/Debug/ipcd.exp Normal file

Binary file not shown.

BIN
x64/Debug/ipcd.lib Normal file

Binary file not shown.

BIN
x64/Debug/ipcd.pdb Normal file

Binary file not shown.

BIN
x64/Release/ipc.dll Normal file

Binary file not shown.

BIN
x64/Release/ipc.exp Normal file

Binary file not shown.

BIN
x64/Release/ipc.lib Normal file

Binary file not shown.

BIN
x64/Release/ipc.pdb Normal file

Binary file not shown.

BIN
x64/Release/ipc_test.dll Normal file

Binary file not shown.

BIN
x64/Release/ipc_test.exp Normal file

Binary file not shown.

BIN
x64/Release/ipc_test.lib Normal file

Binary file not shown.

BIN
x64/Release/ipc_test.pdb Normal file

Binary file not shown.