Spaces:
Sleeping
Sleeping
批量生成函数注释
Browse files- crazy_functions/test_project/cpp/cppipc/buffer.cpp +87 -0
- crazy_functions/test_project/cpp/cppipc/ipc.cpp +701 -0
- crazy_functions/test_project/cpp/cppipc/policy.h +25 -0
- crazy_functions/test_project/cpp/cppipc/pool_alloc.cpp +17 -0
- crazy_functions/test_project/cpp/cppipc/prod_cons.h +433 -0
- crazy_functions/test_project/cpp/cppipc/queue.h +216 -0
- crazy_functions/test_project/cpp/cppipc/shm.cpp +103 -0
- crazy_functions/test_project/cpp/cppipc/waiter.h +83 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/JpegLibrary.tps +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/UElibJPG.Build.cs +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/jpeg-compressor.tps +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/jpgd.cpp +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/jpgd.h +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/jpge.cpp +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/jpge.h +0 -0
- crazy_functions/test_project/{Cpp → cpp}/libJPG/来源 +0 -0
- crazy_functions/test_project/其他测试 +9 -0
- crazy_functions/生成函数注释.py +63 -0
- functional_crazy.py +6 -1
- toolbox.py +1 -1
crazy_functions/test_project/cpp/cppipc/buffer.cpp
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include "libipc/buffer.h"
|
2 |
+
#include "libipc/utility/pimpl.h"
|
3 |
+
|
4 |
+
#include <cstring>
|
5 |
+
|
6 |
+
namespace ipc {
|
7 |
+
|
8 |
+
bool operator==(buffer const & b1, buffer const & b2) {
|
9 |
+
return (b1.size() == b2.size()) && (std::memcmp(b1.data(), b2.data(), b1.size()) == 0);
|
10 |
+
}
|
11 |
+
|
12 |
+
bool operator!=(buffer const & b1, buffer const & b2) {
|
13 |
+
return !(b1 == b2);
|
14 |
+
}
|
15 |
+
|
16 |
+
class buffer::buffer_ : public pimpl<buffer_> {
|
17 |
+
public:
|
18 |
+
void* p_;
|
19 |
+
std::size_t s_;
|
20 |
+
void* a_;
|
21 |
+
buffer::destructor_t d_;
|
22 |
+
|
23 |
+
buffer_(void* p, std::size_t s, buffer::destructor_t d, void* a)
|
24 |
+
: p_(p), s_(s), a_(a), d_(d) {
|
25 |
+
}
|
26 |
+
|
27 |
+
~buffer_() {
|
28 |
+
if (d_ == nullptr) return;
|
29 |
+
d_((a_ == nullptr) ? p_ : a_, s_);
|
30 |
+
}
|
31 |
+
};
|
32 |
+
|
33 |
+
buffer::buffer()
|
34 |
+
: buffer(nullptr, 0, nullptr, nullptr) {
|
35 |
+
}
|
36 |
+
|
37 |
+
buffer::buffer(void* p, std::size_t s, destructor_t d)
|
38 |
+
: p_(p_->make(p, s, d, nullptr)) {
|
39 |
+
}
|
40 |
+
|
41 |
+
buffer::buffer(void* p, std::size_t s, destructor_t d, void* additional)
|
42 |
+
: p_(p_->make(p, s, d, additional)) {
|
43 |
+
}
|
44 |
+
|
45 |
+
buffer::buffer(void* p, std::size_t s)
|
46 |
+
: buffer(p, s, nullptr) {
|
47 |
+
}
|
48 |
+
|
49 |
+
buffer::buffer(char const & c)
|
50 |
+
: buffer(const_cast<char*>(&c), 1) {
|
51 |
+
}
|
52 |
+
|
53 |
+
buffer::buffer(buffer&& rhs)
|
54 |
+
: buffer() {
|
55 |
+
swap(rhs);
|
56 |
+
}
|
57 |
+
|
58 |
+
buffer::~buffer() {
|
59 |
+
p_->clear();
|
60 |
+
}
|
61 |
+
|
62 |
+
void buffer::swap(buffer& rhs) {
|
63 |
+
std::swap(p_, rhs.p_);
|
64 |
+
}
|
65 |
+
|
66 |
+
buffer& buffer::operator=(buffer rhs) {
|
67 |
+
swap(rhs);
|
68 |
+
return *this;
|
69 |
+
}
|
70 |
+
|
71 |
+
bool buffer::empty() const noexcept {
|
72 |
+
return (impl(p_)->p_ == nullptr) || (impl(p_)->s_ == 0);
|
73 |
+
}
|
74 |
+
|
75 |
+
void* buffer::data() noexcept {
|
76 |
+
return impl(p_)->p_;
|
77 |
+
}
|
78 |
+
|
79 |
+
void const * buffer::data() const noexcept {
|
80 |
+
return impl(p_)->p_;
|
81 |
+
}
|
82 |
+
|
83 |
+
std::size_t buffer::size() const noexcept {
|
84 |
+
return impl(p_)->s_;
|
85 |
+
}
|
86 |
+
|
87 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/ipc.cpp
ADDED
@@ -0,0 +1,701 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
#include <type_traits>
|
3 |
+
#include <cstring>
|
4 |
+
#include <algorithm>
|
5 |
+
#include <utility> // std::pair, std::move, std::forward
|
6 |
+
#include <atomic>
|
7 |
+
#include <type_traits> // aligned_storage_t
|
8 |
+
#include <string>
|
9 |
+
#include <vector>
|
10 |
+
#include <array>
|
11 |
+
#include <cassert>
|
12 |
+
|
13 |
+
#include "libipc/ipc.h"
|
14 |
+
#include "libipc/def.h"
|
15 |
+
#include "libipc/shm.h"
|
16 |
+
#include "libipc/pool_alloc.h"
|
17 |
+
#include "libipc/queue.h"
|
18 |
+
#include "libipc/policy.h"
|
19 |
+
#include "libipc/rw_lock.h"
|
20 |
+
#include "libipc/waiter.h"
|
21 |
+
|
22 |
+
#include "libipc/utility/log.h"
|
23 |
+
#include "libipc/utility/id_pool.h"
|
24 |
+
#include "libipc/utility/scope_guard.h"
|
25 |
+
#include "libipc/utility/utility.h"
|
26 |
+
|
27 |
+
#include "libipc/memory/resource.h"
|
28 |
+
#include "libipc/platform/detail.h"
|
29 |
+
#include "libipc/circ/elem_array.h"
|
30 |
+
|
31 |
+
namespace {
|
32 |
+
|
33 |
+
using msg_id_t = std::uint32_t;
|
34 |
+
using acc_t = std::atomic<msg_id_t>;
|
35 |
+
|
36 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
37 |
+
struct msg_t;
|
38 |
+
|
39 |
+
template <std::size_t AlignSize>
|
40 |
+
struct msg_t<0, AlignSize> {
|
41 |
+
msg_id_t cc_id_;
|
42 |
+
msg_id_t id_;
|
43 |
+
std::int32_t remain_;
|
44 |
+
bool storage_;
|
45 |
+
};
|
46 |
+
|
47 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
48 |
+
struct msg_t : msg_t<0, AlignSize> {
|
49 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
50 |
+
|
51 |
+
msg_t() = default;
|
52 |
+
msg_t(msg_id_t cc_id, msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
|
53 |
+
: msg_t<0, AlignSize> {cc_id, id, remain, (data == nullptr) || (size == 0)} {
|
54 |
+
if (this->storage_) {
|
55 |
+
if (data != nullptr) {
|
56 |
+
// copy storage-id
|
57 |
+
*reinterpret_cast<ipc::storage_id_t*>(&data_) =
|
58 |
+
*static_cast<ipc::storage_id_t const *>(data);
|
59 |
+
}
|
60 |
+
}
|
61 |
+
else std::memcpy(&data_, data, size);
|
62 |
+
}
|
63 |
+
};
|
64 |
+
|
65 |
+
template <typename T>
|
66 |
+
ipc::buff_t make_cache(T& data, std::size_t size) {
|
67 |
+
auto ptr = ipc::mem::alloc(size);
|
68 |
+
std::memcpy(ptr, &data, (ipc::detail::min)(sizeof(data), size));
|
69 |
+
return { ptr, size, ipc::mem::free };
|
70 |
+
}
|
71 |
+
|
72 |
+
struct cache_t {
|
73 |
+
std::size_t fill_;
|
74 |
+
ipc::buff_t buff_;
|
75 |
+
|
76 |
+
cache_t(std::size_t f, ipc::buff_t && b)
|
77 |
+
: fill_(f), buff_(std::move(b))
|
78 |
+
{}
|
79 |
+
|
80 |
+
void append(void const * data, std::size_t size) {
|
81 |
+
if (fill_ >= buff_.size() || data == nullptr || size == 0) return;
|
82 |
+
auto new_fill = (ipc::detail::min)(fill_ + size, buff_.size());
|
83 |
+
std::memcpy(static_cast<ipc::byte_t*>(buff_.data()) + fill_, data, new_fill - fill_);
|
84 |
+
fill_ = new_fill;
|
85 |
+
}
|
86 |
+
};
|
87 |
+
|
88 |
+
auto cc_acc() {
|
89 |
+
static ipc::shm::handle acc_h("__CA_CONN__", sizeof(acc_t));
|
90 |
+
return static_cast<acc_t*>(acc_h.get());
|
91 |
+
}
|
92 |
+
|
93 |
+
IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
|
94 |
+
return (((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align;
|
95 |
+
}
|
96 |
+
|
97 |
+
IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
|
98 |
+
return ipc::make_align(alignof(std::max_align_t), align_chunk_size(
|
99 |
+
ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>)) + size));
|
100 |
+
}
|
101 |
+
|
102 |
+
struct chunk_t {
|
103 |
+
std::atomic<ipc::circ::cc_t> &conns() noexcept {
|
104 |
+
return *reinterpret_cast<std::atomic<ipc::circ::cc_t> *>(this);
|
105 |
+
}
|
106 |
+
|
107 |
+
void *data() noexcept {
|
108 |
+
return reinterpret_cast<ipc::byte_t *>(this)
|
109 |
+
+ ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>));
|
110 |
+
}
|
111 |
+
};
|
112 |
+
|
113 |
+
struct chunk_info_t {
|
114 |
+
ipc::id_pool<> pool_;
|
115 |
+
ipc::spin_lock lock_;
|
116 |
+
|
117 |
+
IPC_CONSTEXPR_ static std::size_t chunks_mem_size(std::size_t chunk_size) noexcept {
|
118 |
+
return ipc::id_pool<>::max_count * chunk_size;
|
119 |
+
}
|
120 |
+
|
121 |
+
ipc::byte_t *chunks_mem() noexcept {
|
122 |
+
return reinterpret_cast<ipc::byte_t *>(this + 1);
|
123 |
+
}
|
124 |
+
|
125 |
+
chunk_t *at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
|
126 |
+
if (id < 0) return nullptr;
|
127 |
+
return reinterpret_cast<chunk_t *>(chunks_mem() + (chunk_size * id));
|
128 |
+
}
|
129 |
+
};
|
130 |
+
|
131 |
+
auto& chunk_storages() {
|
132 |
+
class chunk_handle_t {
|
133 |
+
ipc::shm::handle handle_;
|
134 |
+
|
135 |
+
public:
|
136 |
+
chunk_info_t *get_info(std::size_t chunk_size) {
|
137 |
+
if (!handle_.valid() &&
|
138 |
+
!handle_.acquire( ("__CHUNK_INFO__" + ipc::to_string(chunk_size)).c_str(),
|
139 |
+
sizeof(chunk_info_t) + chunk_info_t::chunks_mem_size(chunk_size) )) {
|
140 |
+
ipc::error("[chunk_storages] chunk_shm.id_info_.acquire failed: chunk_size = %zd\n", chunk_size);
|
141 |
+
return nullptr;
|
142 |
+
}
|
143 |
+
auto info = static_cast<chunk_info_t*>(handle_.get());
|
144 |
+
if (info == nullptr) {
|
145 |
+
ipc::error("[chunk_storages] chunk_shm.id_info_.get failed: chunk_size = %zd\n", chunk_size);
|
146 |
+
return nullptr;
|
147 |
+
}
|
148 |
+
return info;
|
149 |
+
}
|
150 |
+
};
|
151 |
+
static ipc::map<std::size_t, chunk_handle_t> chunk_hs;
|
152 |
+
return chunk_hs;
|
153 |
+
}
|
154 |
+
|
155 |
+
chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
|
156 |
+
auto &storages = chunk_storages();
|
157 |
+
std::decay_t<decltype(storages)>::iterator it;
|
158 |
+
{
|
159 |
+
static ipc::rw_lock lock;
|
160 |
+
IPC_UNUSED_ std::shared_lock<ipc::rw_lock> guard {lock};
|
161 |
+
if ((it = storages.find(chunk_size)) == storages.end()) {
|
162 |
+
using chunk_handle_t = std::decay_t<decltype(storages)>::value_type::second_type;
|
163 |
+
guard.unlock();
|
164 |
+
IPC_UNUSED_ std::lock_guard<ipc::rw_lock> guard {lock};
|
165 |
+
it = storages.emplace(chunk_size, chunk_handle_t{}).first;
|
166 |
+
}
|
167 |
+
}
|
168 |
+
return it->second.get_info(chunk_size);
|
169 |
+
}
|
170 |
+
|
171 |
+
std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size, ipc::circ::cc_t conns) {
|
172 |
+
std::size_t chunk_size = calc_chunk_size(size);
|
173 |
+
auto info = chunk_storage_info(chunk_size);
|
174 |
+
if (info == nullptr) return {};
|
175 |
+
|
176 |
+
info->lock_.lock();
|
177 |
+
info->pool_.prepare();
|
178 |
+
// got an unique id
|
179 |
+
auto id = info->pool_.acquire();
|
180 |
+
info->lock_.unlock();
|
181 |
+
|
182 |
+
auto chunk = info->at(chunk_size, id);
|
183 |
+
if (chunk == nullptr) return {};
|
184 |
+
chunk->conns().store(conns, std::memory_order_relaxed);
|
185 |
+
return { id, chunk->data() };
|
186 |
+
}
|
187 |
+
|
188 |
+
void *find_storage(ipc::storage_id_t id, std::size_t size) {
|
189 |
+
if (id < 0) {
|
190 |
+
ipc::error("[find_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
|
191 |
+
return nullptr;
|
192 |
+
}
|
193 |
+
std::size_t chunk_size = calc_chunk_size(size);
|
194 |
+
auto info = chunk_storage_info(chunk_size);
|
195 |
+
if (info == nullptr) return nullptr;
|
196 |
+
return info->at(chunk_size, id)->data();
|
197 |
+
}
|
198 |
+
|
199 |
+
void release_storage(ipc::storage_id_t id, std::size_t size) {
|
200 |
+
if (id < 0) {
|
201 |
+
ipc::error("[release_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
|
202 |
+
return;
|
203 |
+
}
|
204 |
+
std::size_t chunk_size = calc_chunk_size(size);
|
205 |
+
auto info = chunk_storage_info(chunk_size);
|
206 |
+
if (info == nullptr) return;
|
207 |
+
info->lock_.lock();
|
208 |
+
info->pool_.release(id);
|
209 |
+
info->lock_.unlock();
|
210 |
+
}
|
211 |
+
|
212 |
+
template <ipc::relat Rp, ipc::relat Rc>
|
213 |
+
bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::unicast>,
|
214 |
+
std::atomic<ipc::circ::cc_t> &/*conns*/, ipc::circ::cc_t /*curr_conns*/, ipc::circ::cc_t /*conn_id*/) noexcept {
|
215 |
+
return true;
|
216 |
+
}
|
217 |
+
|
218 |
+
template <ipc::relat Rp, ipc::relat Rc>
|
219 |
+
bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::broadcast>,
|
220 |
+
std::atomic<ipc::circ::cc_t> &conns, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) noexcept {
|
221 |
+
auto last_conns = curr_conns & ~conn_id;
|
222 |
+
for (unsigned k = 0;;) {
|
223 |
+
auto chunk_conns = conns.load(std::memory_order_acquire);
|
224 |
+
if (conns.compare_exchange_weak(chunk_conns, chunk_conns & last_conns, std::memory_order_release)) {
|
225 |
+
return (chunk_conns & last_conns) == 0;
|
226 |
+
}
|
227 |
+
ipc::yield(k);
|
228 |
+
}
|
229 |
+
}
|
230 |
+
|
231 |
+
template <typename Flag>
|
232 |
+
void recycle_storage(ipc::storage_id_t id, std::size_t size, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) {
|
233 |
+
if (id < 0) {
|
234 |
+
ipc::error("[recycle_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
|
235 |
+
return;
|
236 |
+
}
|
237 |
+
std::size_t chunk_size = calc_chunk_size(size);
|
238 |
+
auto info = chunk_storage_info(chunk_size);
|
239 |
+
if (info == nullptr) return;
|
240 |
+
|
241 |
+
auto chunk = info->at(chunk_size, id);
|
242 |
+
if (chunk == nullptr) return;
|
243 |
+
|
244 |
+
if (!sub_rc(Flag{}, chunk->conns(), curr_conns, conn_id)) {
|
245 |
+
return;
|
246 |
+
}
|
247 |
+
info->lock_.lock();
|
248 |
+
info->pool_.release(id);
|
249 |
+
info->lock_.unlock();
|
250 |
+
}
|
251 |
+
|
252 |
+
template <typename MsgT>
|
253 |
+
bool clear_message(void* p) {
|
254 |
+
auto msg = static_cast<MsgT*>(p);
|
255 |
+
if (msg->storage_) {
|
256 |
+
std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg->remain_;
|
257 |
+
if (r_size <= 0) {
|
258 |
+
ipc::error("[clear_message] invalid msg size: %d\n", (int)r_size);
|
259 |
+
return true;
|
260 |
+
}
|
261 |
+
release_storage(
|
262 |
+
*reinterpret_cast<ipc::storage_id_t*>(&msg->data_),
|
263 |
+
static_cast<std::size_t>(r_size));
|
264 |
+
}
|
265 |
+
return true;
|
266 |
+
}
|
267 |
+
|
268 |
+
struct conn_info_head {
|
269 |
+
|
270 |
+
ipc::string name_;
|
271 |
+
msg_id_t cc_id_; // connection-info id
|
272 |
+
ipc::detail::waiter cc_waiter_, wt_waiter_, rd_waiter_;
|
273 |
+
ipc::shm::handle acc_h_;
|
274 |
+
|
275 |
+
conn_info_head(char const * name)
|
276 |
+
: name_ {name}
|
277 |
+
, cc_id_ {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)}
|
278 |
+
, cc_waiter_{("__CC_CONN__" + name_).c_str()}
|
279 |
+
, wt_waiter_{("__WT_CONN__" + name_).c_str()}
|
280 |
+
, rd_waiter_{("__RD_CONN__" + name_).c_str()}
|
281 |
+
, acc_h_ {("__AC_CONN__" + name_).c_str(), sizeof(acc_t)} {
|
282 |
+
}
|
283 |
+
|
284 |
+
void quit_waiting() {
|
285 |
+
cc_waiter_.quit_waiting();
|
286 |
+
wt_waiter_.quit_waiting();
|
287 |
+
rd_waiter_.quit_waiting();
|
288 |
+
}
|
289 |
+
|
290 |
+
auto acc() {
|
291 |
+
return static_cast<acc_t*>(acc_h_.get());
|
292 |
+
}
|
293 |
+
|
294 |
+
auto& recv_cache() {
|
295 |
+
thread_local ipc::unordered_map<msg_id_t, cache_t> tls;
|
296 |
+
return tls;
|
297 |
+
}
|
298 |
+
};
|
299 |
+
|
300 |
+
template <typename W, typename F>
|
301 |
+
bool wait_for(W& waiter, F&& pred, std::uint64_t tm) {
|
302 |
+
if (tm == 0) return !pred();
|
303 |
+
for (unsigned k = 0; pred();) {
|
304 |
+
bool ret = true;
|
305 |
+
ipc::sleep(k, [&k, &ret, &waiter, &pred, tm] {
|
306 |
+
ret = waiter.wait_if(std::forward<F>(pred), tm);
|
307 |
+
k = 0;
|
308 |
+
});
|
309 |
+
if (!ret) return false; // timeout or fail
|
310 |
+
if (k == 0) break; // k has been reset
|
311 |
+
}
|
312 |
+
return true;
|
313 |
+
}
|
314 |
+
|
315 |
+
template <typename Policy,
|
316 |
+
std::size_t DataSize = ipc::data_length,
|
317 |
+
std::size_t AlignSize = (ipc::detail::min)(DataSize, alignof(std::max_align_t))>
|
318 |
+
struct queue_generator {
|
319 |
+
|
320 |
+
using queue_t = ipc::queue<msg_t<DataSize, AlignSize>, Policy>;
|
321 |
+
|
322 |
+
struct conn_info_t : conn_info_head {
|
323 |
+
queue_t que_;
|
324 |
+
|
325 |
+
conn_info_t(char const * name)
|
326 |
+
: conn_info_head{name}
|
327 |
+
, que_{("__QU_CONN__" +
|
328 |
+
ipc::to_string(DataSize) + "__" +
|
329 |
+
ipc::to_string(AlignSize) + "__" + name).c_str()} {
|
330 |
+
}
|
331 |
+
|
332 |
+
void disconnect_receiver() {
|
333 |
+
bool dis = que_.disconnect();
|
334 |
+
this->quit_waiting();
|
335 |
+
if (dis) {
|
336 |
+
this->recv_cache().clear();
|
337 |
+
}
|
338 |
+
}
|
339 |
+
};
|
340 |
+
};
|
341 |
+
|
342 |
+
template <typename Policy>
|
343 |
+
struct detail_impl {
|
344 |
+
|
345 |
+
using policy_t = Policy;
|
346 |
+
using flag_t = typename policy_t::flag_t;
|
347 |
+
using queue_t = typename queue_generator<policy_t>::queue_t;
|
348 |
+
using conn_info_t = typename queue_generator<policy_t>::conn_info_t;
|
349 |
+
|
350 |
+
constexpr static conn_info_t* info_of(ipc::handle_t h) noexcept {
|
351 |
+
return static_cast<conn_info_t*>(h);
|
352 |
+
}
|
353 |
+
|
354 |
+
constexpr static queue_t* queue_of(ipc::handle_t h) noexcept {
|
355 |
+
return (info_of(h) == nullptr) ? nullptr : &(info_of(h)->que_);
|
356 |
+
}
|
357 |
+
|
358 |
+
/* API implementations */
|
359 |
+
|
360 |
+
static void disconnect(ipc::handle_t h) {
|
361 |
+
auto que = queue_of(h);
|
362 |
+
if (que == nullptr) {
|
363 |
+
return;
|
364 |
+
}
|
365 |
+
que->shut_sending();
|
366 |
+
assert(info_of(h) != nullptr);
|
367 |
+
info_of(h)->disconnect_receiver();
|
368 |
+
}
|
369 |
+
|
370 |
+
static bool reconnect(ipc::handle_t * ph, bool start_to_recv) {
|
371 |
+
assert(ph != nullptr);
|
372 |
+
assert(*ph != nullptr);
|
373 |
+
auto que = queue_of(*ph);
|
374 |
+
if (que == nullptr) {
|
375 |
+
return false;
|
376 |
+
}
|
377 |
+
if (start_to_recv) {
|
378 |
+
que->shut_sending();
|
379 |
+
if (que->connect()) { // wouldn't connect twice
|
380 |
+
info_of(*ph)->cc_waiter_.broadcast();
|
381 |
+
return true;
|
382 |
+
}
|
383 |
+
return false;
|
384 |
+
}
|
385 |
+
// start_to_recv == false
|
386 |
+
if (que->connected()) {
|
387 |
+
info_of(*ph)->disconnect_receiver();
|
388 |
+
}
|
389 |
+
return que->ready_sending();
|
390 |
+
}
|
391 |
+
|
392 |
+
static bool connect(ipc::handle_t * ph, char const * name, bool start_to_recv) {
|
393 |
+
assert(ph != nullptr);
|
394 |
+
if (*ph == nullptr) {
|
395 |
+
*ph = ipc::mem::alloc<conn_info_t>(name);
|
396 |
+
}
|
397 |
+
return reconnect(ph, start_to_recv);
|
398 |
+
}
|
399 |
+
|
400 |
+
static void destroy(ipc::handle_t h) {
|
401 |
+
disconnect(h);
|
402 |
+
ipc::mem::free(info_of(h));
|
403 |
+
}
|
404 |
+
|
405 |
+
static std::size_t recv_count(ipc::handle_t h) noexcept {
|
406 |
+
auto que = queue_of(h);
|
407 |
+
if (que == nullptr) {
|
408 |
+
return ipc::invalid_value;
|
409 |
+
}
|
410 |
+
return que->conn_count();
|
411 |
+
}
|
412 |
+
|
413 |
+
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
|
414 |
+
auto que = queue_of(h);
|
415 |
+
if (que == nullptr) {
|
416 |
+
return false;
|
417 |
+
}
|
418 |
+
return wait_for(info_of(h)->cc_waiter_, [que, r_count] {
|
419 |
+
return que->conn_count() < r_count;
|
420 |
+
}, tm);
|
421 |
+
}
|
422 |
+
|
423 |
+
template <typename F>
|
424 |
+
static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t size) {
|
425 |
+
if (data == nullptr || size == 0) {
|
426 |
+
ipc::error("fail: send(%p, %zd)\n", data, size);
|
427 |
+
return false;
|
428 |
+
}
|
429 |
+
auto que = queue_of(h);
|
430 |
+
if (que == nullptr) {
|
431 |
+
ipc::error("fail: send, queue_of(h) == nullptr\n");
|
432 |
+
return false;
|
433 |
+
}
|
434 |
+
if (que->elems() == nullptr) {
|
435 |
+
ipc::error("fail: send, queue_of(h)->elems() == nullptr\n");
|
436 |
+
return false;
|
437 |
+
}
|
438 |
+
if (!que->ready_sending()) {
|
439 |
+
ipc::error("fail: send, que->ready_sending() == false\n");
|
440 |
+
return false;
|
441 |
+
}
|
442 |
+
ipc::circ::cc_t conns = que->elems()->connections(std::memory_order_relaxed);
|
443 |
+
if (conns == 0) {
|
444 |
+
ipc::error("fail: send, there is no receiver on this connection.\n");
|
445 |
+
return false;
|
446 |
+
}
|
447 |
+
// calc a new message id
|
448 |
+
auto acc = info_of(h)->acc();
|
449 |
+
if (acc == nullptr) {
|
450 |
+
ipc::error("fail: send, info_of(h)->acc() == nullptr\n");
|
451 |
+
return false;
|
452 |
+
}
|
453 |
+
auto msg_id = acc->fetch_add(1, std::memory_order_relaxed);
|
454 |
+
auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
|
455 |
+
if (size > ipc::large_msg_limit) {
|
456 |
+
auto dat = acquire_storage(size, conns);
|
457 |
+
void * buf = dat.second;
|
458 |
+
if (buf != nullptr) {
|
459 |
+
std::memcpy(buf, data, size);
|
460 |
+
return try_push(static_cast<std::int32_t>(size) -
|
461 |
+
static_cast<std::int32_t>(ipc::data_length), &(dat.first), 0);
|
462 |
+
}
|
463 |
+
// try using message fragment
|
464 |
+
//ipc::log("fail: shm::handle for big message. msg_id: %zd, size: %zd\n", msg_id, size);
|
465 |
+
}
|
466 |
+
// push message fragment
|
467 |
+
std::int32_t offset = 0;
|
468 |
+
for (std::int32_t i = 0; i < static_cast<std::int32_t>(size / ipc::data_length); ++i, offset += ipc::data_length) {
|
469 |
+
if (!try_push(static_cast<std::int32_t>(size) - offset - static_cast<std::int32_t>(ipc::data_length),
|
470 |
+
static_cast<ipc::byte_t const *>(data) + offset, ipc::data_length)) {
|
471 |
+
return false;
|
472 |
+
}
|
473 |
+
}
|
474 |
+
// if remain > 0, this is the last message fragment
|
475 |
+
std::int32_t remain = static_cast<std::int32_t>(size) - offset;
|
476 |
+
if (remain > 0) {
|
477 |
+
if (!try_push(remain - static_cast<std::int32_t>(ipc::data_length),
|
478 |
+
static_cast<ipc::byte_t const *>(data) + offset,
|
479 |
+
static_cast<std::size_t>(remain))) {
|
480 |
+
return false;
|
481 |
+
}
|
482 |
+
}
|
483 |
+
return true;
|
484 |
+
}
|
485 |
+
|
486 |
+
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
487 |
+
return send([tm](auto info, auto que, auto msg_id) {
|
488 |
+
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
489 |
+
if (!wait_for(info->wt_waiter_, [&] {
|
490 |
+
return !que->push(
|
491 |
+
[](void*) { return true; },
|
492 |
+
info->cc_id_, msg_id, remain, data, size);
|
493 |
+
}, tm)) {
|
494 |
+
ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
|
495 |
+
if (!que->force_push(
|
496 |
+
clear_message<typename queue_t::value_t>,
|
497 |
+
info->cc_id_, msg_id, remain, data, size)) {
|
498 |
+
return false;
|
499 |
+
}
|
500 |
+
}
|
501 |
+
info->rd_waiter_.broadcast();
|
502 |
+
return true;
|
503 |
+
};
|
504 |
+
}, h, data, size);
|
505 |
+
}
|
506 |
+
|
507 |
+
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
508 |
+
return send([tm](auto info, auto que, auto msg_id) {
|
509 |
+
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
510 |
+
if (!wait_for(info->wt_waiter_, [&] {
|
511 |
+
return !que->push(
|
512 |
+
[](void*) { return true; },
|
513 |
+
info->cc_id_, msg_id, remain, data, size);
|
514 |
+
}, tm)) {
|
515 |
+
return false;
|
516 |
+
}
|
517 |
+
info->rd_waiter_.broadcast();
|
518 |
+
return true;
|
519 |
+
};
|
520 |
+
}, h, data, size);
|
521 |
+
}
|
522 |
+
|
523 |
+
static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
|
524 |
+
auto que = queue_of(h);
|
525 |
+
if (que == nullptr) {
|
526 |
+
ipc::error("fail: recv, queue_of(h) == nullptr\n");
|
527 |
+
return {};
|
528 |
+
}
|
529 |
+
if (!que->connected()) {
|
530 |
+
// hasn't connected yet, just return.
|
531 |
+
return {};
|
532 |
+
}
|
533 |
+
auto& rc = info_of(h)->recv_cache();
|
534 |
+
for (;;) {
|
535 |
+
// pop a new message
|
536 |
+
typename queue_t::value_t msg;
|
537 |
+
if (!wait_for(info_of(h)->rd_waiter_, [que, &msg] {
|
538 |
+
return !que->pop(msg);
|
539 |
+
}, tm)) {
|
540 |
+
// pop failed, just return.
|
541 |
+
return {};
|
542 |
+
}
|
543 |
+
info_of(h)->wt_waiter_.broadcast();
|
544 |
+
if ((info_of(h)->acc() != nullptr) && (msg.cc_id_ == info_of(h)->cc_id_)) {
|
545 |
+
continue; // ignore message to self
|
546 |
+
}
|
547 |
+
// msg.remain_ may minus & abs(msg.remain_) < data_length
|
548 |
+
std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg.remain_;
|
549 |
+
if (r_size <= 0) {
|
550 |
+
ipc::error("fail: recv, r_size = %d\n", (int)r_size);
|
551 |
+
return {};
|
552 |
+
}
|
553 |
+
std::size_t msg_size = static_cast<std::size_t>(r_size);
|
554 |
+
// large message
|
555 |
+
if (msg.storage_) {
|
556 |
+
ipc::storage_id_t buf_id = *reinterpret_cast<ipc::storage_id_t*>(&msg.data_);
|
557 |
+
void* buf = find_storage(buf_id, msg_size);
|
558 |
+
if (buf != nullptr) {
|
559 |
+
struct recycle_t {
|
560 |
+
ipc::storage_id_t storage_id;
|
561 |
+
ipc::circ::cc_t curr_conns;
|
562 |
+
ipc::circ::cc_t conn_id;
|
563 |
+
} *r_info = ipc::mem::alloc<recycle_t>(recycle_t{
|
564 |
+
buf_id, que->elems()->connections(std::memory_order_relaxed), que->connected_id()
|
565 |
+
});
|
566 |
+
if (r_info == nullptr) {
|
567 |
+
ipc::log("fail: ipc::mem::alloc<recycle_t>.\n");
|
568 |
+
return ipc::buff_t{buf, msg_size}; // no recycle
|
569 |
+
} else {
|
570 |
+
return ipc::buff_t{buf, msg_size, [](void* p_info, std::size_t size) {
|
571 |
+
auto r_info = static_cast<recycle_t *>(p_info);
|
572 |
+
IPC_UNUSED_ auto finally = ipc::guard([r_info] {
|
573 |
+
ipc::mem::free(r_info);
|
574 |
+
});
|
575 |
+
recycle_storage<flag_t>(r_info->storage_id, size, r_info->curr_conns, r_info->conn_id);
|
576 |
+
}, r_info};
|
577 |
+
}
|
578 |
+
} else {
|
579 |
+
ipc::log("fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
|
580 |
+
continue;
|
581 |
+
}
|
582 |
+
}
|
583 |
+
// find cache with msg.id_
|
584 |
+
auto cac_it = rc.find(msg.id_);
|
585 |
+
if (cac_it == rc.end()) {
|
586 |
+
if (msg_size <= ipc::data_length) {
|
587 |
+
return make_cache(msg.data_, msg_size);
|
588 |
+
}
|
589 |
+
// gc
|
590 |
+
if (rc.size() > 1024) {
|
591 |
+
std::vector<msg_id_t> need_del;
|
592 |
+
for (auto const & pair : rc) {
|
593 |
+
auto cmp = std::minmax(msg.id_, pair.first);
|
594 |
+
if (cmp.second - cmp.first > 8192) {
|
595 |
+
need_del.push_back(pair.first);
|
596 |
+
}
|
597 |
+
}
|
598 |
+
for (auto id : need_del) rc.erase(id);
|
599 |
+
}
|
600 |
+
// cache the first message fragment
|
601 |
+
rc.emplace(msg.id_, cache_t { ipc::data_length, make_cache(msg.data_, msg_size) });
|
602 |
+
}
|
603 |
+
// has cached before this message
|
604 |
+
else {
|
605 |
+
auto& cac = cac_it->second;
|
606 |
+
// this is the last message fragment
|
607 |
+
if (msg.remain_ <= 0) {
|
608 |
+
cac.append(&(msg.data_), msg_size);
|
609 |
+
// finish this message, erase it from cache
|
610 |
+
auto buff = std::move(cac.buff_);
|
611 |
+
rc.erase(cac_it);
|
612 |
+
return buff;
|
613 |
+
}
|
614 |
+
// there are remain datas after this message
|
615 |
+
cac.append(&(msg.data_), ipc::data_length);
|
616 |
+
}
|
617 |
+
}
|
618 |
+
}
|
619 |
+
|
620 |
+
static ipc::buff_t try_recv(ipc::handle_t h) {
|
621 |
+
return recv(h, 0);
|
622 |
+
}
|
623 |
+
|
624 |
+
}; // detail_impl<Policy>
|
625 |
+
|
626 |
+
template <typename Flag>
|
627 |
+
using policy_t = ipc::policy::choose<ipc::circ::elem_array, Flag>;
|
628 |
+
|
629 |
+
} // internal-linkage
|
630 |
+
|
631 |
+
namespace ipc {
|
632 |
+
|
633 |
+
template <typename Flag>
|
634 |
+
ipc::handle_t chan_impl<Flag>::inited() {
|
635 |
+
ipc::detail::waiter::init();
|
636 |
+
return nullptr;
|
637 |
+
}
|
638 |
+
|
639 |
+
template <typename Flag>
|
640 |
+
bool chan_impl<Flag>::connect(ipc::handle_t * ph, char const * name, unsigned mode) {
|
641 |
+
return detail_impl<policy_t<Flag>>::connect(ph, name, mode & receiver);
|
642 |
+
}
|
643 |
+
|
644 |
+
template <typename Flag>
|
645 |
+
bool chan_impl<Flag>::reconnect(ipc::handle_t * ph, unsigned mode) {
|
646 |
+
return detail_impl<policy_t<Flag>>::reconnect(ph, mode & receiver);
|
647 |
+
}
|
648 |
+
|
649 |
+
template <typename Flag>
|
650 |
+
void chan_impl<Flag>::disconnect(ipc::handle_t h) {
|
651 |
+
detail_impl<policy_t<Flag>>::disconnect(h);
|
652 |
+
}
|
653 |
+
|
654 |
+
template <typename Flag>
|
655 |
+
void chan_impl<Flag>::destroy(ipc::handle_t h) {
|
656 |
+
detail_impl<policy_t<Flag>>::destroy(h);
|
657 |
+
}
|
658 |
+
|
659 |
+
template <typename Flag>
|
660 |
+
char const * chan_impl<Flag>::name(ipc::handle_t h) {
|
661 |
+
auto info = detail_impl<policy_t<Flag>>::info_of(h);
|
662 |
+
return (info == nullptr) ? nullptr : info->name_.c_str();
|
663 |
+
}
|
664 |
+
|
665 |
+
template <typename Flag>
|
666 |
+
std::size_t chan_impl<Flag>::recv_count(ipc::handle_t h) {
|
667 |
+
return detail_impl<policy_t<Flag>>::recv_count(h);
|
668 |
+
}
|
669 |
+
|
670 |
+
template <typename Flag>
|
671 |
+
bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
|
672 |
+
return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
|
673 |
+
}
|
674 |
+
|
675 |
+
template <typename Flag>
|
676 |
+
bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
677 |
+
return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
|
678 |
+
}
|
679 |
+
|
680 |
+
template <typename Flag>
|
681 |
+
buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::uint64_t tm) {
|
682 |
+
return detail_impl<policy_t<Flag>>::recv(h, tm);
|
683 |
+
}
|
684 |
+
|
685 |
+
template <typename Flag>
|
686 |
+
bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
687 |
+
return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
|
688 |
+
}
|
689 |
+
|
690 |
+
template <typename Flag>
|
691 |
+
buff_t chan_impl<Flag>::try_recv(ipc::handle_t h) {
|
692 |
+
return detail_impl<policy_t<Flag>>::try_recv(h);
|
693 |
+
}
|
694 |
+
|
695 |
+
template struct chan_impl<ipc::wr<relat::single, relat::single, trans::unicast >>;
|
696 |
+
// template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast >>; // TBD
|
697 |
+
// template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast >>; // TBD
|
698 |
+
template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::broadcast>>;
|
699 |
+
template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::broadcast>>;
|
700 |
+
|
701 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/policy.h
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <type_traits>
|
4 |
+
|
5 |
+
#include "libipc/def.h"
|
6 |
+
#include "libipc/prod_cons.h"
|
7 |
+
|
8 |
+
#include "libipc/circ/elem_array.h"
|
9 |
+
|
10 |
+
namespace ipc {
|
11 |
+
namespace policy {
|
12 |
+
|
13 |
+
template <template <typename, std::size_t...> class Elems, typename Flag>
|
14 |
+
struct choose;
|
15 |
+
|
16 |
+
template <typename Flag>
|
17 |
+
struct choose<circ::elem_array, Flag> {
|
18 |
+
using flag_t = Flag;
|
19 |
+
|
20 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
21 |
+
using elems_t = circ::elem_array<ipc::prod_cons_impl<flag_t>, DataSize, AlignSize>;
|
22 |
+
};
|
23 |
+
|
24 |
+
} // namespace policy
|
25 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/pool_alloc.cpp
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include "libipc/pool_alloc.h"
|
2 |
+
|
3 |
+
#include "libipc/memory/resource.h"
|
4 |
+
|
5 |
+
namespace ipc {
|
6 |
+
namespace mem {
|
7 |
+
|
8 |
+
void* pool_alloc::alloc(std::size_t size) {
|
9 |
+
return async_pool_alloc::alloc(size);
|
10 |
+
}
|
11 |
+
|
12 |
+
void pool_alloc::free(void* p, std::size_t size) {
|
13 |
+
async_pool_alloc::free(p, size);
|
14 |
+
}
|
15 |
+
|
16 |
+
} // namespace mem
|
17 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/prod_cons.h
ADDED
@@ -0,0 +1,433 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <atomic>
|
4 |
+
#include <utility>
|
5 |
+
#include <cstring>
|
6 |
+
#include <type_traits>
|
7 |
+
#include <cstdint>
|
8 |
+
|
9 |
+
#include "libipc/def.h"
|
10 |
+
|
11 |
+
#include "libipc/platform/detail.h"
|
12 |
+
#include "libipc/circ/elem_def.h"
|
13 |
+
#include "libipc/utility/log.h"
|
14 |
+
#include "libipc/utility/utility.h"
|
15 |
+
|
16 |
+
namespace ipc {
|
17 |
+
|
18 |
+
////////////////////////////////////////////////////////////////
|
19 |
+
/// producer-consumer implementation
|
20 |
+
////////////////////////////////////////////////////////////////
|
21 |
+
|
22 |
+
template <typename Flag>
|
23 |
+
struct prod_cons_impl;
|
24 |
+
|
25 |
+
template <>
|
26 |
+
struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
27 |
+
|
28 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
29 |
+
struct elem_t {
|
30 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
31 |
+
};
|
32 |
+
|
33 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
|
34 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
35 |
+
|
36 |
+
constexpr circ::u2_t cursor() const noexcept {
|
37 |
+
return 0;
|
38 |
+
}
|
39 |
+
|
40 |
+
template <typename W, typename F, typename E>
|
41 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
42 |
+
auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
|
43 |
+
if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
|
44 |
+
return false; // full
|
45 |
+
}
|
46 |
+
std::forward<F>(f)(&(elems[cur_wt].data_));
|
47 |
+
wt_.fetch_add(1, std::memory_order_release);
|
48 |
+
return true;
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
|
53 |
+
* So we could just disconnect all connections of receiver, and return false.
|
54 |
+
*/
|
55 |
+
template <typename W, typename F, typename E>
|
56 |
+
bool force_push(W* wrapper, F&&, E*) {
|
57 |
+
wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
template <typename W, typename F, typename R, typename E>
|
62 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
|
63 |
+
auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
|
64 |
+
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
|
65 |
+
return false; // empty
|
66 |
+
}
|
67 |
+
std::forward<F>(f)(&(elems[cur_rd].data_));
|
68 |
+
std::forward<R>(out)(true);
|
69 |
+
rd_.fetch_add(1, std::memory_order_release);
|
70 |
+
return true;
|
71 |
+
}
|
72 |
+
};
|
73 |
+
|
74 |
+
template <>
|
75 |
+
struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
|
76 |
+
: prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
77 |
+
|
78 |
+
template <typename W, typename F, typename E>
|
79 |
+
bool force_push(W* wrapper, F&&, E*) {
|
80 |
+
wrapper->elems()->disconnect_receiver(1);
|
81 |
+
return false;
|
82 |
+
}
|
83 |
+
|
84 |
+
template <typename W, typename F, typename R,
|
85 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
86 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
87 |
+
byte_t buff[DS];
|
88 |
+
for (unsigned k = 0;;) {
|
89 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
90 |
+
if (circ::index_of(cur_rd) ==
|
91 |
+
circ::index_of(wt_.load(std::memory_order_acquire))) {
|
92 |
+
return false; // empty
|
93 |
+
}
|
94 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
95 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
96 |
+
std::forward<F>(f)(buff);
|
97 |
+
std::forward<R>(out)(true);
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
ipc::yield(k);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
};
|
104 |
+
|
105 |
+
template <>
|
106 |
+
struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
|
107 |
+
: prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
|
108 |
+
|
109 |
+
using flag_t = std::uint64_t;
|
110 |
+
|
111 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
112 |
+
struct elem_t {
|
113 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
114 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
115 |
+
};
|
116 |
+
|
117 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
118 |
+
|
119 |
+
template <typename W, typename F, typename E>
|
120 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
121 |
+
circ::u2_t cur_ct, nxt_ct;
|
122 |
+
for (unsigned k = 0;;) {
|
123 |
+
cur_ct = ct_.load(std::memory_order_relaxed);
|
124 |
+
if (circ::index_of(nxt_ct = cur_ct + 1) ==
|
125 |
+
circ::index_of(rd_.load(std::memory_order_acquire))) {
|
126 |
+
return false; // full
|
127 |
+
}
|
128 |
+
if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
|
129 |
+
break;
|
130 |
+
}
|
131 |
+
ipc::yield(k);
|
132 |
+
}
|
133 |
+
auto* el = elems + circ::index_of(cur_ct);
|
134 |
+
std::forward<F>(f)(&(el->data_));
|
135 |
+
// set flag & try update wt
|
136 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
137 |
+
while (1) {
|
138 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
139 |
+
if (cur_ct != wt_.load(std::memory_order_relaxed)) {
|
140 |
+
return true;
|
141 |
+
}
|
142 |
+
if ((~cac_ct) != cur_ct) {
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
|
146 |
+
return true;
|
147 |
+
}
|
148 |
+
wt_.store(nxt_ct, std::memory_order_release);
|
149 |
+
cur_ct = nxt_ct;
|
150 |
+
nxt_ct = cur_ct + 1;
|
151 |
+
el = elems + circ::index_of(cur_ct);
|
152 |
+
}
|
153 |
+
return true;
|
154 |
+
}
|
155 |
+
|
156 |
+
template <typename W, typename F, typename E>
|
157 |
+
bool force_push(W* wrapper, F&&, E*) {
|
158 |
+
wrapper->elems()->disconnect_receiver(1);
|
159 |
+
return false;
|
160 |
+
}
|
161 |
+
|
162 |
+
template <typename W, typename F, typename R,
|
163 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
164 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
165 |
+
byte_t buff[DS];
|
166 |
+
for (unsigned k = 0;;) {
|
167 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
168 |
+
auto cur_wt = wt_.load(std::memory_order_acquire);
|
169 |
+
auto id_rd = circ::index_of(cur_rd);
|
170 |
+
auto id_wt = circ::index_of(cur_wt);
|
171 |
+
if (id_rd == id_wt) {
|
172 |
+
auto* el = elems + id_wt;
|
173 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
174 |
+
if ((~cac_ct) != cur_wt) {
|
175 |
+
return false; // empty
|
176 |
+
}
|
177 |
+
if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
|
178 |
+
wt_.store(cur_wt + 1, std::memory_order_release);
|
179 |
+
}
|
180 |
+
k = 0;
|
181 |
+
}
|
182 |
+
else {
|
183 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
184 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
185 |
+
std::forward<F>(f)(buff);
|
186 |
+
std::forward<R>(out)(true);
|
187 |
+
return true;
|
188 |
+
}
|
189 |
+
ipc::yield(k);
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
};
|
194 |
+
|
195 |
+
template <>
|
196 |
+
struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
197 |
+
|
198 |
+
using rc_t = std::uint64_t;
|
199 |
+
|
200 |
+
enum : rc_t {
|
201 |
+
ep_mask = 0x00000000ffffffffull,
|
202 |
+
ep_incr = 0x0000000100000000ull
|
203 |
+
};
|
204 |
+
|
205 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
206 |
+
struct elem_t {
|
207 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
208 |
+
std::atomic<rc_t> rc_ { 0 }; // read-counter
|
209 |
+
};
|
210 |
+
|
211 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
212 |
+
alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
|
213 |
+
|
214 |
+
circ::u2_t cursor() const noexcept {
|
215 |
+
return wt_.load(std::memory_order_acquire);
|
216 |
+
}
|
217 |
+
|
218 |
+
template <typename W, typename F, typename E>
|
219 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
220 |
+
E* el;
|
221 |
+
for (unsigned k = 0;;) {
|
222 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
223 |
+
if (cc == 0) return false; // no reader
|
224 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
225 |
+
// check all consumers have finished reading this element
|
226 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
227 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
228 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
|
229 |
+
return false; // has not finished yet
|
230 |
+
}
|
231 |
+
// consider rem_cc to be 0 here
|
232 |
+
if (el->rc_.compare_exchange_weak(
|
233 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
234 |
+
break;
|
235 |
+
}
|
236 |
+
ipc::yield(k);
|
237 |
+
}
|
238 |
+
std::forward<F>(f)(&(el->data_));
|
239 |
+
wt_.fetch_add(1, std::memory_order_release);
|
240 |
+
return true;
|
241 |
+
}
|
242 |
+
|
243 |
+
template <typename W, typename F, typename E>
|
244 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
245 |
+
E* el;
|
246 |
+
epoch_ += ep_incr;
|
247 |
+
for (unsigned k = 0;;) {
|
248 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
249 |
+
if (cc == 0) return false; // no reader
|
250 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
251 |
+
// check all consumers have finished reading this element
|
252 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
253 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
254 |
+
if (cc & rem_cc) {
|
255 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
256 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
257 |
+
if (cc == 0) return false; // no reader
|
258 |
+
}
|
259 |
+
// just compare & exchange
|
260 |
+
if (el->rc_.compare_exchange_weak(
|
261 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
262 |
+
break;
|
263 |
+
}
|
264 |
+
ipc::yield(k);
|
265 |
+
}
|
266 |
+
std::forward<F>(f)(&(el->data_));
|
267 |
+
wt_.fetch_add(1, std::memory_order_release);
|
268 |
+
return true;
|
269 |
+
}
|
270 |
+
|
271 |
+
template <typename W, typename F, typename R, typename E>
|
272 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
|
273 |
+
if (cur == cursor()) return false; // acquire
|
274 |
+
auto* el = elems + circ::index_of(cur++);
|
275 |
+
std::forward<F>(f)(&(el->data_));
|
276 |
+
for (unsigned k = 0;;) {
|
277 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
278 |
+
if ((cur_rc & ep_mask) == 0) {
|
279 |
+
std::forward<R>(out)(true);
|
280 |
+
return true;
|
281 |
+
}
|
282 |
+
auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
|
283 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
284 |
+
std::forward<R>(out)((nxt_rc & ep_mask) == 0);
|
285 |
+
return true;
|
286 |
+
}
|
287 |
+
ipc::yield(k);
|
288 |
+
}
|
289 |
+
}
|
290 |
+
};
|
291 |
+
|
292 |
+
template <>
|
293 |
+
struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
|
294 |
+
|
295 |
+
using rc_t = std::uint64_t;
|
296 |
+
using flag_t = std::uint64_t;
|
297 |
+
|
298 |
+
enum : rc_t {
|
299 |
+
rc_mask = 0x00000000ffffffffull,
|
300 |
+
ep_mask = 0x00ffffffffffffffull,
|
301 |
+
ep_incr = 0x0100000000000000ull,
|
302 |
+
ic_mask = 0xff000000ffffffffull,
|
303 |
+
ic_incr = 0x0000000100000000ull
|
304 |
+
};
|
305 |
+
|
306 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
307 |
+
struct elem_t {
|
308 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
309 |
+
std::atomic<rc_t > rc_ { 0 }; // read-counter
|
310 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
311 |
+
};
|
312 |
+
|
313 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
314 |
+
alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
|
315 |
+
|
316 |
+
circ::u2_t cursor() const noexcept {
|
317 |
+
return ct_.load(std::memory_order_acquire);
|
318 |
+
}
|
319 |
+
|
320 |
+
constexpr static rc_t inc_rc(rc_t rc) noexcept {
|
321 |
+
return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
|
322 |
+
}
|
323 |
+
|
324 |
+
constexpr static rc_t inc_mask(rc_t rc) noexcept {
|
325 |
+
return inc_rc(rc) & ~rc_mask;
|
326 |
+
}
|
327 |
+
|
328 |
+
template <typename W, typename F, typename E>
|
329 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
330 |
+
E* el;
|
331 |
+
circ::u2_t cur_ct;
|
332 |
+
rc_t epoch = epoch_.load(std::memory_order_acquire);
|
333 |
+
for (unsigned k = 0;;) {
|
334 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
335 |
+
if (cc == 0) return false; // no reader
|
336 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
337 |
+
// check all consumers have finished reading this element
|
338 |
+
auto cur_rc = el->rc_.load(std::memory_order_relaxed);
|
339 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
340 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
|
341 |
+
return false; // has not finished yet
|
342 |
+
}
|
343 |
+
else if (!rem_cc) {
|
344 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
345 |
+
if ((cur_fl != cur_ct) && cur_fl) {
|
346 |
+
return false; // full
|
347 |
+
}
|
348 |
+
}
|
349 |
+
// consider rem_cc to be 0 here
|
350 |
+
if (el->rc_.compare_exchange_weak(
|
351 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
|
352 |
+
epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
|
353 |
+
break;
|
354 |
+
}
|
355 |
+
ipc::yield(k);
|
356 |
+
}
|
357 |
+
// only one thread/process would touch here at one time
|
358 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
359 |
+
std::forward<F>(f)(&(el->data_));
|
360 |
+
// set flag & try update wt
|
361 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
362 |
+
return true;
|
363 |
+
}
|
364 |
+
|
365 |
+
template <typename W, typename F, typename E>
|
366 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
367 |
+
E* el;
|
368 |
+
circ::u2_t cur_ct;
|
369 |
+
rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
370 |
+
for (unsigned k = 0;;) {
|
371 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
372 |
+
if (cc == 0) return false; // no reader
|
373 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
374 |
+
// check all consumers have finished reading this element
|
375 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
376 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
377 |
+
if (cc & rem_cc) {
|
378 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
379 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
380 |
+
if (cc == 0) return false; // no reader
|
381 |
+
}
|
382 |
+
// just compare & exchange
|
383 |
+
if (el->rc_.compare_exchange_weak(
|
384 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
|
385 |
+
if (epoch == epoch_.load(std::memory_order_acquire)) {
|
386 |
+
break;
|
387 |
+
}
|
388 |
+
else if (push(wrapper, std::forward<F>(f), elems)) {
|
389 |
+
return true;
|
390 |
+
}
|
391 |
+
epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
392 |
+
}
|
393 |
+
ipc::yield(k);
|
394 |
+
}
|
395 |
+
// only one thread/process would touch here at one time
|
396 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
397 |
+
std::forward<F>(f)(&(el->data_));
|
398 |
+
// set flag & try update wt
|
399 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
400 |
+
return true;
|
401 |
+
}
|
402 |
+
|
403 |
+
template <typename W, typename F, typename R, typename E, std::size_t N>
|
404 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
|
405 |
+
auto* el = elems + circ::index_of(cur);
|
406 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
407 |
+
if (cur_fl != ~static_cast<flag_t>(cur)) {
|
408 |
+
return false; // empty
|
409 |
+
}
|
410 |
+
++cur;
|
411 |
+
std::forward<F>(f)(&(el->data_));
|
412 |
+
for (unsigned k = 0;;) {
|
413 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
414 |
+
if ((cur_rc & rc_mask) == 0) {
|
415 |
+
std::forward<R>(out)(true);
|
416 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
417 |
+
return true;
|
418 |
+
}
|
419 |
+
auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
|
420 |
+
bool last_one = false;
|
421 |
+
if ((last_one = (nxt_rc & rc_mask) == 0)) {
|
422 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
423 |
+
}
|
424 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
425 |
+
std::forward<R>(out)(last_one);
|
426 |
+
return true;
|
427 |
+
}
|
428 |
+
ipc::yield(k);
|
429 |
+
}
|
430 |
+
}
|
431 |
+
};
|
432 |
+
|
433 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/queue.h
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <type_traits>
|
4 |
+
#include <new>
|
5 |
+
#include <utility> // [[since C++14]]: std::exchange
|
6 |
+
#include <algorithm>
|
7 |
+
#include <atomic>
|
8 |
+
#include <tuple>
|
9 |
+
#include <thread>
|
10 |
+
#include <chrono>
|
11 |
+
#include <string>
|
12 |
+
#include <cassert> // assert
|
13 |
+
|
14 |
+
#include "libipc/def.h"
|
15 |
+
#include "libipc/shm.h"
|
16 |
+
#include "libipc/rw_lock.h"
|
17 |
+
|
18 |
+
#include "libipc/utility/log.h"
|
19 |
+
#include "libipc/platform/detail.h"
|
20 |
+
#include "libipc/circ/elem_def.h"
|
21 |
+
|
22 |
+
namespace ipc {
|
23 |
+
namespace detail {
|
24 |
+
|
25 |
+
class queue_conn {
|
26 |
+
protected:
|
27 |
+
circ::cc_t connected_ = 0;
|
28 |
+
shm::handle elems_h_;
|
29 |
+
|
30 |
+
template <typename Elems>
|
31 |
+
Elems* open(char const * name) {
|
32 |
+
if (name == nullptr || name[0] == '\0') {
|
33 |
+
ipc::error("fail open waiter: name is empty!\n");
|
34 |
+
return nullptr;
|
35 |
+
}
|
36 |
+
if (!elems_h_.acquire(name, sizeof(Elems))) {
|
37 |
+
return nullptr;
|
38 |
+
}
|
39 |
+
auto elems = static_cast<Elems*>(elems_h_.get());
|
40 |
+
if (elems == nullptr) {
|
41 |
+
ipc::error("fail acquire elems: %s\n", name);
|
42 |
+
return nullptr;
|
43 |
+
}
|
44 |
+
elems->init();
|
45 |
+
return elems;
|
46 |
+
}
|
47 |
+
|
48 |
+
void close() {
|
49 |
+
elems_h_.release();
|
50 |
+
}
|
51 |
+
|
52 |
+
public:
|
53 |
+
queue_conn() = default;
|
54 |
+
queue_conn(const queue_conn&) = delete;
|
55 |
+
queue_conn& operator=(const queue_conn&) = delete;
|
56 |
+
|
57 |
+
bool connected() const noexcept {
|
58 |
+
return connected_ != 0;
|
59 |
+
}
|
60 |
+
|
61 |
+
circ::cc_t connected_id() const noexcept {
|
62 |
+
return connected_;
|
63 |
+
}
|
64 |
+
|
65 |
+
template <typename Elems>
|
66 |
+
auto connect(Elems* elems) noexcept
|
67 |
+
/*needs 'optional' here*/
|
68 |
+
-> std::tuple<bool, bool, decltype(std::declval<Elems>().cursor())> {
|
69 |
+
if (elems == nullptr) return {};
|
70 |
+
// if it's already connected, just return
|
71 |
+
if (connected()) return {connected(), false, 0};
|
72 |
+
connected_ = elems->connect_receiver();
|
73 |
+
return {connected(), true, elems->cursor()};
|
74 |
+
}
|
75 |
+
|
76 |
+
template <typename Elems>
|
77 |
+
bool disconnect(Elems* elems) noexcept {
|
78 |
+
if (elems == nullptr) return false;
|
79 |
+
// if it's already disconnected, just return false
|
80 |
+
if (!connected()) return false;
|
81 |
+
elems->disconnect_receiver(std::exchange(connected_, 0));
|
82 |
+
return true;
|
83 |
+
}
|
84 |
+
};
|
85 |
+
|
86 |
+
template <typename Elems>
|
87 |
+
class queue_base : public queue_conn {
|
88 |
+
using base_t = queue_conn;
|
89 |
+
|
90 |
+
public:
|
91 |
+
using elems_t = Elems;
|
92 |
+
using policy_t = typename elems_t::policy_t;
|
93 |
+
|
94 |
+
protected:
|
95 |
+
elems_t * elems_ = nullptr;
|
96 |
+
decltype(std::declval<elems_t>().cursor()) cursor_ = 0;
|
97 |
+
bool sender_flag_ = false;
|
98 |
+
|
99 |
+
public:
|
100 |
+
using base_t::base_t;
|
101 |
+
|
102 |
+
queue_base() = default;
|
103 |
+
|
104 |
+
explicit queue_base(char const * name)
|
105 |
+
: queue_base{} {
|
106 |
+
elems_ = open<elems_t>(name);
|
107 |
+
}
|
108 |
+
|
109 |
+
explicit queue_base(elems_t * elems) noexcept
|
110 |
+
: queue_base{} {
|
111 |
+
assert(elems != nullptr);
|
112 |
+
elems_ = elems;
|
113 |
+
}
|
114 |
+
|
115 |
+
/* not virtual */ ~queue_base() {
|
116 |
+
base_t::close();
|
117 |
+
}
|
118 |
+
|
119 |
+
elems_t * elems() noexcept { return elems_; }
|
120 |
+
elems_t const * elems() const noexcept { return elems_; }
|
121 |
+
|
122 |
+
bool ready_sending() noexcept {
|
123 |
+
if (elems_ == nullptr) return false;
|
124 |
+
return sender_flag_ || (sender_flag_ = elems_->connect_sender());
|
125 |
+
}
|
126 |
+
|
127 |
+
void shut_sending() noexcept {
|
128 |
+
if (elems_ == nullptr) return;
|
129 |
+
if (!sender_flag_) return;
|
130 |
+
elems_->disconnect_sender();
|
131 |
+
}
|
132 |
+
|
133 |
+
bool connect() noexcept {
|
134 |
+
auto tp = base_t::connect(elems_);
|
135 |
+
if (std::get<0>(tp) && std::get<1>(tp)) {
|
136 |
+
cursor_ = std::get<2>(tp);
|
137 |
+
return true;
|
138 |
+
}
|
139 |
+
return std::get<0>(tp);
|
140 |
+
}
|
141 |
+
|
142 |
+
bool disconnect() noexcept {
|
143 |
+
return base_t::disconnect(elems_);
|
144 |
+
}
|
145 |
+
|
146 |
+
std::size_t conn_count() const noexcept {
|
147 |
+
return (elems_ == nullptr) ? static_cast<std::size_t>(invalid_value) : elems_->conn_count();
|
148 |
+
}
|
149 |
+
|
150 |
+
bool valid() const noexcept {
|
151 |
+
return elems_ != nullptr;
|
152 |
+
}
|
153 |
+
|
154 |
+
bool empty() const noexcept {
|
155 |
+
return !valid() || (cursor_ == elems_->cursor());
|
156 |
+
}
|
157 |
+
|
158 |
+
template <typename T, typename F, typename... P>
|
159 |
+
bool push(F&& prep, P&&... params) {
|
160 |
+
if (elems_ == nullptr) return false;
|
161 |
+
return elems_->push(this, [&](void* p) {
|
162 |
+
if (prep(p)) ::new (p) T(std::forward<P>(params)...);
|
163 |
+
});
|
164 |
+
}
|
165 |
+
|
166 |
+
template <typename T, typename F, typename... P>
|
167 |
+
bool force_push(F&& prep, P&&... params) {
|
168 |
+
if (elems_ == nullptr) return false;
|
169 |
+
return elems_->force_push(this, [&](void* p) {
|
170 |
+
if (prep(p)) ::new (p) T(std::forward<P>(params)...);
|
171 |
+
});
|
172 |
+
}
|
173 |
+
|
174 |
+
template <typename T, typename F>
|
175 |
+
bool pop(T& item, F&& out) {
|
176 |
+
if (elems_ == nullptr) {
|
177 |
+
return false;
|
178 |
+
}
|
179 |
+
return elems_->pop(this, &(this->cursor_), [&item](void* p) {
|
180 |
+
::new (&item) T(std::move(*static_cast<T*>(p)));
|
181 |
+
}, std::forward<F>(out));
|
182 |
+
}
|
183 |
+
};
|
184 |
+
|
185 |
+
} // namespace detail
|
186 |
+
|
187 |
+
template <typename T, typename Policy>
|
188 |
+
class queue final : public detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>> {
|
189 |
+
using base_t = detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>>;
|
190 |
+
|
191 |
+
public:
|
192 |
+
using value_t = T;
|
193 |
+
|
194 |
+
using base_t::base_t;
|
195 |
+
|
196 |
+
template <typename... P>
|
197 |
+
bool push(P&&... params) {
|
198 |
+
return base_t::template push<T>(std::forward<P>(params)...);
|
199 |
+
}
|
200 |
+
|
201 |
+
template <typename... P>
|
202 |
+
bool force_push(P&&... params) {
|
203 |
+
return base_t::template force_push<T>(std::forward<P>(params)...);
|
204 |
+
}
|
205 |
+
|
206 |
+
bool pop(T& item) {
|
207 |
+
return base_t::pop(item, [](bool) {});
|
208 |
+
}
|
209 |
+
|
210 |
+
template <typename F>
|
211 |
+
bool pop(T& item, F&& out) {
|
212 |
+
return base_t::pop(item, std::forward<F>(out));
|
213 |
+
}
|
214 |
+
};
|
215 |
+
|
216 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/shm.cpp
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
#include <string>
|
3 |
+
#include <utility>
|
4 |
+
|
5 |
+
#include "libipc/shm.h"
|
6 |
+
|
7 |
+
#include "libipc/utility/pimpl.h"
|
8 |
+
#include "libipc/memory/resource.h"
|
9 |
+
|
10 |
+
namespace ipc {
|
11 |
+
namespace shm {
|
12 |
+
|
13 |
+
class handle::handle_ : public pimpl<handle_> {
|
14 |
+
public:
|
15 |
+
shm::id_t id_ = nullptr;
|
16 |
+
void* m_ = nullptr;
|
17 |
+
|
18 |
+
ipc::string n_;
|
19 |
+
std::size_t s_ = 0;
|
20 |
+
};
|
21 |
+
|
22 |
+
handle::handle()
|
23 |
+
: p_(p_->make()) {
|
24 |
+
}
|
25 |
+
|
26 |
+
handle::handle(char const * name, std::size_t size, unsigned mode)
|
27 |
+
: handle() {
|
28 |
+
acquire(name, size, mode);
|
29 |
+
}
|
30 |
+
|
31 |
+
handle::handle(handle&& rhs)
|
32 |
+
: handle() {
|
33 |
+
swap(rhs);
|
34 |
+
}
|
35 |
+
|
36 |
+
handle::~handle() {
|
37 |
+
release();
|
38 |
+
p_->clear();
|
39 |
+
}
|
40 |
+
|
41 |
+
void handle::swap(handle& rhs) {
|
42 |
+
std::swap(p_, rhs.p_);
|
43 |
+
}
|
44 |
+
|
45 |
+
handle& handle::operator=(handle rhs) {
|
46 |
+
swap(rhs);
|
47 |
+
return *this;
|
48 |
+
}
|
49 |
+
|
50 |
+
bool handle::valid() const noexcept {
|
51 |
+
return impl(p_)->m_ != nullptr;
|
52 |
+
}
|
53 |
+
|
54 |
+
std::size_t handle::size() const noexcept {
|
55 |
+
return impl(p_)->s_;
|
56 |
+
}
|
57 |
+
|
58 |
+
char const * handle::name() const noexcept {
|
59 |
+
return impl(p_)->n_.c_str();
|
60 |
+
}
|
61 |
+
|
62 |
+
std::int32_t handle::ref() const noexcept {
|
63 |
+
return shm::get_ref(impl(p_)->id_);
|
64 |
+
}
|
65 |
+
|
66 |
+
void handle::sub_ref() noexcept {
|
67 |
+
shm::sub_ref(impl(p_)->id_);
|
68 |
+
}
|
69 |
+
|
70 |
+
bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
71 |
+
release();
|
72 |
+
impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
|
73 |
+
impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
|
74 |
+
return valid();
|
75 |
+
}
|
76 |
+
|
77 |
+
std::int32_t handle::release() {
|
78 |
+
if (impl(p_)->id_ == nullptr) return -1;
|
79 |
+
return shm::release(detach());
|
80 |
+
}
|
81 |
+
|
82 |
+
void* handle::get() const {
|
83 |
+
return impl(p_)->m_;
|
84 |
+
}
|
85 |
+
|
86 |
+
void handle::attach(id_t id) {
|
87 |
+
if (id == nullptr) return;
|
88 |
+
release();
|
89 |
+
impl(p_)->id_ = id;
|
90 |
+
impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
|
91 |
+
}
|
92 |
+
|
93 |
+
id_t handle::detach() {
|
94 |
+
auto old = impl(p_)->id_;
|
95 |
+
impl(p_)->id_ = nullptr;
|
96 |
+
impl(p_)->m_ = nullptr;
|
97 |
+
impl(p_)->s_ = 0;
|
98 |
+
impl(p_)->n_.clear();
|
99 |
+
return old;
|
100 |
+
}
|
101 |
+
|
102 |
+
} // namespace shm
|
103 |
+
} // namespace ipc
|
crazy_functions/test_project/cpp/cppipc/waiter.h
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <utility>
|
4 |
+
#include <string>
|
5 |
+
#include <mutex>
|
6 |
+
#include <atomic>
|
7 |
+
|
8 |
+
#include "libipc/def.h"
|
9 |
+
#include "libipc/mutex.h"
|
10 |
+
#include "libipc/condition.h"
|
11 |
+
#include "libipc/platform/detail.h"
|
12 |
+
|
13 |
+
namespace ipc {
|
14 |
+
namespace detail {
|
15 |
+
|
16 |
+
class waiter {
|
17 |
+
ipc::sync::condition cond_;
|
18 |
+
ipc::sync::mutex lock_;
|
19 |
+
std::atomic<bool> quit_ {false};
|
20 |
+
|
21 |
+
public:
|
22 |
+
static void init();
|
23 |
+
|
24 |
+
waiter() = default;
|
25 |
+
waiter(char const *name) {
|
26 |
+
open(name);
|
27 |
+
}
|
28 |
+
|
29 |
+
~waiter() {
|
30 |
+
close();
|
31 |
+
}
|
32 |
+
|
33 |
+
bool valid() const noexcept {
|
34 |
+
return cond_.valid() && lock_.valid();
|
35 |
+
}
|
36 |
+
|
37 |
+
bool open(char const *name) noexcept {
|
38 |
+
quit_.store(false, std::memory_order_relaxed);
|
39 |
+
if (!cond_.open((std::string{"_waiter_cond_"} + name).c_str())) {
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
if (!lock_.open((std::string{"_waiter_lock_"} + name).c_str())) {
|
43 |
+
cond_.close();
|
44 |
+
return false;
|
45 |
+
}
|
46 |
+
return valid();
|
47 |
+
}
|
48 |
+
|
49 |
+
void close() noexcept {
|
50 |
+
cond_.close();
|
51 |
+
lock_.close();
|
52 |
+
}
|
53 |
+
|
54 |
+
template <typename F>
|
55 |
+
bool wait_if(F &&pred, std::uint64_t tm = ipc::invalid_value) noexcept {
|
56 |
+
IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
|
57 |
+
while ([this, &pred] {
|
58 |
+
return !quit_.load(std::memory_order_relaxed)
|
59 |
+
&& std::forward<F>(pred)();
|
60 |
+
}()) {
|
61 |
+
if (!cond_.wait(lock_, tm)) return false;
|
62 |
+
}
|
63 |
+
return true;
|
64 |
+
}
|
65 |
+
|
66 |
+
bool notify() noexcept {
|
67 |
+
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
68 |
+
return cond_.notify(lock_);
|
69 |
+
}
|
70 |
+
|
71 |
+
bool broadcast() noexcept {
|
72 |
+
std::lock_guard<ipc::sync::mutex>{lock_}; // barrier
|
73 |
+
return cond_.broadcast(lock_);
|
74 |
+
}
|
75 |
+
|
76 |
+
bool quit_waiting() {
|
77 |
+
quit_.store(true, std::memory_order_release);
|
78 |
+
return broadcast();
|
79 |
+
}
|
80 |
+
};
|
81 |
+
|
82 |
+
} // namespace detail
|
83 |
+
} // namespace ipc
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/JpegLibrary.tps
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/UElibJPG.Build.cs
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/jpeg-compressor.tps
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/jpgd.cpp
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/jpgd.h
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/jpge.cpp
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/jpge.h
RENAMED
File without changes
|
crazy_functions/test_project/{Cpp → cpp}/libJPG/来源
RENAMED
File without changes
|
crazy_functions/test_project/其他测试
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"In practice, we found that a high-entropy initial state is more likely to increase the speed of training.
|
2 |
+
The entropy is calculated by:
|
3 |
+
$$H=-\sum_{k= 1}^{n_k} p(k) \cdot \log p(k), p(k)=\frac{|A_k|}{|\mathcal{A}|}$$
|
4 |
+
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.
|
5 |
+
To ensure the Cooperation Graph initialization has higher entropy,
|
6 |
+
we will randomly generate multiple initial states,
|
7 |
+
rank by their entropy and then pick the one with maximum $H$."
|
8 |
+
|
9 |
+
|
crazy_functions/生成函数注释.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from predict import predict_no_ui
|
2 |
+
from toolbox import CatchException, report_execption, write_results_to_file
|
3 |
+
fast_debug = False
|
4 |
+
|
5 |
+
|
6 |
+
def 生成函数注释(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
|
7 |
+
import time, glob, os
|
8 |
+
print('begin analysis on:', file_manifest)
|
9 |
+
for index, fp in enumerate(file_manifest):
|
10 |
+
with open(fp, 'r', encoding='utf-8') as f:
|
11 |
+
file_content = f.read()
|
12 |
+
|
13 |
+
i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
|
14 |
+
i_say_show_user = f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
|
15 |
+
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
16 |
+
print('[1] yield chatbot, history')
|
17 |
+
yield chatbot, history, '正常'
|
18 |
+
|
19 |
+
if not fast_debug:
|
20 |
+
msg = '正常'
|
21 |
+
# ** gpt request **
|
22 |
+
while True:
|
23 |
+
try:
|
24 |
+
gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature)
|
25 |
+
break
|
26 |
+
except ConnectionAbortedError as e:
|
27 |
+
i_say = i_say[:len(i_say)//2]
|
28 |
+
msg = '文件太长,进行了拦腰截断'
|
29 |
+
|
30 |
+
print('[2] end gpt req')
|
31 |
+
chatbot[-1] = (i_say_show_user, gpt_say)
|
32 |
+
history.append(i_say_show_user); history.append(gpt_say)
|
33 |
+
print('[3] yield chatbot, history')
|
34 |
+
yield chatbot, history, msg
|
35 |
+
print('[4] next')
|
36 |
+
if not fast_debug: time.sleep(2)
|
37 |
+
|
38 |
+
if not fast_debug:
|
39 |
+
res = write_results_to_file(history)
|
40 |
+
chatbot.append(("完成了吗?", res))
|
41 |
+
yield chatbot, history, msg
|
42 |
+
|
43 |
+
|
44 |
+
|
45 |
+
@CatchException
|
46 |
+
def 批量生成函数注释(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
47 |
+
history = [] # 清空历史,以免输入溢出
|
48 |
+
import glob, os
|
49 |
+
if os.path.exists(txt):
|
50 |
+
project_folder = txt
|
51 |
+
else:
|
52 |
+
if txt == "": txt = '空空如也的输入栏'
|
53 |
+
report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
54 |
+
yield chatbot, history, '正常'
|
55 |
+
return
|
56 |
+
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)] + \
|
57 |
+
[f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)]
|
58 |
+
|
59 |
+
if len(file_manifest) == 0:
|
60 |
+
report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}")
|
61 |
+
yield chatbot, history, '正常'
|
62 |
+
return
|
63 |
+
yield from 生成函数注释(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)
|
functional_crazy.py
CHANGED
@@ -157,9 +157,10 @@ def 解析一个C项目的头文件(txt, top_p, temperature, chatbot, history, s
|
|
157 |
|
158 |
def get_crazy_functionals():
|
159 |
from crazy_functions.读文章写摘要 import 读文章写摘要
|
|
|
|
|
160 |
return {
|
161 |
"[实验功能] 请解析并解构此项目本身": {
|
162 |
-
"Color": "stop", # 按钮颜色
|
163 |
"Function": 解析项目本身
|
164 |
},
|
165 |
"[实验功能] 解析整个Python项目(input输入项目根路径)": {
|
@@ -174,6 +175,10 @@ def get_crazy_functionals():
|
|
174 |
"Color": "stop", # 按钮颜色
|
175 |
"Function": 读文章写摘要
|
176 |
},
|
|
|
|
|
|
|
|
|
177 |
"[实验功能] 高阶功能模板函数": {
|
178 |
"Color": "stop", # 按钮颜色
|
179 |
"Function": 高阶功能模板函数
|
|
|
157 |
|
158 |
def get_crazy_functionals():
|
159 |
from crazy_functions.读文章写摘要 import 读文章写摘要
|
160 |
+
from crazy_functions.生成函数注释 import 批量生成函数注释
|
161 |
+
|
162 |
return {
|
163 |
"[实验功能] 请解析并解构此项目本身": {
|
|
|
164 |
"Function": 解析项目本身
|
165 |
},
|
166 |
"[实验功能] 解析整个Python项目(input输入项目根路径)": {
|
|
|
175 |
"Color": "stop", # 按钮颜色
|
176 |
"Function": 读文章写摘要
|
177 |
},
|
178 |
+
"[实验功能] 批量生成函数注释(input输入项目根路径)": {
|
179 |
+
"Color": "stop", # 按钮颜色
|
180 |
+
"Function": 批量生成函数注释
|
181 |
+
},
|
182 |
"[实验功能] 高阶功能模板函数": {
|
183 |
"Color": "stop", # 按钮颜色
|
184 |
"Function": 高阶功能模板函数
|
toolbox.py
CHANGED
@@ -13,7 +13,7 @@ def write_results_to_file(history, file_name=None):
|
|
13 |
if i%2==0: f.write('## ')
|
14 |
f.write(content)
|
15 |
f.write('\n\n')
|
16 |
-
res ='以上材料已经被写入'
|
17 |
print(res)
|
18 |
return res
|
19 |
|
|
|
13 |
if i%2==0: f.write('## ')
|
14 |
f.write(content)
|
15 |
f.write('\n\n')
|
16 |
+
res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')
|
17 |
print(res)
|
18 |
return res
|
19 |
|