3v324v23 commited on
Commit
77408f7
1 Parent(s): 32f36a6

批量生成函数注释

Browse files
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 ='以上材料已经被写入', f'./gpt_log/{file_name}'
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