20
20
21
21
#include " libipc/utility/log.h"
22
22
#include " libipc/utility/id_pool.h"
23
+ #include " libipc/utility/scope_guard.h"
23
24
#include " libipc/utility/utility.h"
24
25
25
26
#include " libipc/memory/resource.h"
@@ -39,7 +40,7 @@ struct msg_t;
39
40
40
41
template <std::size_t AlignSize>
41
42
struct msg_t <0 , AlignSize> {
42
- msg_id_t conn_ ;
43
+ msg_id_t cc_id_ ;
43
44
msg_id_t id_;
44
45
std::int32_t remain_;
45
46
bool storage_;
@@ -50,8 +51,8 @@ struct msg_t : msg_t<0, AlignSize> {
50
51
std::aligned_storage_t <DataSize, AlignSize> data_ {};
51
52
52
53
msg_t () = default ;
53
- msg_t (msg_id_t conn , msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
54
- : msg_t <0 , AlignSize> {conn , id, remain, (data == nullptr ) || (size == 0 )} {
54
+ msg_t (msg_id_t cc_id , msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
55
+ : msg_t <0 , AlignSize> {cc_id , id, remain, (data == nullptr ) || (size == 0 )} {
55
56
if (this ->storage_ ) {
56
57
if (data != nullptr ) {
57
58
// copy storage-id
@@ -96,9 +97,21 @@ IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
96
97
}
97
98
98
99
IPC_CONSTEXPR_ std::size_t calc_chunk_size (std::size_t size) noexcept {
99
- return ipc::make_align (alignof (std::max_align_t ), align_chunk_size (size));
100
+ return ipc::make_align (alignof (std::max_align_t ), align_chunk_size (
101
+ ipc::make_align (alignof (std::max_align_t ), sizeof (std::atomic<ipc::circ::cc_t >)) + size));
100
102
}
101
103
104
+ struct chunk_t {
105
+ std::atomic<ipc::circ::cc_t > &conns () noexcept {
106
+ return *reinterpret_cast <std::atomic<ipc::circ::cc_t > *>(this );
107
+ }
108
+
109
+ void *data () noexcept {
110
+ return reinterpret_cast <ipc::byte_t *>(this )
111
+ + ipc::make_align (alignof (std::max_align_t ), sizeof (std::atomic<ipc::circ::cc_t >));
112
+ }
113
+ };
114
+
102
115
struct chunk_info_t {
103
116
ipc::id_pool<> pool_;
104
117
ipc::spin_lock lock_;
@@ -107,13 +120,13 @@ struct chunk_info_t {
107
120
return ipc::id_pool<>::max_count * chunk_size;
108
121
}
109
122
110
- ipc::byte_t * chunks_mem () noexcept {
111
- return reinterpret_cast <ipc::byte_t *>(this + 1 );
123
+ ipc::byte_t * chunks_mem () noexcept {
124
+ return reinterpret_cast <ipc::byte_t *>(this + 1 );
112
125
}
113
126
114
- ipc:: byte_t * at (std::size_t chunk_size, ipc::storage_id_t id) noexcept {
127
+ chunk_t * at (std::size_t chunk_size, ipc::storage_id_t id) noexcept {
115
128
if (id < 0 ) return nullptr ;
116
- return chunks_mem () + (chunk_size * id);
129
+ return reinterpret_cast < chunk_t *>( chunks_mem () + (chunk_size * id) );
117
130
}
118
131
};
119
132
@@ -145,7 +158,7 @@ chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
145
158
return chunk_storages ()[chunk_size].get_info (chunk_size);
146
159
}
147
160
148
- std::pair<ipc::storage_id_t , void *> acquire_storage (std::size_t size) {
161
+ std::pair<ipc::storage_id_t , void *> acquire_storage (std::size_t size, ipc::circ:: cc_t conns ) {
149
162
std::size_t chunk_size = calc_chunk_size (size);
150
163
auto info = chunk_storage_info (chunk_size);
151
164
if (info == nullptr ) return {};
@@ -156,7 +169,10 @@ std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size) {
156
169
auto id = info->pool_ .acquire ();
157
170
info->lock_ .unlock ();
158
171
159
- return { id, info->at (chunk_size, id) };
172
+ auto chunk = info->at (chunk_size, id);
173
+ if (chunk == nullptr ) return {};
174
+ chunk->conns ().store (conns, std::memory_order_relaxed);
175
+ return { id, chunk->data () };
160
176
}
161
177
162
178
void *find_storage (ipc::storage_id_t id, std::size_t size) {
@@ -167,7 +183,7 @@ void *find_storage(ipc::storage_id_t id, std::size_t size) {
167
183
std::size_t chunk_size = calc_chunk_size (size);
168
184
auto info = chunk_storage_info (chunk_size);
169
185
if (info == nullptr ) return nullptr ;
170
- return info->at (chunk_size, id);
186
+ return info->at (chunk_size, id)-> data () ;
171
187
}
172
188
173
189
void release_storage (ipc::storage_id_t id, std::size_t size) {
@@ -183,13 +199,53 @@ void release_storage(ipc::storage_id_t id, std::size_t size) {
183
199
info->lock_ .unlock ();
184
200
}
185
201
202
+ template <ipc::relat Rp, ipc::relat Rc>
203
+ bool sub_rc (ipc::wr<Rp, Rc, ipc::trans::unicast>,
204
+ std::atomic<ipc::circ::cc_t > &/* conns*/ , ipc::circ::cc_t /* curr_conns*/ , ipc::circ::cc_t /* conn_id*/ ) noexcept {
205
+ return true ;
206
+ }
207
+
208
+ template <ipc::relat Rp, ipc::relat Rc>
209
+ bool sub_rc (ipc::wr<Rp, Rc, ipc::trans::broadcast>,
210
+ std::atomic<ipc::circ::cc_t > &conns, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) noexcept {
211
+ auto last_conns = curr_conns & ~conn_id;
212
+ for (unsigned k = 0 ;;) {
213
+ auto chunk_conns = conns.load (std::memory_order_acquire);
214
+ if (conns.compare_exchange_weak (chunk_conns, chunk_conns & last_conns, std::memory_order_release)) {
215
+ return (chunk_conns & last_conns) == 0 ;
216
+ }
217
+ ipc::yield (k);
218
+ }
219
+ }
220
+
221
+ template <typename Flag>
222
+ void recycle_storage (ipc::storage_id_t id, std::size_t size, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) {
223
+ if (id < 0 ) {
224
+ ipc::error (" [recycle_storage] id is invalid: id = %ld, size = %zd\n " , (long )id, size);
225
+ return ;
226
+ }
227
+ std::size_t chunk_size = calc_chunk_size (size);
228
+ auto info = chunk_storage_info (chunk_size);
229
+ if (info == nullptr ) return ;
230
+
231
+ auto chunk = info->at (chunk_size, id);
232
+ if (chunk == nullptr ) return ;
233
+
234
+ if (!sub_rc (Flag{}, chunk->conns (), curr_conns, conn_id)) {
235
+ return ;
236
+ }
237
+ info->lock_ .lock ();
238
+ info->pool_ .release (id);
239
+ info->lock_ .unlock ();
240
+ }
241
+
186
242
template <typename MsgT>
187
- bool recycle_message (void * p) {
243
+ bool clear_message (void * p) {
188
244
auto msg = static_cast <MsgT*>(p);
189
245
if (msg->storage_ ) {
190
246
std::int32_t r_size = static_cast <std::int32_t >(ipc::data_length) + msg->remain_ ;
191
247
if (r_size <= 0 ) {
192
- ipc::error (" [recycle_message ] invalid msg size: %d\n " , (int )r_size);
248
+ ipc::error (" [clear_message ] invalid msg size: %d\n " , (int )r_size);
193
249
return true ;
194
250
}
195
251
release_storage (
@@ -278,8 +334,10 @@ struct queue_generator {
278
334
template <typename Policy>
279
335
struct detail_impl {
280
336
281
- using queue_t = typename queue_generator<Policy>::queue_t ;
282
- using conn_info_t = typename queue_generator<Policy>::conn_info_t ;
337
+ using policy_t = Policy;
338
+ using flag_t = typename policy_t ::flag_t ;
339
+ using queue_t = typename queue_generator<policy_t >::queue_t ;
340
+ using conn_info_t = typename queue_generator<policy_t >::conn_info_t ;
283
341
284
342
constexpr static conn_info_t * info_of (ipc::handle_t h) noexcept {
285
343
return static_cast <conn_info_t *>(h);
@@ -373,7 +431,8 @@ static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t s
373
431
ipc::error (" fail: send, que->ready_sending() == false\n " );
374
432
return false ;
375
433
}
376
- if (que->elems ()->connections (std::memory_order_relaxed) == 0 ) {
434
+ ipc::circ::cc_t conns = que->elems ()->connections (std::memory_order_relaxed);
435
+ if (conns == 0 ) {
377
436
ipc::error (" fail: send, there is no receiver on this connection.\n " );
378
437
return false ;
379
438
}
@@ -386,7 +445,7 @@ static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t s
386
445
auto msg_id = acc->fetch_add (1 , std::memory_order_relaxed);
387
446
auto try_push = std::forward<F>(gen_push)(info_of (h), que, msg_id);
388
447
if (size > ipc::large_msg_limit) {
389
- auto dat = acquire_storage (size);
448
+ auto dat = acquire_storage (size, conns );
390
449
void * buf = dat.second ;
391
450
if (buf != nullptr ) {
392
451
std::memcpy (buf, data, size);
@@ -426,7 +485,7 @@ static bool send(ipc::handle_t h, void const * data, std::size_t size, std::size
426
485
}, tm)) {
427
486
ipc::log (" force_push: msg_id = %zd, remain = %d, size = %zd\n " , msg_id, remain, size);
428
487
if (!que->force_push (
429
- recycle_message <typename queue_t ::value_t >,
488
+ clear_message <typename queue_t ::value_t >,
430
489
info->cc_id_ , msg_id, remain, data, size)) {
431
490
return false ;
432
491
}
@@ -467,15 +526,14 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
467
526
for (;;) {
468
527
// pop a new message
469
528
typename queue_t ::value_t msg;
470
- bool recycled = false ;
471
- if (!wait_for (info_of (h)->rd_waiter_ , [que, &msg, &recycled] {
472
- return !que->pop (msg, [&recycled](bool r) { recycled = r; });
529
+ if (!wait_for (info_of (h)->rd_waiter_ , [que, &msg] {
530
+ return !que->pop (msg);
473
531
}, tm)) {
474
532
// pop failed, just return.
475
533
return {};
476
534
}
477
535
info_of (h)->wt_waiter_ .broadcast ();
478
- if ((info_of (h)->acc () != nullptr ) && (msg.conn_ == info_of (h)->cc_id_ )) {
536
+ if ((info_of (h)->acc () != nullptr ) && (msg.cc_id_ == info_of (h)->cc_id_ )) {
479
537
continue ; // ignore message to self
480
538
}
481
539
// msg.remain_ may minus & abs(msg.remain_) < data_length
@@ -490,12 +548,24 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
490
548
ipc::storage_id_t buf_id = *reinterpret_cast <ipc::storage_id_t *>(&msg.data_ );
491
549
void * buf = find_storage (buf_id, msg_size);
492
550
if (buf != nullptr ) {
493
- if (recycled) {
494
- return ipc::buff_t {buf, msg_size, [](void * pmid, std::size_t size) {
495
- release_storage (ipc::detail::horrible_cast<ipc::storage_id_t >(pmid) - 1 , size);
496
- }, ipc::detail::horrible_cast<void *>(buf_id + 1 )};
497
- } else {
551
+ struct recycle_t {
552
+ ipc::storage_id_t storage_id;
553
+ ipc::circ::cc_t curr_conns;
554
+ ipc::circ::cc_t conn_id;
555
+ } *r_info = ipc::mem::alloc<recycle_t >(recycle_t {
556
+ buf_id, que->elems ()->connections (std::memory_order_relaxed), que->connected_id ()
557
+ });
558
+ if (r_info == nullptr ) {
559
+ ipc::log (" fail: ipc::mem::alloc<recycle_t>.\n " );
498
560
return ipc::buff_t {buf, msg_size}; // no recycle
561
+ } else {
562
+ return ipc::buff_t {buf, msg_size, [](void * p_info, std::size_t size) {
563
+ auto r_info = static_cast <recycle_t *>(p_info);
564
+ IPC_UNUSED_ auto finally = ipc::guard ([r_info] {
565
+ ipc::mem::free (r_info);
566
+ });
567
+ recycle_storage<flag_t >(r_info->storage_id , size, r_info->curr_conns , r_info->conn_id );
568
+ }, r_info};
499
569
}
500
570
} else {
501
571
ipc::log (" fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n " , msg.id_ , buf_id, msg_size);
0 commit comments