Skip to content

Commit 3c2fed5

Browse files
florincorasdmarion
authored andcommitted
session: use msg queue for events
Change-Id: I3c58367eec2243fe19b75be78a175c5261863e9e Signed-off-by: Florin Coras <[email protected]>
1 parent 5da96a7 commit 3c2fed5

27 files changed

+773
-400
lines changed

src/svm/message_queue.c

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,25 @@
1616
#include <svm/message_queue.h>
1717
#include <vppinfra/mem.h>
1818

19+
static inline svm_msg_q_ring_t *
20+
svm_msg_q_ring_inline (svm_msg_q_t * mq, u32 ring_index)
21+
{
22+
return vec_elt_at_index (mq->rings, ring_index);
23+
}
24+
25+
svm_msg_q_ring_t *
26+
svm_msg_q_ring (svm_msg_q_t * mq, u32 ring_index)
27+
{
28+
return svm_msg_q_ring_inline (mq, ring_index);
29+
}
30+
31+
static inline void *
32+
svm_msg_q_ring_data (svm_msg_q_ring_t * ring, u32 elt_index)
33+
{
34+
ASSERT (elt_index < ring->nitems);
35+
return (ring->data + elt_index * ring->elsize);
36+
}
37+
1938
svm_msg_q_t *
2039
svm_msg_q_alloc (svm_msg_q_cfg_t * cfg)
2140
{
@@ -62,6 +81,53 @@ svm_msg_q_free (svm_msg_q_t * mq)
6281
clib_mem_free (mq);
6382
}
6483

84+
svm_msg_q_msg_t
85+
svm_msg_q_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index)
86+
{
87+
svm_msg_q_msg_t msg = {.as_u64 = ~0 };
88+
svm_msg_q_ring_t *ring = svm_msg_q_ring_inline (mq, ring_index);
89+
90+
ASSERT (ring->cursize != ring->nitems);
91+
msg.ring_index = ring - mq->rings;
92+
msg.elt_index = ring->tail;
93+
ring->tail = (ring->tail + 1) % ring->nitems;
94+
__sync_fetch_and_add (&ring->cursize, 1);
95+
return msg;
96+
}
97+
98+
int
99+
svm_msg_q_lock_and_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index,
100+
u8 noblock, svm_msg_q_msg_t * msg)
101+
{
102+
if (noblock)
103+
{
104+
if (svm_msg_q_try_lock (mq))
105+
return -1;
106+
if (PREDICT_FALSE (svm_msg_q_ring_is_full (mq, ring_index)))
107+
{
108+
svm_msg_q_unlock (mq);
109+
return -2;
110+
}
111+
*msg = svm_msg_q_alloc_msg_w_ring (mq, ring_index);
112+
if (PREDICT_FALSE (svm_msg_q_msg_is_invalid (msg)))
113+
{
114+
svm_msg_q_unlock (mq);
115+
return -2;
116+
}
117+
}
118+
else
119+
{
120+
svm_msg_q_lock (mq);
121+
*msg = svm_msg_q_alloc_msg_w_ring (mq, ring_index);
122+
while (svm_msg_q_msg_is_invalid (msg))
123+
{
124+
svm_msg_q_wait (mq);
125+
*msg = svm_msg_q_alloc_msg_w_ring (mq, ring_index);
126+
}
127+
}
128+
return 0;
129+
}
130+
65131
svm_msg_q_msg_t
66132
svm_msg_q_alloc_msg (svm_msg_q_t * mq, u32 nbytes)
67133
{
@@ -81,23 +147,10 @@ svm_msg_q_alloc_msg (svm_msg_q_t * mq, u32 nbytes)
81147
return msg;
82148
}
83149

84-
static inline svm_msg_q_ring_t *
85-
svm_msg_q_get_ring (svm_msg_q_t * mq, u32 ring_index)
86-
{
87-
return vec_elt_at_index (mq->rings, ring_index);
88-
}
89-
90-
static inline void *
91-
svm_msg_q_ring_data (svm_msg_q_ring_t * ring, u32 elt_index)
92-
{
93-
ASSERT (elt_index < ring->nitems);
94-
return (ring->data + elt_index * ring->elsize);
95-
}
96-
97150
void *
98151
svm_msg_q_msg_data (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
99152
{
100-
svm_msg_q_ring_t *ring = svm_msg_q_get_ring (mq, msg->ring_index);
153+
svm_msg_q_ring_t *ring = svm_msg_q_ring_inline (mq, msg->ring_index);
101154
return svm_msg_q_ring_data (ring, msg->elt_index);
102155
}
103156

@@ -131,7 +184,7 @@ svm_msq_q_msg_is_valid (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
131184
return 0;
132185
ring = &mq->rings[msg->ring_index];
133186

134-
dist1 = ((ring->nitems + msg->ring_index) - ring->head) % ring->nitems;
187+
dist1 = ((ring->nitems + msg->elt_index) - ring->head) % ring->nitems;
135188
if (ring->tail == ring->head)
136189
dist2 = (ring->cursize == 0) ? 0 : ring->nitems;
137190
else
@@ -140,10 +193,17 @@ svm_msq_q_msg_is_valid (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
140193
}
141194

142195
int
143-
svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t msg, int nowait)
196+
svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t * msg, int nowait)
197+
{
198+
ASSERT (svm_msq_q_msg_is_valid (mq, msg));
199+
return svm_queue_add (mq->q, (u8 *) msg, nowait);
200+
}
201+
202+
void
203+
svm_msg_q_add_w_lock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
144204
{
145-
ASSERT (svm_msq_q_msg_is_valid (mq, &msg));
146-
return svm_queue_add (mq->q, (u8 *) & msg, nowait);
205+
ASSERT (svm_msq_q_msg_is_valid (mq, msg));
206+
svm_queue_add_raw (mq->q, (u8 *) msg);
147207
}
148208

149209
int
@@ -153,6 +213,12 @@ svm_msg_q_sub (svm_msg_q_t * mq, svm_msg_q_msg_t * msg,
153213
return svm_queue_sub (mq->q, (u8 *) msg, cond, time);
154214
}
155215

216+
void
217+
svm_msg_q_sub_w_lock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg)
218+
{
219+
svm_queue_sub_raw (mq->q, (u8 *) msg);
220+
}
221+
156222
/*
157223
* fd.io coding-style-patch-verification: ON
158224
*

src/svm/message_queue.h

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
#define SRC_SVM_MESSAGE_QUEUE_H_
2222

2323
#include <vppinfra/clib.h>
24+
#include <vppinfra/error.h>
2425
#include <svm/queue.h>
2526

2627
typedef struct svm_msg_q_ring_
2728
{
2829
volatile u32 cursize; /**< current size of the ring */
2930
u32 nitems; /**< max size of the ring */
30-
u32 head; /**< current head (for dequeue) */
31-
u32 tail; /**< current tail (for enqueue) */
31+
volatile u32 head; /**< current head (for dequeue) */
32+
volatile u32 tail; /**< current tail (for enqueue) */
3233
u32 elsize; /**< size of an element */
3334
u8 *data; /**< chunk of memory for msg data */
3435
} svm_msg_q_ring_t;
@@ -64,6 +65,7 @@ typedef union
6465
u64 as_u64;
6566
} svm_msg_q_msg_t;
6667

68+
#define SVM_MQ_INVALID_MSG { .as_u64 = ~0 }
6769
/**
6870
* Allocate message queue
6971
*
@@ -97,6 +99,36 @@ void svm_msg_q_free (svm_msg_q_t * mq);
9799
*/
98100
svm_msg_q_msg_t svm_msg_q_alloc_msg (svm_msg_q_t * mq, u32 nbytes);
99101

102+
/**
103+
* Allocate message buffer on ring
104+
*
105+
* Message is allocated, on requested ring. The caller MUST check that
106+
* the ring is not full.
107+
*
108+
* @param mq message queue
109+
* @param ring_index ring on which the allocation should occur
110+
* @return message structure pointing to the ring and position
111+
* allocated
112+
*/
113+
svm_msg_q_msg_t svm_msg_q_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index);
114+
115+
/**
116+
* Lock message queue and allocate message buffer on ring
117+
*
118+
* This should be used when multiple writers/readers are expected to
119+
* compete for the rings/queue. Message should be enqueued by calling
120+
* @ref svm_msg_q_add_w_lock and the caller MUST unlock the queue once
121+
* the message in enqueued.
122+
*
123+
* @param mq message queue
124+
* @param ring_index ring on which the allocation should occur
125+
* @param noblock flag that indicates if request should block
126+
* @param msg pointer to message to be filled in
127+
* @return 0 on success, negative number otherwise
128+
*/
129+
int svm_msg_q_lock_and_alloc_msg_w_ring (svm_msg_q_t * mq, u32 ring_index,
130+
u8 noblock, svm_msg_q_msg_t * msg);
131+
100132
/**
101133
* Free message buffer
102134
*
@@ -106,6 +138,7 @@ svm_msg_q_msg_t svm_msg_q_alloc_msg (svm_msg_q_t * mq, u32 nbytes);
106138
* @param msg message to be freed
107139
*/
108140
void svm_msg_q_free_msg (svm_msg_q_t * mq, svm_msg_q_msg_t * msg);
141+
109142
/**
110143
* Producer enqueue one message to queue
111144
*
@@ -117,7 +150,20 @@ void svm_msg_q_free_msg (svm_msg_q_t * mq, svm_msg_q_msg_t * msg);
117150
* @param nowait flag to indicate if request is blocking or not
118151
* @return success status
119152
*/
120-
int svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t msg, int nowait);
153+
int svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t * msg, int nowait);
154+
155+
/**
156+
* Producer enqueue one message to queue with mutex held
157+
*
158+
* Prior to calling this, the producer should've obtained a message buffer
159+
* from one of the rings by calling @ref svm_msg_q_alloc_msg. It assumes
160+
* the queue mutex is held.
161+
*
162+
* @param mq message queue
163+
* @param msg message (pointer to ring position) to be enqueued
164+
* @return success status
165+
*/
166+
void svm_msg_q_add_w_lock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg);
121167

122168
/**
123169
* Consumer dequeue one message from queue
@@ -129,20 +175,123 @@ int svm_msg_q_add (svm_msg_q_t * mq, svm_msg_q_msg_t msg, int nowait);
129175
* @param mq message queue
130176
* @param msg pointer to structure where message is to be received
131177
* @param cond flag that indicates if request should block or not
178+
* @param time time to wait if condition it SVM_Q_TIMEDWAIT
132179
* @return success status
133180
*/
134181
int svm_msg_q_sub (svm_msg_q_t * mq, svm_msg_q_msg_t * msg,
135182
svm_q_conditional_wait_t cond, u32 time);
136183

137184
/**
138-
* Get data for message in queu
185+
* Consumer dequeue one message from queue with mutex held
186+
*
187+
* Returns the message pointing to the data in the message rings under the
188+
* assumption that the message queue lock is already held. The consumer is
189+
* expected to call @ref svm_msg_q_free_msg once it finishes
190+
* processing/copies the message data.
191+
*
192+
* @param mq message queue
193+
* @param msg pointer to structure where message is to be received
194+
* @return success status
195+
*/
196+
void svm_msg_q_sub_w_lock (svm_msg_q_t * mq, svm_msg_q_msg_t * msg);
197+
198+
/**
199+
* Get data for message in queue
139200
*
140201
* @param mq message queue
141202
* @param msg message for which the data is requested
142203
* @return pointer to data
143204
*/
144205
void *svm_msg_q_msg_data (svm_msg_q_t * mq, svm_msg_q_msg_t * msg);
145206

207+
/**
208+
* Get message queue ring
209+
*
210+
* @param mq message queue
211+
* @param ring_index index of ring
212+
* @return pointer to ring
213+
*/
214+
svm_msg_q_ring_t *svm_msg_q_ring (svm_msg_q_t * mq, u32 ring_index);
215+
216+
/**
217+
* Check if message queue is full
218+
*/
219+
static inline u8
220+
svm_msg_q_is_full (svm_msg_q_t * mq)
221+
{
222+
return (mq->q->cursize == mq->q->maxsize);
223+
}
224+
225+
static inline u8
226+
svm_msg_q_ring_is_full (svm_msg_q_t * mq, u32 ring_index)
227+
{
228+
ASSERT (ring_index < vec_len (mq->rings));
229+
return (mq->rings[ring_index].cursize == mq->rings[ring_index].nitems);
230+
}
231+
232+
/**
233+
* Check if message queue is empty
234+
*/
235+
static inline u8
236+
svm_msg_q_is_empty (svm_msg_q_t * mq)
237+
{
238+
return (mq->q->cursize == 0);
239+
}
240+
241+
/**
242+
* Check length of message queue
243+
*/
244+
static inline u32
245+
svm_msg_q_size (svm_msg_q_t * mq)
246+
{
247+
return mq->q->cursize;
248+
}
249+
250+
/**
251+
* Check if message is invalid
252+
*/
253+
static inline u8
254+
svm_msg_q_msg_is_invalid (svm_msg_q_msg_t * msg)
255+
{
256+
return (msg->as_u64 == (u64) ~ 0);
257+
}
258+
259+
/**
260+
* Try locking message queue
261+
*/
262+
static inline int
263+
svm_msg_q_try_lock (svm_msg_q_t * mq)
264+
{
265+
return pthread_mutex_trylock (&mq->q->mutex);
266+
}
267+
268+
/**
269+
* Lock, or block trying, the message queue
270+
*/
271+
static inline int
272+
svm_msg_q_lock (svm_msg_q_t * mq)
273+
{
274+
return pthread_mutex_lock (&mq->q->mutex);
275+
}
276+
277+
static inline void
278+
svm_msg_q_wait (svm_msg_q_t * mq)
279+
{
280+
pthread_cond_wait (&mq->q->condvar, &mq->q->mutex);
281+
}
282+
283+
/**
284+
* Unlock message queue
285+
*/
286+
static inline void
287+
svm_msg_q_unlock (svm_msg_q_t * mq)
288+
{
289+
/* The other side of the connection is not polling */
290+
if (mq->q->cursize < (mq->q->maxsize / 8))
291+
(void) pthread_cond_broadcast (&mq->q->condvar);
292+
pthread_mutex_unlock (&mq->q->mutex);
293+
}
294+
146295
#endif /* SRC_SVM_MESSAGE_QUEUE_H_ */
147296

148297
/*

0 commit comments

Comments
 (0)