批量生成函数注释
This commit is contained in:
		
							parent
							
								
									32f36a609e
								
							
						
					
					
						commit
						77408f795e
					
				
							
								
								
									
										87
									
								
								crazy_functions/test_project/cpp/cppipc/buffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								crazy_functions/test_project/cpp/cppipc/buffer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					#include "libipc/buffer.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/pimpl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<buffer_> {
 | 
				
			||||||
 | 
					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<char*>(&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
 | 
				
			||||||
							
								
								
									
										701
									
								
								crazy_functions/test_project/cpp/cppipc/ipc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										701
									
								
								crazy_functions/test_project/cpp/cppipc/ipc.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,701 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <utility>          // std::pair, std::move, std::forward
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <type_traits>      // aligned_storage_t
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/ipc.h"
 | 
				
			||||||
 | 
					#include "libipc/def.h"
 | 
				
			||||||
 | 
					#include "libipc/shm.h"
 | 
				
			||||||
 | 
					#include "libipc/pool_alloc.h"
 | 
				
			||||||
 | 
					#include "libipc/queue.h"
 | 
				
			||||||
 | 
					#include "libipc/policy.h"
 | 
				
			||||||
 | 
					#include "libipc/rw_lock.h"
 | 
				
			||||||
 | 
					#include "libipc/waiter.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/utility/log.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/id_pool.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/scope_guard.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/utility.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/memory/resource.h"
 | 
				
			||||||
 | 
					#include "libipc/platform/detail.h"
 | 
				
			||||||
 | 
					#include "libipc/circ/elem_array.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using msg_id_t = std::uint32_t;
 | 
				
			||||||
 | 
					using acc_t    = std::atomic<msg_id_t>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					struct msg_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <std::size_t AlignSize>
 | 
				
			||||||
 | 
					struct msg_t<0, AlignSize> {
 | 
				
			||||||
 | 
					    msg_id_t     cc_id_;
 | 
				
			||||||
 | 
					    msg_id_t     id_;
 | 
				
			||||||
 | 
					    std::int32_t remain_;
 | 
				
			||||||
 | 
					    bool         storage_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					struct msg_t : msg_t<0, AlignSize> {
 | 
				
			||||||
 | 
					    std::aligned_storage_t<DataSize, AlignSize> data_ {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    msg_t() = default;
 | 
				
			||||||
 | 
					    msg_t(msg_id_t cc_id, msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
 | 
				
			||||||
 | 
					        : msg_t<0, AlignSize> {cc_id, id, remain, (data == nullptr) || (size == 0)} {
 | 
				
			||||||
 | 
					        if (this->storage_) {
 | 
				
			||||||
 | 
					            if (data != nullptr) {
 | 
				
			||||||
 | 
					                // copy storage-id
 | 
				
			||||||
 | 
					                *reinterpret_cast<ipc::storage_id_t*>(&data_) =
 | 
				
			||||||
 | 
					                     *static_cast<ipc::storage_id_t const *>(data);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else std::memcpy(&data_, data, size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					ipc::buff_t make_cache(T& data, std::size_t size) {
 | 
				
			||||||
 | 
					    auto ptr = ipc::mem::alloc(size);
 | 
				
			||||||
 | 
					    std::memcpy(ptr, &data, (ipc::detail::min)(sizeof(data), size));
 | 
				
			||||||
 | 
					    return { ptr, size, ipc::mem::free };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cache_t {
 | 
				
			||||||
 | 
					    std::size_t fill_;
 | 
				
			||||||
 | 
					    ipc::buff_t buff_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cache_t(std::size_t f, ipc::buff_t && b)
 | 
				
			||||||
 | 
					        : fill_(f), buff_(std::move(b))
 | 
				
			||||||
 | 
					    {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void append(void const * data, std::size_t size) {
 | 
				
			||||||
 | 
					        if (fill_ >= buff_.size() || data == nullptr || size == 0) return;
 | 
				
			||||||
 | 
					        auto new_fill = (ipc::detail::min)(fill_ + size, buff_.size());
 | 
				
			||||||
 | 
					        std::memcpy(static_cast<ipc::byte_t*>(buff_.data()) + fill_, data, new_fill - fill_);
 | 
				
			||||||
 | 
					        fill_ = new_fill;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto cc_acc() {
 | 
				
			||||||
 | 
					    static ipc::shm::handle acc_h("__CA_CONN__", sizeof(acc_t));
 | 
				
			||||||
 | 
					    return static_cast<acc_t*>(acc_h.get());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
 | 
				
			||||||
 | 
					    return (((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
 | 
				
			||||||
 | 
					    return ipc::make_align(alignof(std::max_align_t), align_chunk_size(
 | 
				
			||||||
 | 
					           ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>)) + size));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct chunk_t {
 | 
				
			||||||
 | 
					    std::atomic<ipc::circ::cc_t> &conns() noexcept {
 | 
				
			||||||
 | 
					        return *reinterpret_cast<std::atomic<ipc::circ::cc_t> *>(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void *data() noexcept {
 | 
				
			||||||
 | 
					        return reinterpret_cast<ipc::byte_t *>(this)
 | 
				
			||||||
 | 
					             + ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct chunk_info_t {
 | 
				
			||||||
 | 
					    ipc::id_pool<> pool_;
 | 
				
			||||||
 | 
					    ipc::spin_lock lock_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IPC_CONSTEXPR_ static std::size_t chunks_mem_size(std::size_t chunk_size) noexcept {
 | 
				
			||||||
 | 
					        return ipc::id_pool<>::max_count * chunk_size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ipc::byte_t *chunks_mem() noexcept {
 | 
				
			||||||
 | 
					        return reinterpret_cast<ipc::byte_t *>(this + 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chunk_t *at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
 | 
				
			||||||
 | 
					        if (id < 0) return nullptr;
 | 
				
			||||||
 | 
					        return reinterpret_cast<chunk_t *>(chunks_mem() + (chunk_size * id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto& chunk_storages() {
 | 
				
			||||||
 | 
					    class chunk_handle_t {
 | 
				
			||||||
 | 
					        ipc::shm::handle handle_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        chunk_info_t *get_info(std::size_t chunk_size) {
 | 
				
			||||||
 | 
					            if (!handle_.valid() &&
 | 
				
			||||||
 | 
					                !handle_.acquire( ("__CHUNK_INFO__" + ipc::to_string(chunk_size)).c_str(), 
 | 
				
			||||||
 | 
					                                  sizeof(chunk_info_t) + chunk_info_t::chunks_mem_size(chunk_size) )) {
 | 
				
			||||||
 | 
					                ipc::error("[chunk_storages] chunk_shm.id_info_.acquire failed: chunk_size = %zd\n", chunk_size);
 | 
				
			||||||
 | 
					                return nullptr;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            auto info = static_cast<chunk_info_t*>(handle_.get());
 | 
				
			||||||
 | 
					            if (info == nullptr) {
 | 
				
			||||||
 | 
					                ipc::error("[chunk_storages] chunk_shm.id_info_.get failed: chunk_size = %zd\n", chunk_size);
 | 
				
			||||||
 | 
					                return nullptr;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return info;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    static ipc::map<std::size_t, chunk_handle_t> chunk_hs;
 | 
				
			||||||
 | 
					    return chunk_hs;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
 | 
				
			||||||
 | 
					    auto &storages = chunk_storages();
 | 
				
			||||||
 | 
					    std::decay_t<decltype(storages)>::iterator it;
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        static ipc::rw_lock lock;
 | 
				
			||||||
 | 
					        IPC_UNUSED_ std::shared_lock<ipc::rw_lock> guard {lock};
 | 
				
			||||||
 | 
					        if ((it = storages.find(chunk_size)) == storages.end()) {
 | 
				
			||||||
 | 
					            using chunk_handle_t = std::decay_t<decltype(storages)>::value_type::second_type;
 | 
				
			||||||
 | 
					            guard.unlock();
 | 
				
			||||||
 | 
					            IPC_UNUSED_ std::lock_guard<ipc::rw_lock> guard {lock};
 | 
				
			||||||
 | 
					            it = storages.emplace(chunk_size, chunk_handle_t{}).first;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return it->second.get_info(chunk_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size, ipc::circ::cc_t conns) {
 | 
				
			||||||
 | 
					    std::size_t chunk_size = calc_chunk_size(size);
 | 
				
			||||||
 | 
					    auto info = chunk_storage_info(chunk_size);
 | 
				
			||||||
 | 
					    if (info == nullptr) return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    info->lock_.lock();
 | 
				
			||||||
 | 
					    info->pool_.prepare();
 | 
				
			||||||
 | 
					    // got an unique id
 | 
				
			||||||
 | 
					    auto id = info->pool_.acquire();
 | 
				
			||||||
 | 
					    info->lock_.unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto chunk = info->at(chunk_size, id);
 | 
				
			||||||
 | 
					    if (chunk == nullptr) return {};
 | 
				
			||||||
 | 
					    chunk->conns().store(conns, std::memory_order_relaxed);
 | 
				
			||||||
 | 
					    return { id, chunk->data() };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *find_storage(ipc::storage_id_t id, std::size_t size) {
 | 
				
			||||||
 | 
					    if (id < 0) {
 | 
				
			||||||
 | 
					        ipc::error("[find_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
 | 
				
			||||||
 | 
					        return nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::size_t chunk_size = calc_chunk_size(size);
 | 
				
			||||||
 | 
					    auto info = chunk_storage_info(chunk_size);
 | 
				
			||||||
 | 
					    if (info == nullptr) return nullptr;
 | 
				
			||||||
 | 
					    return info->at(chunk_size, id)->data();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void release_storage(ipc::storage_id_t id, std::size_t size) {
 | 
				
			||||||
 | 
					    if (id < 0) {
 | 
				
			||||||
 | 
					        ipc::error("[release_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::size_t chunk_size = calc_chunk_size(size);
 | 
				
			||||||
 | 
					    auto info = chunk_storage_info(chunk_size);
 | 
				
			||||||
 | 
					    if (info == nullptr) return;
 | 
				
			||||||
 | 
					    info->lock_.lock();
 | 
				
			||||||
 | 
					    info->pool_.release(id);
 | 
				
			||||||
 | 
					    info->lock_.unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <ipc::relat Rp, ipc::relat Rc>
 | 
				
			||||||
 | 
					bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::unicast>, 
 | 
				
			||||||
 | 
					            std::atomic<ipc::circ::cc_t> &/*conns*/, ipc::circ::cc_t /*curr_conns*/, ipc::circ::cc_t /*conn_id*/) noexcept {
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <ipc::relat Rp, ipc::relat Rc>
 | 
				
			||||||
 | 
					bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::broadcast>, 
 | 
				
			||||||
 | 
					            std::atomic<ipc::circ::cc_t> &conns, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) noexcept {
 | 
				
			||||||
 | 
					    auto last_conns = curr_conns & ~conn_id;
 | 
				
			||||||
 | 
					    for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					        auto chunk_conns  = conns.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					        if (conns.compare_exchange_weak(chunk_conns, chunk_conns & last_conns, std::memory_order_release)) {
 | 
				
			||||||
 | 
					            return (chunk_conns & last_conns) == 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ipc::yield(k);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					void recycle_storage(ipc::storage_id_t id, std::size_t size, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) {
 | 
				
			||||||
 | 
					    if (id < 0) {
 | 
				
			||||||
 | 
					        ipc::error("[recycle_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::size_t chunk_size = calc_chunk_size(size);
 | 
				
			||||||
 | 
					    auto info = chunk_storage_info(chunk_size);
 | 
				
			||||||
 | 
					    if (info == nullptr) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto chunk = info->at(chunk_size, id);
 | 
				
			||||||
 | 
					    if (chunk == nullptr) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!sub_rc(Flag{}, chunk->conns(), curr_conns, conn_id)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    info->lock_.lock();
 | 
				
			||||||
 | 
					    info->pool_.release(id);
 | 
				
			||||||
 | 
					    info->lock_.unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename MsgT>
 | 
				
			||||||
 | 
					bool clear_message(void* p) {
 | 
				
			||||||
 | 
					    auto msg = static_cast<MsgT*>(p);
 | 
				
			||||||
 | 
					    if (msg->storage_) {
 | 
				
			||||||
 | 
					        std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg->remain_;
 | 
				
			||||||
 | 
					        if (r_size <= 0) {
 | 
				
			||||||
 | 
					            ipc::error("[clear_message] invalid msg size: %d\n", (int)r_size);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        release_storage(
 | 
				
			||||||
 | 
					            *reinterpret_cast<ipc::storage_id_t*>(&msg->data_),
 | 
				
			||||||
 | 
					            static_cast<std::size_t>(r_size));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct conn_info_head {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ipc::string name_;
 | 
				
			||||||
 | 
					    msg_id_t    cc_id_; // connection-info id
 | 
				
			||||||
 | 
					    ipc::detail::waiter cc_waiter_, wt_waiter_, rd_waiter_;
 | 
				
			||||||
 | 
					    ipc::shm::handle acc_h_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conn_info_head(char const * name)
 | 
				
			||||||
 | 
					        : name_     {name}
 | 
				
			||||||
 | 
					        , cc_id_    {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)}
 | 
				
			||||||
 | 
					        , cc_waiter_{("__CC_CONN__" + name_).c_str()}
 | 
				
			||||||
 | 
					        , wt_waiter_{("__WT_CONN__" + name_).c_str()}
 | 
				
			||||||
 | 
					        , rd_waiter_{("__RD_CONN__" + name_).c_str()}
 | 
				
			||||||
 | 
					        , acc_h_    {("__AC_CONN__" + name_).c_str(), sizeof(acc_t)} {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void quit_waiting() {
 | 
				
			||||||
 | 
					        cc_waiter_.quit_waiting();
 | 
				
			||||||
 | 
					        wt_waiter_.quit_waiting();
 | 
				
			||||||
 | 
					        rd_waiter_.quit_waiting();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto acc() {
 | 
				
			||||||
 | 
					        return static_cast<acc_t*>(acc_h_.get());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& recv_cache() {
 | 
				
			||||||
 | 
					        thread_local ipc::unordered_map<msg_id_t, cache_t> tls;
 | 
				
			||||||
 | 
					        return tls;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename W, typename F>
 | 
				
			||||||
 | 
					bool wait_for(W& waiter, F&& pred, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    if (tm == 0) return !pred();
 | 
				
			||||||
 | 
					    for (unsigned k = 0; pred();) {
 | 
				
			||||||
 | 
					        bool ret = true;
 | 
				
			||||||
 | 
					        ipc::sleep(k, [&k, &ret, &waiter, &pred, tm] {
 | 
				
			||||||
 | 
					            ret = waiter.wait_if(std::forward<F>(pred), tm);
 | 
				
			||||||
 | 
					            k   = 0;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        if (!ret) return false; // timeout or fail
 | 
				
			||||||
 | 
					        if (k == 0) break; // k has been reset
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Policy,
 | 
				
			||||||
 | 
					          std::size_t DataSize  = ipc::data_length,
 | 
				
			||||||
 | 
					          std::size_t AlignSize = (ipc::detail::min)(DataSize, alignof(std::max_align_t))>
 | 
				
			||||||
 | 
					struct queue_generator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using queue_t = ipc::queue<msg_t<DataSize, AlignSize>, Policy>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct conn_info_t : conn_info_head {
 | 
				
			||||||
 | 
					        queue_t que_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn_info_t(char const * name)
 | 
				
			||||||
 | 
					            : conn_info_head{name}
 | 
				
			||||||
 | 
					            , que_{("__QU_CONN__" +
 | 
				
			||||||
 | 
					                    ipc::to_string(DataSize) + "__" +
 | 
				
			||||||
 | 
					                    ipc::to_string(AlignSize) + "__" + name).c_str()} {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void disconnect_receiver() {
 | 
				
			||||||
 | 
					            bool dis = que_.disconnect();
 | 
				
			||||||
 | 
					            this->quit_waiting();
 | 
				
			||||||
 | 
					            if (dis) {
 | 
				
			||||||
 | 
					                this->recv_cache().clear();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Policy>
 | 
				
			||||||
 | 
					struct detail_impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using policy_t    = Policy;
 | 
				
			||||||
 | 
					using flag_t      = typename policy_t::flag_t;
 | 
				
			||||||
 | 
					using queue_t     = typename queue_generator<policy_t>::queue_t;
 | 
				
			||||||
 | 
					using conn_info_t = typename queue_generator<policy_t>::conn_info_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr static conn_info_t* info_of(ipc::handle_t h) noexcept {
 | 
				
			||||||
 | 
					    return static_cast<conn_info_t*>(h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr static queue_t* queue_of(ipc::handle_t h) noexcept {
 | 
				
			||||||
 | 
					    return (info_of(h) == nullptr) ? nullptr : &(info_of(h)->que_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* API implementations */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void disconnect(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    auto que = queue_of(h);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    que->shut_sending();
 | 
				
			||||||
 | 
					    assert(info_of(h) != nullptr);
 | 
				
			||||||
 | 
					    info_of(h)->disconnect_receiver();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool reconnect(ipc::handle_t * ph, bool start_to_recv) {
 | 
				
			||||||
 | 
					    assert(ph != nullptr);
 | 
				
			||||||
 | 
					    assert(*ph != nullptr);
 | 
				
			||||||
 | 
					    auto que = queue_of(*ph);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (start_to_recv) {
 | 
				
			||||||
 | 
					        que->shut_sending();
 | 
				
			||||||
 | 
					        if (que->connect()) { // wouldn't connect twice
 | 
				
			||||||
 | 
					            info_of(*ph)->cc_waiter_.broadcast();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // start_to_recv == false
 | 
				
			||||||
 | 
					    if (que->connected()) {
 | 
				
			||||||
 | 
					        info_of(*ph)->disconnect_receiver();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return que->ready_sending();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool connect(ipc::handle_t * ph, char const * name, bool start_to_recv) {
 | 
				
			||||||
 | 
					    assert(ph != nullptr);
 | 
				
			||||||
 | 
					    if (*ph == nullptr) {
 | 
				
			||||||
 | 
					        *ph = ipc::mem::alloc<conn_info_t>(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return reconnect(ph, start_to_recv);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    disconnect(h);
 | 
				
			||||||
 | 
					    ipc::mem::free(info_of(h));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static std::size_t recv_count(ipc::handle_t h) noexcept {
 | 
				
			||||||
 | 
					    auto que = queue_of(h);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        return ipc::invalid_value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return que->conn_count();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    auto que = queue_of(h);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return wait_for(info_of(h)->cc_waiter_, [que, r_count] {
 | 
				
			||||||
 | 
					        return que->conn_count() < r_count;
 | 
				
			||||||
 | 
					    }, tm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename F>
 | 
				
			||||||
 | 
					static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t size) {
 | 
				
			||||||
 | 
					    if (data == nullptr || size == 0) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send(%p, %zd)\n", data, size);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    auto que = queue_of(h);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send, queue_of(h) == nullptr\n");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (que->elems() == nullptr) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send, queue_of(h)->elems() == nullptr\n");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!que->ready_sending()) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send, que->ready_sending() == false\n");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ipc::circ::cc_t conns = que->elems()->connections(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					    if (conns == 0) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send, there is no receiver on this connection.\n");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // calc a new message id
 | 
				
			||||||
 | 
					    auto acc = info_of(h)->acc();
 | 
				
			||||||
 | 
					    if (acc == nullptr) {
 | 
				
			||||||
 | 
					        ipc::error("fail: send, info_of(h)->acc() == nullptr\n");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    auto msg_id   = acc->fetch_add(1, std::memory_order_relaxed);
 | 
				
			||||||
 | 
					    auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
 | 
				
			||||||
 | 
					    if (size > ipc::large_msg_limit) {
 | 
				
			||||||
 | 
					        auto   dat = acquire_storage(size, conns);
 | 
				
			||||||
 | 
					        void * buf = dat.second;
 | 
				
			||||||
 | 
					        if (buf != nullptr) {
 | 
				
			||||||
 | 
					            std::memcpy(buf, data, size);
 | 
				
			||||||
 | 
					            return try_push(static_cast<std::int32_t>(size) - 
 | 
				
			||||||
 | 
					                            static_cast<std::int32_t>(ipc::data_length), &(dat.first), 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // try using message fragment
 | 
				
			||||||
 | 
					        //ipc::log("fail: shm::handle for big message. msg_id: %zd, size: %zd\n", msg_id, size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // push message fragment
 | 
				
			||||||
 | 
					    std::int32_t offset = 0;
 | 
				
			||||||
 | 
					    for (std::int32_t i = 0; i < static_cast<std::int32_t>(size / ipc::data_length); ++i, offset += ipc::data_length) {
 | 
				
			||||||
 | 
					        if (!try_push(static_cast<std::int32_t>(size) - offset - static_cast<std::int32_t>(ipc::data_length),
 | 
				
			||||||
 | 
					                      static_cast<ipc::byte_t const *>(data) + offset, ipc::data_length)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // if remain > 0, this is the last message fragment
 | 
				
			||||||
 | 
					    std::int32_t remain = static_cast<std::int32_t>(size) - offset;
 | 
				
			||||||
 | 
					    if (remain > 0) {
 | 
				
			||||||
 | 
					        if (!try_push(remain - static_cast<std::int32_t>(ipc::data_length),
 | 
				
			||||||
 | 
					                      static_cast<ipc::byte_t const *>(data) + offset, 
 | 
				
			||||||
 | 
					                      static_cast<std::size_t>(remain))) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return send([tm](auto info, auto que, auto msg_id) {
 | 
				
			||||||
 | 
					        return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
 | 
				
			||||||
 | 
					            if (!wait_for(info->wt_waiter_, [&] {
 | 
				
			||||||
 | 
					                    return !que->push(
 | 
				
			||||||
 | 
					                        [](void*) { return true; },
 | 
				
			||||||
 | 
					                        info->cc_id_, msg_id, remain, data, size);
 | 
				
			||||||
 | 
					                }, tm)) {
 | 
				
			||||||
 | 
					                ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
 | 
				
			||||||
 | 
					                if (!que->force_push(
 | 
				
			||||||
 | 
					                        clear_message<typename queue_t::value_t>,
 | 
				
			||||||
 | 
					                        info->cc_id_, msg_id, remain, data, size)) {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            info->rd_waiter_.broadcast();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }, h, data, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return send([tm](auto info, auto que, auto msg_id) {
 | 
				
			||||||
 | 
					        return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
 | 
				
			||||||
 | 
					            if (!wait_for(info->wt_waiter_, [&] {
 | 
				
			||||||
 | 
					                    return !que->push(
 | 
				
			||||||
 | 
					                        [](void*) { return true; },
 | 
				
			||||||
 | 
					                        info->cc_id_, msg_id, remain, data, size);
 | 
				
			||||||
 | 
					                }, tm)) {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            info->rd_waiter_.broadcast();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }, h, data, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    auto que = queue_of(h);
 | 
				
			||||||
 | 
					    if (que == nullptr) {
 | 
				
			||||||
 | 
					        ipc::error("fail: recv, queue_of(h) == nullptr\n");
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!que->connected()) {
 | 
				
			||||||
 | 
					        // hasn't connected yet, just return.
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    auto& rc = info_of(h)->recv_cache();
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        // pop a new message
 | 
				
			||||||
 | 
					        typename queue_t::value_t msg;
 | 
				
			||||||
 | 
					        if (!wait_for(info_of(h)->rd_waiter_, [que, &msg] {
 | 
				
			||||||
 | 
					                return !que->pop(msg);
 | 
				
			||||||
 | 
					            }, tm)) {
 | 
				
			||||||
 | 
					            // pop failed, just return.
 | 
				
			||||||
 | 
					            return {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        info_of(h)->wt_waiter_.broadcast();
 | 
				
			||||||
 | 
					        if ((info_of(h)->acc() != nullptr) && (msg.cc_id_ == info_of(h)->cc_id_)) {
 | 
				
			||||||
 | 
					            continue; // ignore message to self
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // msg.remain_ may minus & abs(msg.remain_) < data_length
 | 
				
			||||||
 | 
					        std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg.remain_;
 | 
				
			||||||
 | 
					        if (r_size <= 0) {
 | 
				
			||||||
 | 
					            ipc::error("fail: recv, r_size = %d\n", (int)r_size);
 | 
				
			||||||
 | 
					            return {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::size_t msg_size = static_cast<std::size_t>(r_size);
 | 
				
			||||||
 | 
					        // large message
 | 
				
			||||||
 | 
					        if (msg.storage_) {
 | 
				
			||||||
 | 
					            ipc::storage_id_t buf_id = *reinterpret_cast<ipc::storage_id_t*>(&msg.data_);
 | 
				
			||||||
 | 
					            void* buf = find_storage(buf_id, msg_size);
 | 
				
			||||||
 | 
					            if (buf != nullptr) {
 | 
				
			||||||
 | 
					                struct recycle_t {
 | 
				
			||||||
 | 
					                    ipc::storage_id_t storage_id;
 | 
				
			||||||
 | 
					                    ipc::circ::cc_t   curr_conns;
 | 
				
			||||||
 | 
					                    ipc::circ::cc_t   conn_id;
 | 
				
			||||||
 | 
					                } *r_info = ipc::mem::alloc<recycle_t>(recycle_t{
 | 
				
			||||||
 | 
					                    buf_id, que->elems()->connections(std::memory_order_relaxed), que->connected_id()
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                if (r_info == nullptr) {
 | 
				
			||||||
 | 
					                    ipc::log("fail: ipc::mem::alloc<recycle_t>.\n");
 | 
				
			||||||
 | 
					                    return ipc::buff_t{buf, msg_size}; // no recycle
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return ipc::buff_t{buf, msg_size, [](void* p_info, std::size_t size) {
 | 
				
			||||||
 | 
					                        auto r_info = static_cast<recycle_t *>(p_info);
 | 
				
			||||||
 | 
					                        IPC_UNUSED_ auto finally = ipc::guard([r_info] {
 | 
				
			||||||
 | 
					                            ipc::mem::free(r_info);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                        recycle_storage<flag_t>(r_info->storage_id, size, r_info->curr_conns, r_info->conn_id);
 | 
				
			||||||
 | 
					                    }, r_info};
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ipc::log("fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // find cache with msg.id_
 | 
				
			||||||
 | 
					        auto cac_it = rc.find(msg.id_);
 | 
				
			||||||
 | 
					        if (cac_it == rc.end()) {
 | 
				
			||||||
 | 
					            if (msg_size <= ipc::data_length) {
 | 
				
			||||||
 | 
					                return make_cache(msg.data_, msg_size);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // gc
 | 
				
			||||||
 | 
					            if (rc.size() > 1024) {
 | 
				
			||||||
 | 
					                std::vector<msg_id_t> need_del;
 | 
				
			||||||
 | 
					                for (auto const & pair : rc) {
 | 
				
			||||||
 | 
					                    auto cmp = std::minmax(msg.id_, pair.first);
 | 
				
			||||||
 | 
					                    if (cmp.second - cmp.first > 8192) {
 | 
				
			||||||
 | 
					                        need_del.push_back(pair.first);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                for (auto id : need_del) rc.erase(id);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // cache the first message fragment
 | 
				
			||||||
 | 
					            rc.emplace(msg.id_, cache_t { ipc::data_length, make_cache(msg.data_, msg_size) });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // has cached before this message
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            auto& cac = cac_it->second;
 | 
				
			||||||
 | 
					            // this is the last message fragment
 | 
				
			||||||
 | 
					            if (msg.remain_ <= 0) {
 | 
				
			||||||
 | 
					                cac.append(&(msg.data_), msg_size);
 | 
				
			||||||
 | 
					                // finish this message, erase it from cache
 | 
				
			||||||
 | 
					                auto buff = std::move(cac.buff_);
 | 
				
			||||||
 | 
					                rc.erase(cac_it);
 | 
				
			||||||
 | 
					                return buff;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // there are remain datas after this message
 | 
				
			||||||
 | 
					            cac.append(&(msg.data_), ipc::data_length);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ipc::buff_t try_recv(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    return recv(h, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}; // detail_impl<Policy>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					using policy_t = ipc::policy::choose<ipc::circ::elem_array, Flag>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // internal-linkage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					ipc::handle_t chan_impl<Flag>::inited() {
 | 
				
			||||||
 | 
					    ipc::detail::waiter::init();
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					bool chan_impl<Flag>::connect(ipc::handle_t * ph, char const * name, unsigned mode) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::connect(ph, name, mode & receiver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					bool chan_impl<Flag>::reconnect(ipc::handle_t * ph, unsigned mode) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::reconnect(ph, mode & receiver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					void chan_impl<Flag>::disconnect(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    detail_impl<policy_t<Flag>>::disconnect(h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					void chan_impl<Flag>::destroy(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    detail_impl<policy_t<Flag>>::destroy(h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					char const * chan_impl<Flag>::name(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    auto info = detail_impl<policy_t<Flag>>::info_of(h);
 | 
				
			||||||
 | 
					    return (info == nullptr) ? nullptr : info->name_.c_str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					std::size_t chan_impl<Flag>::recv_count(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::recv_count(h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::recv(h, tm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					buff_t chan_impl<Flag>::try_recv(ipc::handle_t h) {
 | 
				
			||||||
 | 
					    return detail_impl<policy_t<Flag>>::try_recv(h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template struct chan_impl<ipc::wr<relat::single, relat::single, trans::unicast  >>;
 | 
				
			||||||
 | 
					// template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast  >>; // TBD
 | 
				
			||||||
 | 
					// template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast  >>; // TBD
 | 
				
			||||||
 | 
					template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::broadcast>>;
 | 
				
			||||||
 | 
					template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::broadcast>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										25
									
								
								crazy_functions/test_project/cpp/cppipc/policy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								crazy_functions/test_project/cpp/cppipc/policy.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/def.h"
 | 
				
			||||||
 | 
					#include "libipc/prod_cons.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/circ/elem_array.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					namespace policy {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename, std::size_t...> class Elems, typename Flag>
 | 
				
			||||||
 | 
					struct choose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					struct choose<circ::elem_array, Flag> {
 | 
				
			||||||
 | 
					    using flag_t = Flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					    using elems_t = circ::elem_array<ipc::prod_cons_impl<flag_t>, DataSize, AlignSize>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace policy
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										17
									
								
								crazy_functions/test_project/cpp/cppipc/pool_alloc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								crazy_functions/test_project/cpp/cppipc/pool_alloc.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					#include "libipc/pool_alloc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/memory/resource.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					namespace mem {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void* pool_alloc::alloc(std::size_t size) {
 | 
				
			||||||
 | 
					    return async_pool_alloc::alloc(size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pool_alloc::free(void* p, std::size_t size) {
 | 
				
			||||||
 | 
					    async_pool_alloc::free(p, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace mem
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										433
									
								
								crazy_functions/test_project/cpp/cppipc/prod_cons.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								crazy_functions/test_project/cpp/cppipc/prod_cons.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,433 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/def.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/platform/detail.h"
 | 
				
			||||||
 | 
					#include "libipc/circ/elem_def.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/log.h"
 | 
				
			||||||
 | 
					#include "libipc/utility/utility.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					/// producer-consumer implementation
 | 
				
			||||||
 | 
					////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Flag>
 | 
				
			||||||
 | 
					struct prod_cons_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					    struct elem_t {
 | 
				
			||||||
 | 
					        std::aligned_storage_t<DataSize, AlignSize> data_ {};
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr circ::u2_t cursor() const noexcept {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool push(W* /*wrapper*/, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					        if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
 | 
				
			||||||
 | 
					            return false; // full
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(elems[cur_wt].data_));
 | 
				
			||||||
 | 
					        wt_.fetch_add(1, std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
 | 
				
			||||||
 | 
					     * So we could just disconnect all connections of receiver, and return false.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool force_push(W* wrapper, F&&, E*) {
 | 
				
			||||||
 | 
					        wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename R, typename E>
 | 
				
			||||||
 | 
					    bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
 | 
				
			||||||
 | 
					        auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					        if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
 | 
				
			||||||
 | 
					            return false; // empty
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(elems[cur_rd].data_));
 | 
				
			||||||
 | 
					        std::forward<R>(out)(true);
 | 
				
			||||||
 | 
					        rd_.fetch_add(1, std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
 | 
				
			||||||
 | 
					     : prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool force_push(W* wrapper, F&&, E*) {
 | 
				
			||||||
 | 
					        wrapper->elems()->disconnect_receiver(1);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename R, 
 | 
				
			||||||
 | 
					              template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
 | 
				
			||||||
 | 
					    bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
 | 
				
			||||||
 | 
					        byte_t buff[DS];
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            auto cur_rd = rd_.load(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (circ::index_of(cur_rd) ==
 | 
				
			||||||
 | 
					                circ::index_of(wt_.load(std::memory_order_acquire))) {
 | 
				
			||||||
 | 
					                return false; // empty
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
 | 
				
			||||||
 | 
					            if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
 | 
				
			||||||
 | 
					                std::forward<F>(f)(buff);
 | 
				
			||||||
 | 
					                std::forward<R>(out)(true);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
 | 
				
			||||||
 | 
					     : prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using flag_t = std::uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					    struct elem_t {
 | 
				
			||||||
 | 
					        std::aligned_storage_t<DataSize, AlignSize> data_ {};
 | 
				
			||||||
 | 
					        std::atomic<flag_t> f_ct_ { 0 }; // commit flag
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool push(W* /*wrapper*/, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        circ::u2_t cur_ct, nxt_ct;
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            cur_ct = ct_.load(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (circ::index_of(nxt_ct = cur_ct + 1) ==
 | 
				
			||||||
 | 
					                circ::index_of(rd_.load(std::memory_order_acquire))) {
 | 
				
			||||||
 | 
					                return false; // full
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        auto* el = elems + circ::index_of(cur_ct);
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        // set flag & try update wt
 | 
				
			||||||
 | 
					        el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
 | 
				
			||||||
 | 
					        while (1) {
 | 
				
			||||||
 | 
					            auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            if (cur_ct != wt_.load(std::memory_order_relaxed)) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ((~cac_ct) != cur_ct) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            wt_.store(nxt_ct, std::memory_order_release);
 | 
				
			||||||
 | 
					            cur_ct = nxt_ct;
 | 
				
			||||||
 | 
					            nxt_ct = cur_ct + 1;
 | 
				
			||||||
 | 
					            el = elems + circ::index_of(cur_ct);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool force_push(W* wrapper, F&&, E*) {
 | 
				
			||||||
 | 
					        wrapper->elems()->disconnect_receiver(1);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename R, 
 | 
				
			||||||
 | 
					              template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
 | 
				
			||||||
 | 
					    bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
 | 
				
			||||||
 | 
					        byte_t buff[DS];
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            auto cur_rd = rd_.load(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            auto cur_wt = wt_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            auto id_rd  = circ::index_of(cur_rd);
 | 
				
			||||||
 | 
					            auto id_wt  = circ::index_of(cur_wt);
 | 
				
			||||||
 | 
					            if (id_rd == id_wt) {
 | 
				
			||||||
 | 
					                auto* el = elems + id_wt;
 | 
				
			||||||
 | 
					                auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					                if ((~cac_ct) != cur_wt) {
 | 
				
			||||||
 | 
					                    return false; // empty
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
 | 
				
			||||||
 | 
					                    wt_.store(cur_wt + 1, std::memory_order_release);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                k = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
 | 
				
			||||||
 | 
					                if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
 | 
				
			||||||
 | 
					                    std::forward<F>(f)(buff);
 | 
				
			||||||
 | 
					                    std::forward<R>(out)(true);
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                ipc::yield(k);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using rc_t = std::uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum : rc_t {
 | 
				
			||||||
 | 
					        ep_mask = 0x00000000ffffffffull,
 | 
				
			||||||
 | 
					        ep_incr = 0x0000000100000000ull
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					    struct elem_t {
 | 
				
			||||||
 | 
					        std::aligned_storage_t<DataSize, AlignSize> data_ {};
 | 
				
			||||||
 | 
					        std::atomic<rc_t> rc_ { 0 }; // read-counter
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<circ::u2_t> wt_;   // write index
 | 
				
			||||||
 | 
					    alignas(cache_line_size) rc_t epoch_ { 0 };             // only one writer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    circ::u2_t cursor() const noexcept {
 | 
				
			||||||
 | 
					        return wt_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool push(W* wrapper, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        E* el;
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					            // check all consumers have finished reading this element
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            circ::cc_t rem_cc = cur_rc & ep_mask;
 | 
				
			||||||
 | 
					            if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
 | 
				
			||||||
 | 
					                return false; // has not finished yet
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // consider rem_cc to be 0 here
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(
 | 
				
			||||||
 | 
					                        cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        wt_.fetch_add(1, std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool force_push(W* wrapper, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        E* el;
 | 
				
			||||||
 | 
					        epoch_ += ep_incr;
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					            // check all consumers have finished reading this element
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            circ::cc_t rem_cc = cur_rc & ep_mask;
 | 
				
			||||||
 | 
					            if (cc & rem_cc) {
 | 
				
			||||||
 | 
					                ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
 | 
				
			||||||
 | 
					                cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
 | 
				
			||||||
 | 
					                if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // just compare & exchange
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(
 | 
				
			||||||
 | 
					                        cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        wt_.fetch_add(1, std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename R, typename E>
 | 
				
			||||||
 | 
					    bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
 | 
				
			||||||
 | 
					        if (cur == cursor()) return false; // acquire
 | 
				
			||||||
 | 
					        auto* el = elems + circ::index_of(cur++);
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            if ((cur_rc & ep_mask) == 0) {
 | 
				
			||||||
 | 
					                std::forward<R>(out)(true);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
 | 
				
			||||||
 | 
					                std::forward<R>(out)((nxt_rc & ep_mask) == 0);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <>
 | 
				
			||||||
 | 
					struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using rc_t   = std::uint64_t;
 | 
				
			||||||
 | 
					    using flag_t = std::uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum : rc_t {
 | 
				
			||||||
 | 
					        rc_mask = 0x00000000ffffffffull,
 | 
				
			||||||
 | 
					        ep_mask = 0x00ffffffffffffffull,
 | 
				
			||||||
 | 
					        ep_incr = 0x0100000000000000ull,
 | 
				
			||||||
 | 
					        ic_mask = 0xff000000ffffffffull,
 | 
				
			||||||
 | 
					        ic_incr = 0x0000000100000000ull
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <std::size_t DataSize, std::size_t AlignSize>
 | 
				
			||||||
 | 
					    struct elem_t {
 | 
				
			||||||
 | 
					        std::aligned_storage_t<DataSize, AlignSize> data_ {};
 | 
				
			||||||
 | 
					        std::atomic<rc_t  > rc_   { 0 }; // read-counter
 | 
				
			||||||
 | 
					        std::atomic<flag_t> f_ct_ { 0 }; // commit flag
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<circ::u2_t> ct_;   // commit index
 | 
				
			||||||
 | 
					    alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    circ::u2_t cursor() const noexcept {
 | 
				
			||||||
 | 
					        return ct_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr static rc_t inc_rc(rc_t rc) noexcept {
 | 
				
			||||||
 | 
					        return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr static rc_t inc_mask(rc_t rc) noexcept {
 | 
				
			||||||
 | 
					        return inc_rc(rc) & ~rc_mask;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool push(W* wrapper, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        E* el;
 | 
				
			||||||
 | 
					        circ::u2_t cur_ct;
 | 
				
			||||||
 | 
					        rc_t epoch = epoch_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					            // check all consumers have finished reading this element
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            circ::cc_t rem_cc = cur_rc & rc_mask;
 | 
				
			||||||
 | 
					            if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
 | 
				
			||||||
 | 
					                return false; // has not finished yet
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (!rem_cc) {
 | 
				
			||||||
 | 
					                auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					                if ((cur_fl != cur_ct) && cur_fl) {
 | 
				
			||||||
 | 
					                    return false; // full
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // consider rem_cc to be 0 here
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(
 | 
				
			||||||
 | 
					                        cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
 | 
				
			||||||
 | 
					                epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // only one thread/process would touch here at one time
 | 
				
			||||||
 | 
					        ct_.store(cur_ct + 1, std::memory_order_release);
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        // set flag & try update wt
 | 
				
			||||||
 | 
					        el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename E>
 | 
				
			||||||
 | 
					    bool force_push(W* wrapper, F&& f, E* elems) {
 | 
				
			||||||
 | 
					        E* el;
 | 
				
			||||||
 | 
					        circ::u2_t cur_ct;
 | 
				
			||||||
 | 
					        rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
 | 
				
			||||||
 | 
					            if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
 | 
				
			||||||
 | 
					            // check all consumers have finished reading this element
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            circ::cc_t rem_cc = cur_rc & rc_mask;
 | 
				
			||||||
 | 
					            if (cc & rem_cc) {
 | 
				
			||||||
 | 
					                ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
 | 
				
			||||||
 | 
					                cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
 | 
				
			||||||
 | 
					                if (cc == 0) return false; // no reader
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // just compare & exchange
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(
 | 
				
			||||||
 | 
					                        cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
 | 
				
			||||||
 | 
					                if (epoch == epoch_.load(std::memory_order_acquire)) {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (push(wrapper, std::forward<F>(f), elems)) {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // only one thread/process would touch here at one time
 | 
				
			||||||
 | 
					        ct_.store(cur_ct + 1, std::memory_order_release);
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        // set flag & try update wt
 | 
				
			||||||
 | 
					        el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename W, typename F, typename R, typename E, std::size_t N>
 | 
				
			||||||
 | 
					    bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
 | 
				
			||||||
 | 
					        auto* el = elems + circ::index_of(cur);
 | 
				
			||||||
 | 
					        auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					        if (cur_fl != ~static_cast<flag_t>(cur)) {
 | 
				
			||||||
 | 
					            return false; // empty
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ++cur;
 | 
				
			||||||
 | 
					        std::forward<F>(f)(&(el->data_));
 | 
				
			||||||
 | 
					        for (unsigned k = 0;;) {
 | 
				
			||||||
 | 
					            auto cur_rc = el->rc_.load(std::memory_order_acquire);
 | 
				
			||||||
 | 
					            if ((cur_rc & rc_mask) == 0) {
 | 
				
			||||||
 | 
					                std::forward<R>(out)(true);
 | 
				
			||||||
 | 
					                el->f_ct_.store(cur + N - 1, std::memory_order_release);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
 | 
				
			||||||
 | 
					            bool last_one = false;
 | 
				
			||||||
 | 
					            if ((last_one = (nxt_rc & rc_mask) == 0)) {
 | 
				
			||||||
 | 
					                el->f_ct_.store(cur + N - 1, std::memory_order_release);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
 | 
				
			||||||
 | 
					                std::forward<R>(out)(last_one);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ipc::yield(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										216
									
								
								crazy_functions/test_project/cpp/cppipc/queue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								crazy_functions/test_project/cpp/cppipc/queue.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include <new>
 | 
				
			||||||
 | 
					#include <utility>  // [[since C++14]]: std::exchange
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <tuple>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <cassert>  // assert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/def.h"
 | 
				
			||||||
 | 
					#include "libipc/shm.h"
 | 
				
			||||||
 | 
					#include "libipc/rw_lock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/utility/log.h"
 | 
				
			||||||
 | 
					#include "libipc/platform/detail.h"
 | 
				
			||||||
 | 
					#include "libipc/circ/elem_def.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					namespace detail {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class queue_conn {
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					    circ::cc_t connected_ = 0;
 | 
				
			||||||
 | 
					    shm::handle elems_h_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename Elems>
 | 
				
			||||||
 | 
					    Elems* open(char const * name) {
 | 
				
			||||||
 | 
					        if (name == nullptr || name[0] == '\0') {
 | 
				
			||||||
 | 
					            ipc::error("fail open waiter: name is empty!\n");
 | 
				
			||||||
 | 
					            return nullptr;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!elems_h_.acquire(name, sizeof(Elems))) {
 | 
				
			||||||
 | 
					            return nullptr;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        auto elems = static_cast<Elems*>(elems_h_.get());
 | 
				
			||||||
 | 
					        if (elems == nullptr) {
 | 
				
			||||||
 | 
					            ipc::error("fail acquire elems: %s\n", name);
 | 
				
			||||||
 | 
					            return nullptr;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        elems->init();
 | 
				
			||||||
 | 
					        return elems;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void close() {
 | 
				
			||||||
 | 
					        elems_h_.release();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    queue_conn() = default;
 | 
				
			||||||
 | 
					    queue_conn(const queue_conn&) = delete;
 | 
				
			||||||
 | 
					    queue_conn& operator=(const queue_conn&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool connected() const noexcept {
 | 
				
			||||||
 | 
					        return connected_ != 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    circ::cc_t connected_id() const noexcept {
 | 
				
			||||||
 | 
					        return connected_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename Elems>
 | 
				
			||||||
 | 
					    auto connect(Elems* elems) noexcept
 | 
				
			||||||
 | 
					                         /*needs 'optional' here*/
 | 
				
			||||||
 | 
					     -> std::tuple<bool, bool, decltype(std::declval<Elems>().cursor())> {
 | 
				
			||||||
 | 
					        if (elems == nullptr) return {};
 | 
				
			||||||
 | 
					        // if it's already connected, just return
 | 
				
			||||||
 | 
					        if (connected()) return {connected(), false, 0};
 | 
				
			||||||
 | 
					        connected_ = elems->connect_receiver();
 | 
				
			||||||
 | 
					        return {connected(), true, elems->cursor()};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename Elems>
 | 
				
			||||||
 | 
					    bool disconnect(Elems* elems) noexcept {
 | 
				
			||||||
 | 
					        if (elems == nullptr) return false;
 | 
				
			||||||
 | 
					        // if it's already disconnected, just return false
 | 
				
			||||||
 | 
					        if (!connected()) return false;
 | 
				
			||||||
 | 
					        elems->disconnect_receiver(std::exchange(connected_, 0));
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Elems>
 | 
				
			||||||
 | 
					class queue_base : public queue_conn {
 | 
				
			||||||
 | 
					    using base_t = queue_conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    using elems_t  = Elems;
 | 
				
			||||||
 | 
					    using policy_t = typename elems_t::policy_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					    elems_t * elems_ = nullptr;
 | 
				
			||||||
 | 
					    decltype(std::declval<elems_t>().cursor()) cursor_ = 0;
 | 
				
			||||||
 | 
					    bool sender_flag_ = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    using base_t::base_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    queue_base() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    explicit queue_base(char const * name)
 | 
				
			||||||
 | 
					        : queue_base{} {
 | 
				
			||||||
 | 
					        elems_ = open<elems_t>(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    explicit queue_base(elems_t * elems) noexcept
 | 
				
			||||||
 | 
					        : queue_base{} {
 | 
				
			||||||
 | 
					        assert(elems != nullptr);
 | 
				
			||||||
 | 
					        elems_ = elems;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* not virtual */ ~queue_base() {
 | 
				
			||||||
 | 
					        base_t::close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    elems_t       * elems()       noexcept { return elems_; }
 | 
				
			||||||
 | 
					    elems_t const * elems() const noexcept { return elems_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool ready_sending() noexcept {
 | 
				
			||||||
 | 
					        if (elems_ == nullptr) return false;
 | 
				
			||||||
 | 
					        return sender_flag_ || (sender_flag_ = elems_->connect_sender());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void shut_sending() noexcept {
 | 
				
			||||||
 | 
					        if (elems_ == nullptr) return;
 | 
				
			||||||
 | 
					        if (!sender_flag_) return;
 | 
				
			||||||
 | 
					        elems_->disconnect_sender();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool connect() noexcept {
 | 
				
			||||||
 | 
					        auto tp = base_t::connect(elems_);
 | 
				
			||||||
 | 
					        if (std::get<0>(tp) && std::get<1>(tp)) {
 | 
				
			||||||
 | 
					            cursor_ = std::get<2>(tp);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return std::get<0>(tp);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool disconnect() noexcept {
 | 
				
			||||||
 | 
					        return base_t::disconnect(elems_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t conn_count() const noexcept {
 | 
				
			||||||
 | 
					        return (elems_ == nullptr) ? static_cast<std::size_t>(invalid_value) : elems_->conn_count();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool valid() const noexcept {
 | 
				
			||||||
 | 
					        return elems_ != nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool empty() const noexcept {
 | 
				
			||||||
 | 
					        return !valid() || (cursor_ == elems_->cursor());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, typename F, typename... P>
 | 
				
			||||||
 | 
					    bool push(F&& prep, P&&... params) {
 | 
				
			||||||
 | 
					        if (elems_ == nullptr) return false;
 | 
				
			||||||
 | 
					        return elems_->push(this, [&](void* p) {
 | 
				
			||||||
 | 
					            if (prep(p)) ::new (p) T(std::forward<P>(params)...);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, typename F, typename... P>
 | 
				
			||||||
 | 
					    bool force_push(F&& prep, P&&... params) {
 | 
				
			||||||
 | 
					        if (elems_ == nullptr) return false;
 | 
				
			||||||
 | 
					        return elems_->force_push(this, [&](void* p) {
 | 
				
			||||||
 | 
					            if (prep(p)) ::new (p) T(std::forward<P>(params)...);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, typename F>
 | 
				
			||||||
 | 
					    bool pop(T& item, F&& out) {
 | 
				
			||||||
 | 
					        if (elems_ == nullptr) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return elems_->pop(this, &(this->cursor_), [&item](void* p) {
 | 
				
			||||||
 | 
					            ::new (&item) T(std::move(*static_cast<T*>(p)));
 | 
				
			||||||
 | 
					        }, std::forward<F>(out));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace detail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T, typename Policy>
 | 
				
			||||||
 | 
					class queue final : public detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>> {
 | 
				
			||||||
 | 
					    using base_t = detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    using value_t = T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using base_t::base_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename... P>
 | 
				
			||||||
 | 
					    bool push(P&&... params) {
 | 
				
			||||||
 | 
					        return base_t::template push<T>(std::forward<P>(params)...);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename... P>
 | 
				
			||||||
 | 
					    bool force_push(P&&... params) {
 | 
				
			||||||
 | 
					        return base_t::template force_push<T>(std::forward<P>(params)...);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool pop(T& item) {
 | 
				
			||||||
 | 
					        return base_t::pop(item, [](bool) {});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename F>
 | 
				
			||||||
 | 
					    bool pop(T& item, F&& out) {
 | 
				
			||||||
 | 
					        return base_t::pop(item, std::forward<F>(out));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										103
									
								
								crazy_functions/test_project/cpp/cppipc/shm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								crazy_functions/test_project/cpp/cppipc/shm.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/shm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/utility/pimpl.h"
 | 
				
			||||||
 | 
					#include "libipc/memory/resource.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					namespace shm {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class handle::handle_ : public pimpl<handle_> {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    shm::id_t id_ = nullptr;
 | 
				
			||||||
 | 
					    void*     m_  = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ipc::string n_;
 | 
				
			||||||
 | 
					    std::size_t s_ = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle::handle()
 | 
				
			||||||
 | 
					    : p_(p_->make()) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle::handle(char const * name, std::size_t size, unsigned mode)
 | 
				
			||||||
 | 
					    : handle() {
 | 
				
			||||||
 | 
					    acquire(name, size, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle::handle(handle&& rhs)
 | 
				
			||||||
 | 
					    : handle() {
 | 
				
			||||||
 | 
					    swap(rhs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle::~handle() {
 | 
				
			||||||
 | 
					    release();
 | 
				
			||||||
 | 
					    p_->clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle::swap(handle& rhs) {
 | 
				
			||||||
 | 
					    std::swap(p_, rhs.p_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle& handle::operator=(handle rhs) {
 | 
				
			||||||
 | 
					    swap(rhs);
 | 
				
			||||||
 | 
					    return *this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool handle::valid() const noexcept {
 | 
				
			||||||
 | 
					    return impl(p_)->m_ != nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::size_t handle::size() const noexcept {
 | 
				
			||||||
 | 
					    return impl(p_)->s_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char const * handle::name() const noexcept {
 | 
				
			||||||
 | 
					    return impl(p_)->n_.c_str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::int32_t handle::ref() const noexcept {
 | 
				
			||||||
 | 
					    return shm::get_ref(impl(p_)->id_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle::sub_ref() noexcept {
 | 
				
			||||||
 | 
					    shm::sub_ref(impl(p_)->id_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
 | 
				
			||||||
 | 
					    release();
 | 
				
			||||||
 | 
					    impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
 | 
				
			||||||
 | 
					    impl(p_)->m_  = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
 | 
				
			||||||
 | 
					    return valid();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::int32_t handle::release() {
 | 
				
			||||||
 | 
					    if (impl(p_)->id_ == nullptr) return -1;
 | 
				
			||||||
 | 
					    return shm::release(detach());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void* handle::get() const {
 | 
				
			||||||
 | 
					    return impl(p_)->m_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle::attach(id_t id) {
 | 
				
			||||||
 | 
					    if (id == nullptr) return;
 | 
				
			||||||
 | 
					    release();
 | 
				
			||||||
 | 
					    impl(p_)->id_ = id;
 | 
				
			||||||
 | 
					    impl(p_)->m_  = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					id_t handle::detach() {
 | 
				
			||||||
 | 
					    auto old = impl(p_)->id_;
 | 
				
			||||||
 | 
					    impl(p_)->id_ = nullptr;
 | 
				
			||||||
 | 
					    impl(p_)->m_  = nullptr;
 | 
				
			||||||
 | 
					    impl(p_)->s_  = 0;
 | 
				
			||||||
 | 
					    impl(p_)->n_.clear();
 | 
				
			||||||
 | 
					    return old;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace shm
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										83
									
								
								crazy_functions/test_project/cpp/cppipc/waiter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								crazy_functions/test_project/cpp/cppipc/waiter.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libipc/def.h"
 | 
				
			||||||
 | 
					#include "libipc/mutex.h"
 | 
				
			||||||
 | 
					#include "libipc/condition.h"
 | 
				
			||||||
 | 
					#include "libipc/platform/detail.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ipc {
 | 
				
			||||||
 | 
					namespace detail {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class waiter {
 | 
				
			||||||
 | 
					    ipc::sync::condition cond_;
 | 
				
			||||||
 | 
					    ipc::sync::mutex     lock_;
 | 
				
			||||||
 | 
					    std::atomic<bool>    quit_ {false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    static void init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    waiter() = default;
 | 
				
			||||||
 | 
					    waiter(char const *name) {
 | 
				
			||||||
 | 
					        open(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~waiter() {
 | 
				
			||||||
 | 
					        close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool valid() const noexcept {
 | 
				
			||||||
 | 
					        return cond_.valid() && lock_.valid();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool open(char const *name) noexcept {
 | 
				
			||||||
 | 
					        quit_.store(false, std::memory_order_relaxed);
 | 
				
			||||||
 | 
					        if (!cond_.open((std::string{"_waiter_cond_"} + name).c_str())) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!lock_.open((std::string{"_waiter_lock_"} + name).c_str())) {
 | 
				
			||||||
 | 
					            cond_.close();
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return valid();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void close() noexcept {
 | 
				
			||||||
 | 
					        cond_.close();
 | 
				
			||||||
 | 
					        lock_.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename F>
 | 
				
			||||||
 | 
					    bool wait_if(F &&pred, std::uint64_t tm = ipc::invalid_value) noexcept {
 | 
				
			||||||
 | 
					        IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
 | 
				
			||||||
 | 
					        while ([this, &pred] {
 | 
				
			||||||
 | 
					                    return !quit_.load(std::memory_order_relaxed)
 | 
				
			||||||
 | 
					                        && std::forward<F>(pred)();
 | 
				
			||||||
 | 
					                }()) {
 | 
				
			||||||
 | 
					            if (!cond_.wait(lock_, tm)) return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool notify() noexcept {
 | 
				
			||||||
 | 
					        std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
 | 
				
			||||||
 | 
					        return cond_.notify(lock_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool broadcast() noexcept {
 | 
				
			||||||
 | 
					        std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
 | 
				
			||||||
 | 
					        return cond_.broadcast(lock_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool quit_waiting() {
 | 
				
			||||||
 | 
					        quit_.store(true, std::memory_order_release);
 | 
				
			||||||
 | 
					        return broadcast();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace detail
 | 
				
			||||||
 | 
					} // namespace ipc
 | 
				
			||||||
							
								
								
									
										9
									
								
								crazy_functions/test_project/其他测试
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								crazy_functions/test_project/其他测试
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					"In practice, we found that a high-entropy initial state is more likely to increase the speed of training.
 | 
				
			||||||
 | 
					The entropy is calculated by:
 | 
				
			||||||
 | 
					$$H=-\sum_{k= 1}^{n_k} p(k) \cdot \log p(k), p(k)=\frac{|A_k|}{|\mathcal{A}|}$$
 | 
				
			||||||
 | 
					where $H$ is the entropy, $|A_k|$ is the number of agent nodes in $k$-th cluster, $|\mathcal{A}|$ is the total number of agents.
 | 
				
			||||||
 | 
					To ensure the Cooperation Graph initialization has higher entropy,
 | 
				
			||||||
 | 
					we will randomly generate multiple initial states, 
 | 
				
			||||||
 | 
					rank by their entropy and then pick the one with maximum $H$."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										63
									
								
								crazy_functions/生成函数注释.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								crazy_functions/生成函数注释.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					from predict import predict_no_ui
 | 
				
			||||||
 | 
					from toolbox import CatchException, report_execption, write_results_to_file
 | 
				
			||||||
 | 
					fast_debug = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def 生成函数注释(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
 | 
				
			||||||
 | 
					    import time, glob, os
 | 
				
			||||||
 | 
					    print('begin analysis on:', file_manifest)
 | 
				
			||||||
 | 
					    for index, fp in enumerate(file_manifest):
 | 
				
			||||||
 | 
					        with open(fp, 'r', encoding='utf-8') as f:
 | 
				
			||||||
 | 
					            file_content = f.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
 | 
				
			||||||
 | 
					        i_say_show_user = f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
 | 
				
			||||||
 | 
					        chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
 | 
				
			||||||
 | 
					        print('[1] yield chatbot, history')
 | 
				
			||||||
 | 
					        yield chatbot, history, '正常'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not fast_debug: 
 | 
				
			||||||
 | 
					            msg = '正常'
 | 
				
			||||||
 | 
					            # ** gpt request **
 | 
				
			||||||
 | 
					            while True:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature)
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                except ConnectionAbortedError as e:
 | 
				
			||||||
 | 
					                    i_say = i_say[:len(i_say)//2]
 | 
				
			||||||
 | 
					                    msg = '文件太长,进行了拦腰截断'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print('[2] end gpt req')
 | 
				
			||||||
 | 
					            chatbot[-1] = (i_say_show_user, gpt_say)
 | 
				
			||||||
 | 
					            history.append(i_say_show_user); history.append(gpt_say)
 | 
				
			||||||
 | 
					            print('[3] yield chatbot, history')
 | 
				
			||||||
 | 
					            yield chatbot, history, msg
 | 
				
			||||||
 | 
					            print('[4] next')
 | 
				
			||||||
 | 
					            if not fast_debug: time.sleep(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not fast_debug: 
 | 
				
			||||||
 | 
					        res = write_results_to_file(history)
 | 
				
			||||||
 | 
					        chatbot.append(("完成了吗?", res))
 | 
				
			||||||
 | 
					        yield chatbot, history, msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CatchException
 | 
				
			||||||
 | 
					def 批量生成函数注释(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
 | 
				
			||||||
 | 
					    history = []    # 清空历史,以免输入溢出
 | 
				
			||||||
 | 
					    import glob, os
 | 
				
			||||||
 | 
					    if os.path.exists(txt):
 | 
				
			||||||
 | 
					        project_folder = txt
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        if txt == "": txt = '空空如也的输入栏'
 | 
				
			||||||
 | 
					        report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
 | 
				
			||||||
 | 
					        yield chatbot, history, '正常'
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)] + \
 | 
				
			||||||
 | 
					                    [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if len(file_manifest) == 0:
 | 
				
			||||||
 | 
					        report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}")
 | 
				
			||||||
 | 
					        yield chatbot, history, '正常'
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    yield from 生成函数注释(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)
 | 
				
			||||||
@ -157,9 +157,10 @@ def 解析一个C项目的头文件(txt, top_p, temperature, chatbot, history, s
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def get_crazy_functionals():
 | 
					def get_crazy_functionals():
 | 
				
			||||||
    from crazy_functions.读文章写摘要 import 读文章写摘要
 | 
					    from crazy_functions.读文章写摘要 import 读文章写摘要
 | 
				
			||||||
 | 
					    from crazy_functions.生成函数注释 import 批量生成函数注释
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        "[实验功能] 请解析并解构此项目本身": {
 | 
					        "[实验功能] 请解析并解构此项目本身": {
 | 
				
			||||||
            "Color": "stop",    # 按钮颜色
 | 
					 | 
				
			||||||
            "Function": 解析项目本身
 | 
					            "Function": 解析项目本身
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "[实验功能] 解析整个Python项目(input输入项目根路径)": {
 | 
					        "[实验功能] 解析整个Python项目(input输入项目根路径)": {
 | 
				
			||||||
@ -174,6 +175,10 @@ def get_crazy_functionals():
 | 
				
			|||||||
            "Color": "stop",    # 按钮颜色
 | 
					            "Color": "stop",    # 按钮颜色
 | 
				
			||||||
            "Function": 读文章写摘要
 | 
					            "Function": 读文章写摘要
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "[实验功能] 批量生成函数注释(input输入项目根路径)": {
 | 
				
			||||||
 | 
					            "Color": "stop",    # 按钮颜色
 | 
				
			||||||
 | 
					            "Function": 批量生成函数注释
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "[实验功能] 高阶功能模板函数": {
 | 
					        "[实验功能] 高阶功能模板函数": {
 | 
				
			||||||
            "Color": "stop",    # 按钮颜色
 | 
					            "Color": "stop",    # 按钮颜色
 | 
				
			||||||
            "Function": 高阶功能模板函数
 | 
					            "Function": 高阶功能模板函数
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@ def write_results_to_file(history, file_name=None):
 | 
				
			|||||||
            if i%2==0: f.write('## ')
 | 
					            if i%2==0: f.write('## ')
 | 
				
			||||||
            f.write(content)
 | 
					            f.write(content)
 | 
				
			||||||
            f.write('\n\n')
 | 
					            f.write('\n\n')
 | 
				
			||||||
    res ='以上材料已经被写入', f'./gpt_log/{file_name}' 
 | 
					    res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')
 | 
				
			||||||
    print(res)
 | 
					    print(res)
 | 
				
			||||||
    return res
 | 
					    return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user