blob: 96e40fc2aec749940e32f110d75aefbd062f725e [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#include <signal.h>
31
32/*
Florin Corase86a8ed2018-01-05 03:20:25 -080033 * svm_queue_init
Dave Barach371e4e12016-07-08 09:38:52 -040034 *
Ed Warnickecb9cada2015-12-08 15:45:58 -070035 * nels = number of elements on the queue
36 * elsize = element size, presumably 4 and cacheline-size will
37 * be popular choices.
Ed Warnickecb9cada2015-12-08 15:45:58 -070038 * pid = consumer pid
Ed Warnickecb9cada2015-12-08 15:45:58 -070039 *
40 * The idea is to call this function in the queue consumer,
41 * and e-mail the queue pointer to the producer(s).
42 *
Dave Barach68b0fb02017-02-28 15:15:56 -050043 * The vpp process / main thread allocates one of these
44 * at startup; its main input queue. The vpp main input queue
Ed Warnickecb9cada2015-12-08 15:45:58 -070045 * has a pointer to it in the shared memory segment header.
Dave Barach371e4e12016-07-08 09:38:52 -040046 *
47 * You probably want to be on an svm data heap before calling this
Ed Warnickecb9cada2015-12-08 15:45:58 -070048 * function.
49 */
Florin Corase86a8ed2018-01-05 03:20:25 -080050svm_queue_t *
51svm_queue_init (int nels,
52 int elsize, int consumer_pid, int signal_when_queue_non_empty)
Ed Warnickecb9cada2015-12-08 15:45:58 -070053{
Florin Corase86a8ed2018-01-05 03:20:25 -080054 svm_queue_t *q;
Dave Barach371e4e12016-07-08 09:38:52 -040055 pthread_mutexattr_t attr;
56 pthread_condattr_t cattr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070057
Florin Corase86a8ed2018-01-05 03:20:25 -080058 q = clib_mem_alloc_aligned (sizeof (svm_queue_t)
Dave Barach371e4e12016-07-08 09:38:52 -040059 + nels * elsize, CLIB_CACHE_LINE_BYTES);
60 memset (q, 0, sizeof (*q));
Ed Warnickecb9cada2015-12-08 15:45:58 -070061
Dave Barach371e4e12016-07-08 09:38:52 -040062 q->elsize = elsize;
63 q->maxsize = nels;
64 q->consumer_pid = consumer_pid;
65 q->signal_when_queue_non_empty = signal_when_queue_non_empty;
Ed Warnickecb9cada2015-12-08 15:45:58 -070066
Dave Barach371e4e12016-07-08 09:38:52 -040067 memset (&attr, 0, sizeof (attr));
Dave Barach68b0fb02017-02-28 15:15:56 -050068 memset (&cattr, 0, sizeof (cattr));
Ed Warnickecb9cada2015-12-08 15:45:58 -070069
Dave Barach371e4e12016-07-08 09:38:52 -040070 if (pthread_mutexattr_init (&attr))
71 clib_unix_warning ("mutexattr_init");
72 if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED))
73 clib_unix_warning ("pthread_mutexattr_setpshared");
74 if (pthread_mutex_init (&q->mutex, &attr))
75 clib_unix_warning ("mutex_init");
76 if (pthread_mutexattr_destroy (&attr))
77 clib_unix_warning ("mutexattr_destroy");
78 if (pthread_condattr_init (&cattr))
79 clib_unix_warning ("condattr_init");
80 /* prints funny-looking messages in the Linux target */
81 if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED))
82 clib_unix_warning ("condattr_setpshared");
83 if (pthread_cond_init (&q->condvar, &cattr))
84 clib_unix_warning ("cond_init1");
85 if (pthread_condattr_destroy (&cattr))
86 clib_unix_warning ("cond_init2");
87
88 return (q);
Ed Warnickecb9cada2015-12-08 15:45:58 -070089}
90
91/*
Florin Corase86a8ed2018-01-05 03:20:25 -080092 * svm_queue_free
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 */
Dave Barach371e4e12016-07-08 09:38:52 -040094void
Florin Corase86a8ed2018-01-05 03:20:25 -080095svm_queue_free (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -070096{
Dave Barach371e4e12016-07-08 09:38:52 -040097 (void) pthread_mutex_destroy (&q->mutex);
98 (void) pthread_cond_destroy (&q->condvar);
99 clib_mem_free (q);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100}
101
Dave Barach371e4e12016-07-08 09:38:52 -0400102void
Florin Corase86a8ed2018-01-05 03:20:25 -0800103svm_queue_lock (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104{
Dave Barach371e4e12016-07-08 09:38:52 -0400105 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106}
107
Dave Barach371e4e12016-07-08 09:38:52 -0400108void
Florin Corase86a8ed2018-01-05 03:20:25 -0800109svm_queue_unlock (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110{
Dave Barach371e4e12016-07-08 09:38:52 -0400111 pthread_mutex_unlock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112}
113
Dave Barach371e4e12016-07-08 09:38:52 -0400114int
Florin Corase86a8ed2018-01-05 03:20:25 -0800115svm_queue_is_full (svm_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116{
Dave Barach371e4e12016-07-08 09:38:52 -0400117 return q->cursize == q->maxsize;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118}
119
120/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800121 * svm_queue_add_nolock
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122 */
Dave Barach371e4e12016-07-08 09:38:52 -0400123int
Florin Corase86a8ed2018-01-05 03:20:25 -0800124svm_queue_add_nolock (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125{
Dave Barach371e4e12016-07-08 09:38:52 -0400126 i8 *tailp;
127 int need_broadcast = 0;
128
129 if (PREDICT_FALSE (q->cursize == q->maxsize))
130 {
131 while (q->cursize == q->maxsize)
132 {
133 (void) pthread_cond_wait (&q->condvar, &q->mutex);
134 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Dave Barach371e4e12016-07-08 09:38:52 -0400137 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
138 clib_memcpy (tailp, elem, q->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Dave Barach371e4e12016-07-08 09:38:52 -0400140 q->tail++;
141 q->cursize++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
Dave Barach371e4e12016-07-08 09:38:52 -0400143 need_broadcast = (q->cursize == 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
Dave Barach371e4e12016-07-08 09:38:52 -0400145 if (q->tail == q->maxsize)
146 q->tail = 0;
147
148 if (need_broadcast)
149 {
150 (void) pthread_cond_broadcast (&q->condvar);
151 if (q->signal_when_queue_non_empty)
152 kill (q->consumer_pid, q->signal_when_queue_non_empty);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 }
Dave Barach371e4e12016-07-08 09:38:52 -0400154 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155}
156
Dave Barach371e4e12016-07-08 09:38:52 -0400157int
Florin Corase86a8ed2018-01-05 03:20:25 -0800158svm_queue_add_raw (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159{
Dave Barach371e4e12016-07-08 09:38:52 -0400160 i8 *tailp;
161
162 if (PREDICT_FALSE (q->cursize == q->maxsize))
163 {
164 while (q->cursize == q->maxsize)
165 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
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
Dave Barach371e4e12016-07-08 09:38:52 -0400171 q->tail++;
172 q->cursize++;
173
174 if (q->tail == q->maxsize)
175 q->tail = 0;
176 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177}
178
179
180/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800181 * svm_queue_add
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 */
Dave Barach371e4e12016-07-08 09:38:52 -0400183int
Florin Corase86a8ed2018-01-05 03:20:25 -0800184svm_queue_add (svm_queue_t * q, u8 * elem, int nowait)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185{
Dave Barach371e4e12016-07-08 09:38:52 -0400186 i8 *tailp;
187 int need_broadcast = 0;
188
189 if (nowait)
190 {
191 /* zero on success */
192 if (pthread_mutex_trylock (&q->mutex))
193 {
194 return (-1);
195 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 }
Dave Barach371e4e12016-07-08 09:38:52 -0400197 else
198 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199
Dave Barach371e4e12016-07-08 09:38:52 -0400200 if (PREDICT_FALSE (q->cursize == q->maxsize))
201 {
202 if (nowait)
203 {
204 pthread_mutex_unlock (&q->mutex);
205 return (-2);
206 }
207 while (q->cursize == q->maxsize)
208 {
209 (void) pthread_cond_wait (&q->condvar, &q->mutex);
210 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Dave Barach371e4e12016-07-08 09:38:52 -0400213 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
214 clib_memcpy (tailp, elem, q->elsize);
215
216 q->tail++;
217 q->cursize++;
218
219 need_broadcast = (q->cursize == 1);
220
221 if (q->tail == q->maxsize)
222 q->tail = 0;
223
224 if (need_broadcast)
225 {
226 (void) pthread_cond_broadcast (&q->condvar);
227 if (q->signal_when_queue_non_empty)
228 kill (q->consumer_pid, q->signal_when_queue_non_empty);
229 }
230 pthread_mutex_unlock (&q->mutex);
231
232 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233}
234
235/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800236 * svm_queue_add2
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200237 */
238int
Florin Corase86a8ed2018-01-05 03:20:25 -0800239svm_queue_add2 (svm_queue_t * q, u8 * elem, u8 * elem2, int nowait)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200240{
241 i8 *tailp;
242 int need_broadcast = 0;
243
244 if (nowait)
245 {
246 /* zero on success */
247 if (pthread_mutex_trylock (&q->mutex))
248 {
249 return (-1);
250 }
251 }
252 else
253 pthread_mutex_lock (&q->mutex);
254
255 if (PREDICT_FALSE (q->cursize + 1 == q->maxsize))
256 {
257 if (nowait)
258 {
259 pthread_mutex_unlock (&q->mutex);
260 return (-2);
261 }
262 while (q->cursize + 1 == q->maxsize)
263 {
264 (void) pthread_cond_wait (&q->condvar, &q->mutex);
265 }
266 }
267
268 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
269 clib_memcpy (tailp, elem, q->elsize);
270
271 q->tail++;
272 q->cursize++;
273
274 if (q->tail == q->maxsize)
275 q->tail = 0;
276
277 need_broadcast = (q->cursize == 1);
278
279 tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
280 clib_memcpy (tailp, elem2, q->elsize);
281
282 q->tail++;
283 q->cursize++;
284
285 if (q->tail == q->maxsize)
286 q->tail = 0;
287
288 if (need_broadcast)
289 {
290 (void) pthread_cond_broadcast (&q->condvar);
291 if (q->signal_when_queue_non_empty)
292 kill (q->consumer_pid, q->signal_when_queue_non_empty);
293 }
294 pthread_mutex_unlock (&q->mutex);
295
296 return 0;
297}
298
299/*
Florin Corase86a8ed2018-01-05 03:20:25 -0800300 * svm_queue_sub
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301 */
Dave Barach371e4e12016-07-08 09:38:52 -0400302int
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100303svm_queue_sub (svm_queue_t * q, u8 * elem, svm_q_conditional_wait_t cond,
304 u32 time)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305{
Dave Barach371e4e12016-07-08 09:38:52 -0400306 i8 *headp;
307 int need_broadcast = 0;
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100308 int rc = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400309
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100310 if (cond == SVM_Q_NOWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400311 {
312 /* zero on success */
313 if (pthread_mutex_trylock (&q->mutex))
314 {
315 return (-1);
316 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317 }
Dave Barach371e4e12016-07-08 09:38:52 -0400318 else
319 pthread_mutex_lock (&q->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320
Dave Barach371e4e12016-07-08 09:38:52 -0400321 if (PREDICT_FALSE (q->cursize == 0))
322 {
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100323 if (cond == SVM_Q_NOWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400324 {
325 pthread_mutex_unlock (&q->mutex);
326 return (-2);
327 }
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100328 else if (cond == SVM_Q_TIMEDWAIT)
Dave Barach371e4e12016-07-08 09:38:52 -0400329 {
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100330 struct timespec ts;
331 ts.tv_sec = unix_time_now () + time;
332 ts.tv_nsec = 0;
333 while (q->cursize == 0 && rc == 0)
334 {
335 rc = pthread_cond_timedwait (&q->condvar, &q->mutex, &ts);
336 }
337 if (rc == ETIMEDOUT)
338 {
339 pthread_mutex_unlock (&q->mutex);
340 return ETIMEDOUT;
341 }
342 }
343 else
344 {
345 while (q->cursize == 0)
346 {
347 (void) pthread_cond_wait (&q->condvar, &q->mutex);
348 }
Dave Barach371e4e12016-07-08 09:38:52 -0400349 }
350 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351
Dave Barach371e4e12016-07-08 09:38:52 -0400352 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
353 clib_memcpy (elem, headp, q->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354
Dave Barach371e4e12016-07-08 09:38:52 -0400355 q->head++;
Dave Barach68b0fb02017-02-28 15:15:56 -0500356 /* $$$$ JFC shouldn't this be == 0? */
Dave Barach371e4e12016-07-08 09:38:52 -0400357 if (q->cursize == q->maxsize)
358 need_broadcast = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359
Dave Barach371e4e12016-07-08 09:38:52 -0400360 q->cursize--;
361
362 if (q->head == q->maxsize)
363 q->head = 0;
364
365 if (need_broadcast)
366 (void) pthread_cond_broadcast (&q->condvar);
367
368 pthread_mutex_unlock (&q->mutex);
369
370 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371}
372
Dave Barach371e4e12016-07-08 09:38:52 -0400373int
Florin Corase86a8ed2018-01-05 03:20:25 -0800374svm_queue_sub2 (svm_queue_t * q, u8 * elem)
375{
376 int need_broadcast;
377 i8 *headp;
378
379 pthread_mutex_lock (&q->mutex);
380 if (q->cursize == 0)
381 {
382 pthread_mutex_unlock (&q->mutex);
383 return -1;
384 }
385
386 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
387 clib_memcpy (elem, headp, q->elsize);
388
389 q->head++;
390 need_broadcast = (q->cursize == q->maxsize / 2);
391 q->cursize--;
392
393 if (PREDICT_FALSE (q->head == q->maxsize))
394 q->head = 0;
395 pthread_mutex_unlock (&q->mutex);
396
397 if (need_broadcast)
398 (void) pthread_cond_broadcast (&q->condvar);
399
400 return 0;
401}
402
403int
404svm_queue_sub_raw (svm_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405{
Dave Barach371e4e12016-07-08 09:38:52 -0400406 i8 *headp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407
Dave Barach371e4e12016-07-08 09:38:52 -0400408 if (PREDICT_FALSE (q->cursize == 0))
409 {
410 while (q->cursize == 0)
411 ;
412 }
413
414 headp = (i8 *) (&q->data[0] + q->elsize * q->head);
415 clib_memcpy (elem, headp, q->elsize);
416
417 q->head++;
418 q->cursize--;
419
420 if (q->head == q->maxsize)
421 q->head = 0;
422 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423}
Dave Barach371e4e12016-07-08 09:38:52 -0400424
425/*
426 * fd.io coding-style-patch-verification: ON
427 *
428 * Local Variables:
429 * eval: (c-set-style "gnu")
430 * End:
431 */