blob: 0fa1fe9b230ec9d3b6e0785530f1f1d5f5006078 [file] [log] [blame]
Dave Barach371e4e12016-07-08 09:38:52 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
Florin Corase86a8ed2018-01-05 03:20:25 -08003 * svm_queue.c - unidirectional shared-memory queues
Ed Warnickecb9cada2015-12-08 15:45:58 -07004 *
5 * Copyright (c) 2009 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
Florin Corase86a8ed2018-01-05 03:20:25 -080020
Ed Warnickecb9cada2015-12-08 15:45:58 -070021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <pthread.h>
25#include <vppinfra/mem.h>
26#include <vppinfra/format.h>
27#include <vppinfra/cache.h>
Florin Corase86a8ed2018-01-05 03:20:25 -080028#include <svm/queue.h>
Mohsin Kazmi3fca5672018-01-04 18:57:26 +010029#include <vppinfra/time.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070030
Florin Corase86a8ed2018-01-05 03:20:25 -080031svm_queue_t *
Florin Corasc470e222018-08-01 07:53:18 -070032svm_queue_init (void *base, int nels, int elsize)
Ed Warnickecb9cada2015-12-08 15:45:58 -070033{
Florin Corase86a8ed2018-01-05 03:20:25 -080034 svm_queue_t *q;
Dave Barach371e4e12016-07-08 09:38:52 -040035 pthread_mutexattr_t attr;
36 pthread_condattr_t cattr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
Florin Corasc470e222018-08-01 07:53:18 -070038 q = (svm_queue_t *) base;
Dave Barach371e4e12016-07-08 09:38:52 -040039 memset (q, 0, sizeof (*q));
Ed Warnickecb9cada2015-12-08 15:45:58 -070040
Dave Barach371e4e12016-07-08 09:38:52 -040041 q->elsize = elsize;
42 q->maxsize = nels;
Florin Corasc470e222018-08-01 07:53:18 -070043 q->producer_evtfd = -1;
44 q->consumer_evtfd = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070045
Dave Barach371e4e12016-07-08 09:38:52 -040046 memset (&attr, 0, sizeof (attr));
Dave Barach68b0fb02017-02-28 15:15:56 -050047 memset (&cattr, 0, sizeof (cattr));
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barach371e4e12016-07-08 09:38:52 -040049 if (pthread_mutexattr_init (&attr))
50 clib_unix_warning ("mutexattr_init");
51 if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED))
52 clib_unix_warning ("pthread_mutexattr_setpshared");
53 if (pthread_mutex_init (&q->mutex, &attr))
54 clib_unix_warning ("mutex_init");
55 if (pthread_mutexattr_destroy (&attr))
56 clib_unix_warning ("mutexattr_destroy");
57 if (pthread_condattr_init (&cattr))
58 clib_unix_warning ("condattr_init");
59 /* prints funny-looking messages in the Linux target */
60 if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED))
61 clib_unix_warning ("condattr_setpshared");
62 if (pthread_cond_init (&q->condvar, &cattr))
63 clib_unix_warning ("cond_init1");
64 if (pthread_condattr_destroy (&cattr))
65 clib_unix_warning ("cond_init2");
66
67 return (q);
Ed Warnickecb9cada2015-12-08 15:45:58 -070068}
69
Florin Corasc470e222018-08-01 07:53:18 -070070svm_queue_t *
71svm_queue_alloc_and_init (int nels, int elsize, int consumer_pid)
72{
73 svm_queue_t *q;
74
75 q = clib_mem_alloc_aligned (sizeof (svm_queue_t)
76 + nels * elsize, CLIB_CACHE_LINE_BYTES);
77 memset (q, 0, sizeof (*q));
78 q = svm_queue_init (q, nels, elsize);
79 q->consumer_pid = consumer_pid;
80
81 return q;
82}
83
Ed Warnickecb9cada2015-12-08 15:45:58 -070084/*
Florin Corase86a8ed2018-01-05 03:20:25 -080085 * svm_queue_free
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 */
Dave Barach371e4e12016-07-08 09:38:52 -040087void
Florin Corase86a8ed2018-01-05 03:20:25 -080088svm_queue_free (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -070089{
Dave Barach371e4e12016-07-08 09:38:52 -040090 (void) pthread_mutex_destroy (&q->mutex);
91 (void) pthread_cond_destroy (&q->condvar);
92 clib_mem_free (q);
Ed Warnickecb9cada2015-12-08 15:45:58 -070093}
94
Dave Barach371e4e12016-07-08 09:38:52 -040095void
Florin Corase86a8ed2018-01-05 03:20:25 -080096svm_queue_lock (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -070097{
Dave Barach371e4e12016-07-08 09:38:52 -040098 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -070099}
100
Dave Barach371e4e12016-07-08 09:38:52 -0400101void
Florin Corase86a8ed2018-01-05 03:20:25 -0800102svm_queue_unlock (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103{
Dave Barach371e4e12016-07-08 09:38:52 -0400104 pthread_mutex_unlock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105}
106
Dave Barach371e4e12016-07-08 09:38:52 -0400107int
Florin Corase86a8ed2018-01-05 03:20:25 -0800108svm_queue_is_full (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109{
Dave Barach371e4e12016-07-08 09:38:52 -0400110 return q->cursize == q->maxsize;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111}
112
Florin Corasc470e222018-08-01 07:53:18 -0700113static inline void
114svm_queue_send_signal (svm_queue_t * q, u8 is_prod)
115{
116 if (q->producer_evtfd == -1)
117 {
118 (void) pthread_cond_broadcast (&q->condvar);
119 }
120 else
121 {
122 int __clib_unused rv, fd;
123 u64 data = 1;
124 ASSERT (q->consumer_evtfd != -1);
125 fd = is_prod ? q->producer_evtfd : q->consumer_evtfd;
126 rv = write (fd, &data, sizeof (data));
127 }
128}
129
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800131 * svm_queue_add_nolock
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 */
Dave Barach371e4e12016-07-08 09:38:52 -0400133int
Florin Corase86a8ed2018-01-05 03:20:25 -0800134svm_queue_add_nolock (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135{
Dave Barach371e4e12016-07-08 09:38:52 -0400136 i8 *tailp;
137 int need_broadcast = 0;
138
139 if (PREDICT_FALSE (q->cursize == q->maxsize))
140 {
141 while (q->cursize == q->maxsize)
142 {
143 (void) pthread_cond_wait (&q->condvar, &q->mutex);
144 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Barach371e4e12016-07-08 09:38:52 -0400147 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
148 clib_memcpy (tailp, elem, q->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149
Dave Barach371e4e12016-07-08 09:38:52 -0400150 q->tail++;
151 q->cursize++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
Dave Barach371e4e12016-07-08 09:38:52 -0400153 need_broadcast = (q->cursize == 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
Dave Barach371e4e12016-07-08 09:38:52 -0400155 if (q->tail == q->maxsize)
156 q->tail = 0;
157
158 if (need_broadcast)
Florin Corasc470e222018-08-01 07:53:18 -0700159 svm_queue_send_signal (q, 1);
Dave Barach371e4e12016-07-08 09:38:52 -0400160 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161}
162
Florin Coras3c2fed52018-07-04 04:15:05 -0700163void
Florin Corase86a8ed2018-01-05 03:20:25 -0800164svm_queue_add_raw (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165{
Dave Barach371e4e12016-07-08 09:38:52 -0400166 i8 *tailp;
167
Dave Barach371e4e12016-07-08 09:38:52 -0400168 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
169 clib_memcpy (tailp, elem, q->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170
Florin Coras3c2fed52018-07-04 04:15:05 -0700171 q->tail = (q->tail + 1) % q->maxsize;
Dave Barach371e4e12016-07-08 09:38:52 -0400172 q->cursize++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173}
174
175
176/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800177 * svm_queue_add
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 */
Dave Barach371e4e12016-07-08 09:38:52 -0400179int
Florin Corase86a8ed2018-01-05 03:20:25 -0800180svm_queue_add (svm_queue_t * q, u8 * elem, int nowait)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181{
Dave Barach371e4e12016-07-08 09:38:52 -0400182 i8 *tailp;
183 int need_broadcast = 0;
184
185 if (nowait)
186 {
187 /* zero on success */
188 if (pthread_mutex_trylock (&q->mutex))
189 {
190 return (-1);
191 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192 }
Dave Barach371e4e12016-07-08 09:38:52 -0400193 else
194 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach371e4e12016-07-08 09:38:52 -0400196 if (PREDICT_FALSE (q->cursize == q->maxsize))
197 {
198 if (nowait)
199 {
200 pthread_mutex_unlock (&q->mutex);
201 return (-2);
202 }
203 while (q->cursize == q->maxsize)
204 {
205 (void) pthread_cond_wait (&q->condvar, &q->mutex);
206 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
Dave Barach371e4e12016-07-08 09:38:52 -0400209 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
210 clib_memcpy (tailp, elem, q->elsize);
211
212 q->tail++;
213 q->cursize++;
214
215 need_broadcast = (q->cursize == 1);
216
217 if (q->tail == q->maxsize)
218 q->tail = 0;
219
220 if (need_broadcast)
Florin Corasc470e222018-08-01 07:53:18 -0700221 svm_queue_send_signal (q, 1);
222
Dave Barach371e4e12016-07-08 09:38:52 -0400223 pthread_mutex_unlock (&q->mutex);
224
225 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226}
227
228/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800229 * svm_queue_add2
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200230 */
231int
Florin Corase86a8ed2018-01-05 03:20:25 -0800232svm_queue_add2 (svm_queue_t * q, u8 * elem, u8 * elem2, int nowait)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200233{
234 i8 *tailp;
235 int need_broadcast = 0;
236
237 if (nowait)
238 {
239 /* zero on success */
240 if (pthread_mutex_trylock (&q->mutex))
241 {
242 return (-1);
243 }
244 }
245 else
246 pthread_mutex_lock (&q->mutex);
247
248 if (PREDICT_FALSE (q->cursize + 1 == q->maxsize))
249 {
250 if (nowait)
251 {
252 pthread_mutex_unlock (&q->mutex);
253 return (-2);
254 }
255 while (q->cursize + 1 == q->maxsize)
256 {
257 (void) pthread_cond_wait (&q->condvar, &q->mutex);
258 }
259 }
260
261 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
262 clib_memcpy (tailp, elem, q->elsize);
263
264 q->tail++;
265 q->cursize++;
266
267 if (q->tail == q->maxsize)
268 q->tail = 0;
269
270 need_broadcast = (q->cursize == 1);
271
272 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
273 clib_memcpy (tailp, elem2, q->elsize);
274
275 q->tail++;
276 q->cursize++;
277
278 if (q->tail == q->maxsize)
279 q->tail = 0;
280
281 if (need_broadcast)
Florin Corasc470e222018-08-01 07:53:18 -0700282 svm_queue_send_signal (q, 1);
283
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200284 pthread_mutex_unlock (&q->mutex);
285
286 return 0;
287}
288
289/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800290 * svm_queue_sub
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 */
Dave Barach371e4e12016-07-08 09:38:52 -0400292int
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100293svm_queue_sub (svm_queue_t * q, u8 * elem, svm_q_conditional_wait_t cond,
294 u32 time)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295{
Dave Barach371e4e12016-07-08 09:38:52 -0400296 i8 *headp;
297 int need_broadcast = 0;
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100298 int rc = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400299
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100300 if (cond == SVM_Q_NOWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400301 {
302 /* zero on success */
303 if (pthread_mutex_trylock (&q->mutex))
304 {
305 return (-1);
306 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307 }
Dave Barach371e4e12016-07-08 09:38:52 -0400308 else
309 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310
Dave Barach371e4e12016-07-08 09:38:52 -0400311 if (PREDICT_FALSE (q->cursize == 0))
312 {
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100313 if (cond == SVM_Q_NOWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400314 {
315 pthread_mutex_unlock (&q->mutex);
316 return (-2);
317 }
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100318 else if (cond == SVM_Q_TIMEDWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400319 {
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100320 struct timespec ts;
321 ts.tv_sec = unix_time_now () + time;
322 ts.tv_nsec = 0;
323 while (q->cursize == 0 && rc == 0)
324 {
325 rc = pthread_cond_timedwait (&q->condvar, &q->mutex, &ts);
326 }
327 if (rc == ETIMEDOUT)
328 {
329 pthread_mutex_unlock (&q->mutex);
330 return ETIMEDOUT;
331 }
332 }
333 else
334 {
335 while (q->cursize == 0)
336 {
337 (void) pthread_cond_wait (&q->condvar, &q->mutex);
338 }
Dave Barach371e4e12016-07-08 09:38:52 -0400339 }
340 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341
Dave Barach371e4e12016-07-08 09:38:52 -0400342 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
343 clib_memcpy (elem, headp, q->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344
Dave Barach371e4e12016-07-08 09:38:52 -0400345 q->head++;
Dave Barach68b0fb02017-02-28 15:15:56 -0500346 /* $$$$ JFC shouldn't this be == 0? */
Dave Barach371e4e12016-07-08 09:38:52 -0400347 if (q->cursize == q->maxsize)
348 need_broadcast = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349
Dave Barach371e4e12016-07-08 09:38:52 -0400350 q->cursize--;
351
352 if (q->head == q->maxsize)
353 q->head = 0;
354
355 if (need_broadcast)
Florin Corasc470e222018-08-01 07:53:18 -0700356 svm_queue_send_signal (q, 0);
Dave Barach371e4e12016-07-08 09:38:52 -0400357
358 pthread_mutex_unlock (&q->mutex);
359
360 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361}
362
Dave Barach371e4e12016-07-08 09:38:52 -0400363int
Florin Corase86a8ed2018-01-05 03:20:25 -0800364svm_queue_sub2 (svm_queue_t * q, u8 * elem)
365{
366 int need_broadcast;
367 i8 *headp;
368
369 pthread_mutex_lock (&q->mutex);
370 if (q->cursize == 0)
371 {
372 pthread_mutex_unlock (&q->mutex);
373 return -1;
374 }
375
376 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
377 clib_memcpy (elem, headp, q->elsize);
378
379 q->head++;
380 need_broadcast = (q->cursize == q->maxsize / 2);
381 q->cursize--;
382
383 if (PREDICT_FALSE (q->head == q->maxsize))
384 q->head = 0;
385 pthread_mutex_unlock (&q->mutex);
386
387 if (need_broadcast)
Florin Corasc470e222018-08-01 07:53:18 -0700388 svm_queue_send_signal (q, 0);
Florin Corase86a8ed2018-01-05 03:20:25 -0800389
390 return 0;
391}
392
393int
394svm_queue_sub_raw (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395{
Dave Barach371e4e12016-07-08 09:38:52 -0400396 i8 *headp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397
Dave Barach371e4e12016-07-08 09:38:52 -0400398 if (PREDICT_FALSE (q->cursize == 0))
399 {
400 while (q->cursize == 0)
401 ;
402 }
403
404 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
405 clib_memcpy (elem, headp, q->elsize);
406
Florin Coras3c2fed52018-07-04 04:15:05 -0700407 q->head = (q->head + 1) % q->maxsize;
Dave Barach371e4e12016-07-08 09:38:52 -0400408 q->cursize--;
409
Dave Barach371e4e12016-07-08 09:38:52 -0400410 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411}
Dave Barach371e4e12016-07-08 09:38:52 -0400412
Florin Corasc470e222018-08-01 07:53:18 -0700413void
414svm_queue_set_producer_event_fd (svm_queue_t * q, int fd)
415{
416 q->producer_evtfd = fd;
417}
418
419void
420svm_queue_set_consumer_event_fd (svm_queue_t * q, int fd)
421{
422 q->consumer_evtfd = fd;
423}
424
Dave Barach371e4e12016-07-08 09:38:52 -0400425/*
426 * fd.io coding-style-patch-verification: ON
427 *
428 * Local Variables:
429 * eval: (c-set-style "gnu")
430 * End:
431 */