xref: /f-stack/dpdk/lib/librte_ring/rte_ring.c (revision 031be553)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Derived from FreeBSD's bufring.c
36  *
37  **************************************************************************
38  *
39  * Copyright (c) 2007,2008 Kip Macy [email protected]
40  * All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions are met:
44  *
45  * 1. Redistributions of source code must retain the above copyright notice,
46  *    this list of conditions and the following disclaimer.
47  *
48  * 2. The name of Kip Macy nor the names of other
49  *    contributors may be used to endorse or promote products derived from
50  *    this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
53  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
56  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
59  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
60  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62  * POSSIBILITY OF SUCH DAMAGE.
63  *
64  ***************************************************************************/
65 
66 #include <stdio.h>
67 #include <stdarg.h>
68 #include <string.h>
69 #include <stdint.h>
70 #include <inttypes.h>
71 #include <errno.h>
72 #include <sys/queue.h>
73 
74 #include <rte_common.h>
75 #include <rte_log.h>
76 #include <rte_memory.h>
77 #include <rte_memzone.h>
78 #include <rte_malloc.h>
79 #include <rte_launch.h>
80 #include <rte_eal.h>
81 #include <rte_eal_memconfig.h>
82 #include <rte_atomic.h>
83 #include <rte_per_lcore.h>
84 #include <rte_lcore.h>
85 #include <rte_branch_prediction.h>
86 #include <rte_errno.h>
87 #include <rte_string_fns.h>
88 #include <rte_spinlock.h>
89 
90 #include "rte_ring.h"
91 
92 TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
93 
94 static struct rte_tailq_elem rte_ring_tailq = {
95 	.name = RTE_TAILQ_RING_NAME,
96 };
97 EAL_REGISTER_TAILQ(rte_ring_tailq)
98 
99 /* true if x is a power of 2 */
100 #define POWEROF2(x) ((((x)-1) & (x)) == 0)
101 
102 /* return the size of memory occupied by a ring */
103 ssize_t
104 rte_ring_get_memsize(unsigned count)
105 {
106 	ssize_t sz;
107 
108 	/* count must be a power of 2 */
109 	if ((!POWEROF2(count)) || (count > RTE_RING_SZ_MASK )) {
110 		RTE_LOG(ERR, RING,
111 			"Requested size is invalid, must be power of 2, and "
112 			"do not exceed the size limit %u\n", RTE_RING_SZ_MASK);
113 		return -EINVAL;
114 	}
115 
116 	sz = sizeof(struct rte_ring) + count * sizeof(void *);
117 	sz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE);
118 	return sz;
119 }
120 
121 int
122 rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
123 	unsigned flags)
124 {
125 	int ret;
126 
127 	/* compilation-time checks */
128 	RTE_BUILD_BUG_ON((sizeof(struct rte_ring) &
129 			  RTE_CACHE_LINE_MASK) != 0);
130 	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, cons) &
131 			  RTE_CACHE_LINE_MASK) != 0);
132 	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, prod) &
133 			  RTE_CACHE_LINE_MASK) != 0);
134 
135 	/* init the ring structure */
136 	memset(r, 0, sizeof(*r));
137 	ret = snprintf(r->name, sizeof(r->name), "%s", name);
138 	if (ret < 0 || ret >= (int)sizeof(r->name))
139 		return -ENAMETOOLONG;
140 	r->flags = flags;
141 	r->prod.single = (flags & RING_F_SP_ENQ) ? __IS_SP : __IS_MP;
142 	r->cons.single = (flags & RING_F_SC_DEQ) ? __IS_SC : __IS_MC;
143 
144 	if (flags & RING_F_EXACT_SZ) {
145 		r->size = rte_align32pow2(count + 1);
146 		r->mask = r->size - 1;
147 		r->capacity = count;
148 	} else {
149 		if ((!POWEROF2(count)) || (count > RTE_RING_SZ_MASK)) {
150 			RTE_LOG(ERR, RING,
151 				"Requested size is invalid, must be power of 2, and not exceed the size limit %u\n",
152 				RTE_RING_SZ_MASK);
153 			return -EINVAL;
154 		}
155 		r->size = count;
156 		r->mask = count - 1;
157 		r->capacity = r->mask;
158 	}
159 	r->prod.head = r->cons.head = 0;
160 	r->prod.tail = r->cons.tail = 0;
161 
162 	return 0;
163 }
164 
165 /* create the ring */
166 struct rte_ring *
167 rte_ring_create(const char *name, unsigned count, int socket_id,
168 		unsigned flags)
169 {
170 	char mz_name[RTE_MEMZONE_NAMESIZE];
171 	struct rte_ring *r;
172 	struct rte_tailq_entry *te;
173 	const struct rte_memzone *mz;
174 	ssize_t ring_size;
175 	int mz_flags = 0;
176 	struct rte_ring_list* ring_list = NULL;
177 	const unsigned int requested_count = count;
178 	int ret;
179 
180 	ring_list = RTE_TAILQ_CAST(rte_ring_tailq.head, rte_ring_list);
181 
182 	/* for an exact size ring, round up from count to a power of two */
183 	if (flags & RING_F_EXACT_SZ)
184 		count = rte_align32pow2(count + 1);
185 
186 	ring_size = rte_ring_get_memsize(count);
187 	if (ring_size < 0) {
188 		rte_errno = ring_size;
189 		return NULL;
190 	}
191 
192 	ret = snprintf(mz_name, sizeof(mz_name), "%s%s",
193 		RTE_RING_MZ_PREFIX, name);
194 	if (ret < 0 || ret >= (int)sizeof(mz_name)) {
195 		rte_errno = ENAMETOOLONG;
196 		return NULL;
197 	}
198 
199 	te = rte_zmalloc("RING_TAILQ_ENTRY", sizeof(*te), 0);
200 	if (te == NULL) {
201 		RTE_LOG(ERR, RING, "Cannot reserve memory for tailq\n");
202 		rte_errno = ENOMEM;
203 		return NULL;
204 	}
205 
206 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
207 
208 	/* reserve a memory zone for this ring. If we can't get rte_config or
209 	 * we are secondary process, the memzone_reserve function will set
210 	 * rte_errno for us appropriately - hence no check in this this function */
211 	mz = rte_memzone_reserve_aligned(mz_name, ring_size, socket_id,
212 					 mz_flags, __alignof__(*r));
213 	if (mz != NULL) {
214 		r = mz->addr;
215 		/* no need to check return value here, we already checked the
216 		 * arguments above */
217 		rte_ring_init(r, name, requested_count, flags);
218 
219 		te->data = (void *) r;
220 		r->memzone = mz;
221 
222 		TAILQ_INSERT_TAIL(ring_list, te, next);
223 	} else {
224 		r = NULL;
225 		RTE_LOG(ERR, RING, "Cannot reserve memory\n");
226 		rte_free(te);
227 	}
228 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
229 
230 	return r;
231 }
232 
233 /* free the ring */
234 void
235 rte_ring_free(struct rte_ring *r)
236 {
237 	struct rte_ring_list *ring_list = NULL;
238 	struct rte_tailq_entry *te;
239 
240 	if (r == NULL)
241 		return;
242 
243 	/*
244 	 * Ring was not created with rte_ring_create,
245 	 * therefore, there is no memzone to free.
246 	 */
247 	if (r->memzone == NULL) {
248 		RTE_LOG(ERR, RING, "Cannot free ring (not created with rte_ring_create()");
249 		return;
250 	}
251 
252 	if (rte_memzone_free(r->memzone) != 0) {
253 		RTE_LOG(ERR, RING, "Cannot free memory\n");
254 		return;
255 	}
256 
257 	ring_list = RTE_TAILQ_CAST(rte_ring_tailq.head, rte_ring_list);
258 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
259 
260 	/* find out tailq entry */
261 	TAILQ_FOREACH(te, ring_list, next) {
262 		if (te->data == (void *) r)
263 			break;
264 	}
265 
266 	if (te == NULL) {
267 		rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
268 		return;
269 	}
270 
271 	TAILQ_REMOVE(ring_list, te, next);
272 
273 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
274 
275 	rte_free(te);
276 }
277 
278 /* dump the status of the ring on the console */
279 void
280 rte_ring_dump(FILE *f, const struct rte_ring *r)
281 {
282 	fprintf(f, "ring <%s>@%p\n", r->name, r);
283 	fprintf(f, "  flags=%x\n", r->flags);
284 	fprintf(f, "  size=%"PRIu32"\n", r->size);
285 	fprintf(f, "  capacity=%"PRIu32"\n", r->capacity);
286 	fprintf(f, "  ct=%"PRIu32"\n", r->cons.tail);
287 	fprintf(f, "  ch=%"PRIu32"\n", r->cons.head);
288 	fprintf(f, "  pt=%"PRIu32"\n", r->prod.tail);
289 	fprintf(f, "  ph=%"PRIu32"\n", r->prod.head);
290 	fprintf(f, "  used=%u\n", rte_ring_count(r));
291 	fprintf(f, "  avail=%u\n", rte_ring_free_count(r));
292 }
293 
294 /* dump the status of all rings on the console */
295 void
296 rte_ring_list_dump(FILE *f)
297 {
298 	const struct rte_tailq_entry *te;
299 	struct rte_ring_list *ring_list;
300 
301 	ring_list = RTE_TAILQ_CAST(rte_ring_tailq.head, rte_ring_list);
302 
303 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
304 
305 	TAILQ_FOREACH(te, ring_list, next) {
306 		rte_ring_dump(f, (struct rte_ring *) te->data);
307 	}
308 
309 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
310 }
311 
312 /* search a ring from its name */
313 struct rte_ring *
314 rte_ring_lookup(const char *name)
315 {
316 	struct rte_tailq_entry *te;
317 	struct rte_ring *r = NULL;
318 	struct rte_ring_list *ring_list;
319 
320 	ring_list = RTE_TAILQ_CAST(rte_ring_tailq.head, rte_ring_list);
321 
322 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
323 
324 	TAILQ_FOREACH(te, ring_list, next) {
325 		r = (struct rte_ring *) te->data;
326 		if (strncmp(name, r->name, RTE_RING_NAMESIZE) == 0)
327 			break;
328 	}
329 
330 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
331 
332 	if (te == NULL) {
333 		rte_errno = ENOENT;
334 		return NULL;
335 	}
336 
337 	return r;
338 }
339