blob: 0ebce702430ed23e1b1d550252cf5996ccaab254 [file] [log] [blame]
Florin Coras65784c12018-07-04 04:17:41 -07001/*
2 * Copyright (c) 2018 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <svm/message_queue.h>
17#include <vppinfra/mem.h>
Nathan Skrzypczakcfdb1092019-12-02 16:44:42 +010018#include <vppinfra/format.h>
Florin Coras99368312018-08-02 10:45:44 -070019#include <sys/eventfd.h>
Florin Coras65784c12018-07-04 04:17:41 -070020
Florin Coras3c2fed52018-07-04 04:15:05 -070021static inline svm_msg_q_ring_t *
22svm_msg_q_ring_inline (svm_msg_q_t * mq, u32 ring_index)
23{
24 return vec_elt_at_index (mq->rings, ring_index);
25}
26
27svm_msg_q_ring_t *
28svm_msg_q_ring (svm_msg_q_t * mq, u32 ring_index)
29{
30 return svm_msg_q_ring_inline (mq, ring_index);
31}
32
33static inline void *
34svm_msg_q_ring_data (svm_msg_q_ring_t * ring, u32 elt_index)
35{
36 ASSERT (elt_index < ring->nitems);
Florin Corasb4624182020-12-11 13:58:12 -080037 return (ring->shr->data + elt_index * ring->elsize);
Florin Coras3c2fed52018-07-04 04:15:05 -070038}
39
Florin Corasb4624182020-12-11 13:58:12 -080040svm_msg_q_shared_t *
Florin Coras213b1bb2020-12-07 14:33:58 -080041svm_msg_q_init (void *base, svm_msg_q_cfg_t *cfg)
Florin Coras65784c12018-07-04 04:17:41 -070042{
Florin Corasb4624182020-12-11 13:58:12 -080043 svm_msg_q_ring_shared_t *ring;
44 svm_msg_q_shared_t *smq;
45 u32 q_sz, offset;
Florin Coras65784c12018-07-04 04:17:41 -070046 int i;
47
Florin Corasc470e222018-08-01 07:53:18 -070048 q_sz = sizeof (svm_queue_t) + cfg->q_nitems * sizeof (svm_msg_q_msg_t);
Florin Coras65784c12018-07-04 04:17:41 -070049
Florin Corasb4624182020-12-11 13:58:12 -080050 smq = (svm_msg_q_shared_t *) base;
51 svm_queue_init (&smq->q, cfg->q_nitems, sizeof (svm_msg_q_msg_t));
52 smq->q->consumer_pid = cfg->consumer_pid;
53 smq->n_rings = cfg->n_rings;
54 ring = (void *) ((u8 *) smq->q + q_sz);
Florin Coras65784c12018-07-04 04:17:41 -070055 for (i = 0; i < cfg->n_rings; i++)
56 {
Florin Coras65784c12018-07-04 04:17:41 -070057 ring->elsize = cfg->ring_cfgs[i].elsize;
58 ring->nitems = cfg->ring_cfgs[i].nitems;
Florin Coras54693d22018-07-17 10:46:29 -070059 ring->cursize = ring->head = ring->tail = 0;
Florin Corasb4624182020-12-11 13:58:12 -080060 offset = sizeof (*ring) + ring->nitems * ring->elsize;
61 ring = (void *) ((u8 *) ring + offset);
Florin Coras65784c12018-07-04 04:17:41 -070062 }
63
Florin Corasb4624182020-12-11 13:58:12 -080064 return smq;
Florin Coras65784c12018-07-04 04:17:41 -070065}
66
Florin Coras213b1bb2020-12-07 14:33:58 -080067uword
68svm_msg_q_size_to_alloc (svm_msg_q_cfg_t *cfg)
69{
70 svm_msg_q_ring_cfg_t *ring_cfg;
71 uword rings_sz = 0, mq_sz;
Florin Corasb4624182020-12-11 13:58:12 -080072 u32 q_sz;
Florin Coras213b1bb2020-12-07 14:33:58 -080073 int i;
74
75 ASSERT (cfg);
76
Florin Corasb4624182020-12-11 13:58:12 -080077 rings_sz = sizeof (svm_msg_q_ring_shared_t) * cfg->n_rings;
Florin Coras213b1bb2020-12-07 14:33:58 -080078 for (i = 0; i < cfg->n_rings; i++)
79 {
80 if (cfg->ring_cfgs[i].data)
81 continue;
82 ring_cfg = &cfg->ring_cfgs[i];
83 rings_sz += (uword) ring_cfg->nitems * ring_cfg->elsize;
84 }
85
86 q_sz = sizeof (svm_queue_t) + cfg->q_nitems * sizeof (svm_msg_q_msg_t);
Florin Corasb4624182020-12-11 13:58:12 -080087 mq_sz = sizeof (svm_msg_q_shared_t) + q_sz + rings_sz;
Florin Coras213b1bb2020-12-07 14:33:58 -080088
89 return mq_sz;
90}
91
Florin Corasb4624182020-12-11 13:58:12 -080092svm_msg_q_shared_t *
Florin Coras213b1bb2020-12-07 14:33:58 -080093svm_msg_q_alloc (svm_msg_q_cfg_t *cfg)
94{
Florin Corasb4624182020-12-11 13:58:12 -080095 uword mq_sz;
Florin Coras213b1bb2020-12-07 14:33:58 -080096 u8 *base;
Florin Coras213b1bb2020-12-07 14:33:58 -080097
Florin Corasb4624182020-12-11 13:58:12 -080098 mq_sz = svm_msg_q_size_to_alloc (cfg);
Florin Coras213b1bb2020-12-07 14:33:58 -080099 base = clib_mem_alloc_aligned (mq_sz, CLIB_CACHE_LINE_BYTES);
100 if (!base)
101 return 0;
102
103 return svm_msg_q_init (base, cfg);
104}
105
Florin Coras65784c12018-07-04 04:17:41 -0700106void
Florin Corasb4624182020-12-11 13:58:12 -0800107svm_msg_q_attach (svm_msg_q_t *mq, void *smq_base)
108{
109 svm_msg_q_ring_shared_t *ring;
110 svm_msg_q_shared_t *smq;
111 u32 i, n_rings, q_sz, offset;
112
113 smq = (svm_msg_q_shared_t *) smq_base;
114 mq->q = smq->q;
115 n_rings = smq->n_rings;
116 vec_validate (mq->rings, n_rings - 1);
117 q_sz = sizeof (svm_queue_t) + mq->q->maxsize * sizeof (svm_msg_q_msg_t);
118 ring = (void *) ((u8 *) smq->q + q_sz);
119 for (i = 0; i < n_rings; i++)
120 {
121 mq->rings[i].nitems = ring->nitems;
122 mq->rings[i].elsize = ring->elsize;
123 mq->rings[i].shr = ring;
124 offset = sizeof (*ring) + ring->nitems * ring->elsize;
125 ring = (void *) ((u8 *) ring + offset);
126 }
127}
128
129void
Florin Coras65784c12018-07-04 04:17:41 -0700130svm_msg_q_free (svm_msg_q_t * mq)
131{
Florin Corase91bdb32018-07-11 16:35:38 -0700132 svm_queue_free (mq->q);
Florin Coras65784c12018-07-04 04:17:41 -0700133 clib_mem_free (mq);
134}
135
136svm_msg_q_msg_t
Florin Coras3c2fed52018-07-04 04:15:05 -0700137svm_msg_q_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index)
138{
Florin Corasb4624182020-12-11 13:58:12 -0800139 svm_msg_q_ring_shared_t *sr;
140 svm_msg_q_ring_t *ring;
Florin Coras54693d22018-07-17 10:46:29 -0700141 svm_msg_q_msg_t msg;
Florin Coras3c2fed52018-07-04 04:15:05 -0700142
Florin Corasb4624182020-12-11 13:58:12 -0800143 ring = svm_msg_q_ring_inline (mq, ring_index);
144 sr = ring->shr;
145
146 ASSERT (sr->cursize < ring->nitems);
Florin Coras3c2fed52018-07-04 04:15:05 -0700147 msg.ring_index = ring - mq->rings;
Florin Corasb4624182020-12-11 13:58:12 -0800148 msg.elt_index = sr->tail;
149 sr->tail = (sr->tail + 1) % ring->nitems;
150 clib_atomic_fetch_add (&sr->cursize, 1);
Florin Coras3c2fed52018-07-04 04:15:05 -0700151 return msg;
152}
153
154int
155svm_msg_q_lock_and_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index,
156 u8 noblock, svm_msg_q_msg_t * msg)
157{
158 if (noblock)
159 {
160 if (svm_msg_q_try_lock (mq))
161 return -1;
Florin Coras2b5fed82019-07-25 14:51:09 -0700162 if (PREDICT_FALSE (svm_msg_q_is_full (mq)
163 || svm_msg_q_ring_is_full (mq, ring_index)))
Florin Coras3c2fed52018-07-04 04:15:05 -0700164 {
165 svm_msg_q_unlock (mq);
166 return -2;
167 }
168 *msg = svm_msg_q_alloc_msg_w_ring (mq, ring_index);
Florin Coras3c2fed52018-07-04 04:15:05 -0700169 }
170 else
171 {
172 svm_msg_q_lock (mq);
Florin Coras2b5fed82019-07-25 14:51:09 -0700173 while (svm_msg_q_is_full (mq)
174 || svm_msg_q_ring_is_full (mq, ring_index))
Florin Coras54693d22018-07-17 10:46:29 -0700175 svm_msg_q_wait (mq);
Florin Coras3c2fed52018-07-04 04:15:05 -0700176 *msg = svm_msg_q_alloc_msg_w_ring (mq, ring_index);
Florin Coras3c2fed52018-07-04 04:15:05 -0700177 }
178 return 0;
179}
180
181svm_msg_q_msg_t
Florin Coras65784c12018-07-04 04:17:41 -0700182svm_msg_q_alloc_msg (svm_msg_q_t * mq, u32 nbytes)
183{
184 svm_msg_q_msg_t msg = {.as_u64 = ~0 };
Florin Corasb4624182020-12-11 13:58:12 -0800185 svm_msg_q_ring_shared_t *sr;
Florin Coras65784c12018-07-04 04:17:41 -0700186 svm_msg_q_ring_t *ring;
187
188 vec_foreach (ring, mq->rings)
189 {
Florin Corasb4624182020-12-11 13:58:12 -0800190 sr = ring->shr;
191 if (ring->elsize < nbytes || sr->cursize == ring->nitems)
Florin Coras65784c12018-07-04 04:17:41 -0700192 continue;
193 msg.ring_index = ring - mq->rings;
Florin Corasb4624182020-12-11 13:58:12 -0800194 msg.elt_index = sr->tail;
195 sr->tail = (sr->tail + 1) % ring->nitems;
196 clib_atomic_fetch_add (&sr->cursize, 1);
Florin Coras65784c12018-07-04 04:17:41 -0700197 break;
198 }
199 return msg;
200}
201
Florin Coras65784c12018-07-04 04:17:41 -0700202void *
203svm_msg_q_msg_data (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
204{
Florin Coras3c2fed52018-07-04 04:15:05 -0700205 svm_msg_q_ring_t *ring = svm_msg_q_ring_inline (mq, msg->ring_index);
Florin Coras65784c12018-07-04 04:17:41 -0700206 return svm_msg_q_ring_data (ring, msg->elt_index);
207}
208
209void
210svm_msg_q_free_msg (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
211{
Florin Corasb4624182020-12-11 13:58:12 -0800212 svm_msg_q_ring_shared_t *sr;
Florin Coras65784c12018-07-04 04:17:41 -0700213 svm_msg_q_ring_t *ring;
Florin Corasfea813a2019-12-27 10:26:56 -0800214 int need_signal;
Florin Coras65784c12018-07-04 04:17:41 -0700215
Florin Coras41c9e042018-09-11 00:10:41 -0700216 ASSERT (vec_len (mq->rings) > msg->ring_index);
Florin Corasb4624182020-12-11 13:58:12 -0800217 ring = svm_msg_q_ring_inline (mq, msg->ring_index);
218 sr = ring->shr;
219 if (msg->elt_index == sr->head)
Florin Coras65784c12018-07-04 04:17:41 -0700220 {
Florin Corasb4624182020-12-11 13:58:12 -0800221 sr->head = (sr->head + 1) % ring->nitems;
Florin Coras65784c12018-07-04 04:17:41 -0700222 }
223 else
224 {
Florin Coras41c9e042018-09-11 00:10:41 -0700225 clib_warning ("message out of order");
Florin Coras65784c12018-07-04 04:17:41 -0700226 /* for now, expect messages to be processed in order */
227 ASSERT (0);
228 }
Florin Corasfea813a2019-12-27 10:26:56 -0800229
Florin Corasb4624182020-12-11 13:58:12 -0800230 need_signal = sr->cursize == ring->nitems;
231 clib_atomic_fetch_sub (&sr->cursize, 1);
Florin Corasfea813a2019-12-27 10:26:56 -0800232
233 if (PREDICT_FALSE (need_signal))
234 svm_queue_send_signal (mq->q, 0);
Florin Coras65784c12018-07-04 04:17:41 -0700235}
236
237static int
238svm_msq_q_msg_is_valid (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
239{
Florin Coras54693d22018-07-17 10:46:29 -0700240 u32 dist1, dist2, tail, head;
Florin Corasb4624182020-12-11 13:58:12 -0800241 svm_msg_q_ring_shared_t *sr;
Florin Coras65784c12018-07-04 04:17:41 -0700242 svm_msg_q_ring_t *ring;
Florin Coras65784c12018-07-04 04:17:41 -0700243
244 if (vec_len (mq->rings) <= msg->ring_index)
245 return 0;
Florin Corasb4624182020-12-11 13:58:12 -0800246
247 ring = svm_msg_q_ring_inline (mq, msg->ring_index);
248 sr = ring->shr;
249 tail = sr->tail;
250 head = sr->head;
Florin Coras65784c12018-07-04 04:17:41 -0700251
Florin Coras54693d22018-07-17 10:46:29 -0700252 dist1 = ((ring->nitems + msg->elt_index) - head) % ring->nitems;
253 if (tail == head)
Florin Corasb4624182020-12-11 13:58:12 -0800254 dist2 = (sr->cursize == 0) ? 0 : ring->nitems;
Florin Coras65784c12018-07-04 04:17:41 -0700255 else
Florin Coras54693d22018-07-17 10:46:29 -0700256 dist2 = ((ring->nitems + tail) - head) % ring->nitems;
Florin Coras65784c12018-07-04 04:17:41 -0700257 return (dist1 < dist2);
258}
259
260int
Florin Coras3c2fed52018-07-04 04:15:05 -0700261svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t * msg, int nowait)
Florin Coras65784c12018-07-04 04:17:41 -0700262{
Florin Coras3c2fed52018-07-04 04:15:05 -0700263 ASSERT (svm_msq_q_msg_is_valid (mq, msg));
264 return svm_queue_add (mq->q, (u8 *) msg, nowait);
265}
266
267void
Florin Coras52207f12018-07-12 14:48:06 -0700268svm_msg_q_add_and_unlock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
Florin Coras3c2fed52018-07-04 04:15:05 -0700269{
270 ASSERT (svm_msq_q_msg_is_valid (mq, msg));
271 svm_queue_add_raw (mq->q, (u8 *) msg);
Florin Coras52207f12018-07-12 14:48:06 -0700272 svm_msg_q_unlock (mq);
Florin Coras65784c12018-07-04 04:17:41 -0700273}
274
275int
276svm_msg_q_sub (svm_msg_q_t * mq, svm_msg_q_msg_t * msg,
277 svm_q_conditional_wait_t cond, u32 time)
278{
279 return svm_queue_sub (mq->q, (u8 *) msg, cond, time);
280}
281
Florin Coras3c2fed52018-07-04 04:15:05 -0700282void
283svm_msg_q_sub_w_lock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
284{
285 svm_queue_sub_raw (mq->q, (u8 *) msg);
286}
287
Florin Coras99368312018-08-02 10:45:44 -0700288void
289svm_msg_q_set_consumer_eventfd (svm_msg_q_t * mq, int fd)
290{
291 mq->q->consumer_evtfd = fd;
292}
293
294void
295svm_msg_q_set_producer_eventfd (svm_msg_q_t * mq, int fd)
296{
297 mq->q->producer_evtfd = fd;
298}
299
300int
301svm_msg_q_alloc_consumer_eventfd (svm_msg_q_t * mq)
302{
303 int fd;
304 if ((fd = eventfd (0, EFD_NONBLOCK)) < 0)
305 return -1;
306 svm_msg_q_set_consumer_eventfd (mq, fd);
307 return 0;
308}
309
310int
311svm_msg_q_alloc_producer_eventfd (svm_msg_q_t * mq)
312{
313 int fd;
314 if ((fd = eventfd (0, EFD_NONBLOCK)) < 0)
315 return -1;
316 svm_msg_q_set_producer_eventfd (mq, fd);
317 return 0;
318}
319
Nathan Skrzypczakcfdb1092019-12-02 16:44:42 +0100320u8 *
321format_svm_msg_q (u8 * s, va_list * args)
322{
323 svm_msg_q_t *mq = va_arg (*args, svm_msg_q_t *);
324 s = format (s, " [Q:%d/%d]", mq->q->cursize, mq->q->maxsize);
325 for (u32 i = 0; i < vec_len (mq->rings); i++)
326 {
Florin Corasb4624182020-12-11 13:58:12 -0800327 s = format (s, " [R%d:%d/%d]", i, mq->rings[i].shr->cursize,
Nathan Skrzypczakcfdb1092019-12-02 16:44:42 +0100328 mq->rings[i].nitems);
329 }
330 return s;
331}
332
Florin Coras65784c12018-07-04 04:17:41 -0700333/*
334 * fd.io coding-style-patch-verification: ON
335 *
336 * Local Variables:
337 * eval: (c-set-style "gnu")
338 * End:
339 */