1 /*
2  * Copyright (c) 2021 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Test log message
10  */
11 
12 #include <zephyr/sys/mpsc_pbuf.h>
13 
14 #include <zephyr/tc_util.h>
15 #include <stdbool.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/ztest.h>
18 #include <zephyr/random/random.h>
19 
20 #define PUT_EXT_LEN \
21 	((sizeof(union mpsc_pbuf_generic) + sizeof(void *)) / sizeof(uint32_t))
22 
23 #define LEN_BITS 9
24 
25 struct test_data {
26 	MPSC_PBUF_HDR;
27 	uint32_t len : LEN_BITS;
28 	uint32_t data : 32 - MPSC_PBUF_HDR_BITS - LEN_BITS;
29 };
30 
31 struct test_data_ext {
32 	struct test_data hdr;
33 	void *data;
34 } __packed;
35 
36 struct test_data_var {
37 	struct test_data hdr;
38 	uint32_t data[];
39 };
40 
41 union test_item {
42 	struct test_data data;
43 	struct test_data_ext data_ext;
44 	union mpsc_pbuf_generic item;
45 };
46 
get_wlen(const union mpsc_pbuf_generic * item)47 static uint32_t get_wlen(const union mpsc_pbuf_generic *item)
48 {
49 	union test_item *t_item = (union test_item *)item;
50 
51 	return t_item->data.len;
52 }
53 
54 static uint32_t drop_cnt;
55 static uint32_t exp_drop_cnt;
56 static uintptr_t exp_dropped_data[10];
57 static uint32_t exp_dropped_len[10];
58 
drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)59 static void drop(const struct mpsc_pbuf_buffer *buffer, const union mpsc_pbuf_generic *item)
60 {
61 	struct test_data_var *packet = (struct test_data_var *)item;
62 
63 	zassert_true(drop_cnt < exp_drop_cnt);
64 	zassert_equal(packet->hdr.len, exp_dropped_len[drop_cnt],
65 			"(%d) Got:%08x, Expected: %08x",
66 			drop_cnt, packet->hdr.len, exp_dropped_len[drop_cnt]);
67 	zassert_equal(packet->hdr.data, exp_dropped_data[drop_cnt],
68 			"(%d) Got:%08x, Expected: %08x",
69 			drop_cnt, packet->hdr.data, (uint32_t)exp_dropped_data[drop_cnt]);
70 	for (int i = 0; i < exp_dropped_len[drop_cnt] - 1; i++) {
71 		int err = memcmp(packet->data, &exp_dropped_data[drop_cnt],
72 				 sizeof(uint32_t));
73 
74 
75 		zassert_equal(err, 0);
76 	}
77 
78 	drop_cnt++;
79 }
80 
81 static uint32_t buf32[512];
82 
83 static struct mpsc_pbuf_buffer_config mpsc_buf_cfg = {
84 	.buf = buf32,
85 	.size = ARRAY_SIZE(buf32),
86 	.notify_drop = drop,
87 	.get_wlen = get_wlen
88 };
89 
init(struct mpsc_pbuf_buffer * buffer,uint32_t wlen,bool overwrite)90 static void init(struct mpsc_pbuf_buffer *buffer, uint32_t wlen, bool overwrite)
91 {
92 	drop_cnt = 0;
93 	exp_drop_cnt = 0;
94 	mpsc_buf_cfg.flags = overwrite ? MPSC_PBUF_MODE_OVERWRITE : 0;
95 	mpsc_buf_cfg.size = wlen;
96 	mpsc_pbuf_init(buffer, &mpsc_buf_cfg);
97 
98 #if CONFIG_SOC_SERIES_NRF52X
99 	DCB->DEMCR |= DCB_DEMCR_TRCENA_Msk;
100 	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
101 	DWT->CYCCNT = 0;
102 #endif
103 }
104 
get_cyc(void)105 static inline uint32_t get_cyc(void)
106 {
107 #if CONFIG_SOC_SERIES_NRF52X
108 	return DWT->CYCCNT;
109 #else
110 	return k_cycle_get_32();
111 #endif
112 }
113 
item_put_no_overwrite(bool pow2)114 void item_put_no_overwrite(bool pow2)
115 {
116 	struct mpsc_pbuf_buffer buffer;
117 
118 	init(&buffer, 4 - !pow2, false);
119 
120 	int repeat = buffer.size*2;
121 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
122 
123 	for (int i = 0; i < repeat; i++) {
124 		union test_item *t;
125 
126 		test_1word.data.data = i;
127 		mpsc_pbuf_put_word(&buffer, test_1word.item);
128 
129 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
130 		zassert_true(t);
131 		zassert_equal(t->data.data, i);
132 		mpsc_pbuf_free(&buffer, &t->item);
133 
134 	}
135 
136 	zassert_is_null(mpsc_pbuf_claim(&buffer));
137 }
138 
ZTEST(log_buffer,test_item_put_no_overwrite)139 ZTEST(log_buffer, test_item_put_no_overwrite)
140 {
141 	item_put_no_overwrite(true);
142 	item_put_no_overwrite(false);
143 }
144 
item_put_overwrite(bool pow2)145 void item_put_overwrite(bool pow2)
146 {
147 	struct mpsc_pbuf_buffer buffer;
148 
149 	init(&buffer, 4 - !pow2, true);
150 
151 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
152 
153 	exp_dropped_data[0] = 0;
154 	exp_dropped_len[0] = 1;
155 	exp_drop_cnt = 1;
156 
157 	for (int i = 0; i < buffer.size + 1; i++) {
158 		test_1word.data.data = i;
159 		mpsc_pbuf_put_word(&buffer, test_1word.item);
160 	}
161 
162 	zassert_equal(drop_cnt, exp_drop_cnt,
163 			"Unexpected number of dropped messages: %d", drop_cnt);
164 }
165 
ZTEST(log_buffer,test_item_put_overwrite)166 ZTEST(log_buffer, test_item_put_overwrite)
167 {
168 	item_put_overwrite(true);
169 	item_put_overwrite(false);
170 }
171 
item_put_saturate(bool pow2)172 void item_put_saturate(bool pow2)
173 {
174 	struct mpsc_pbuf_buffer buffer;
175 
176 	init(&buffer, 4 - !pow2, false);
177 
178 	int repeat = buffer.size;
179 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
180 	union test_item *t;
181 
182 	zassert_false(mpsc_pbuf_is_pending(&buffer));
183 
184 	for (int i = 0; i < repeat / 2; i++) {
185 		test_1word.data.data = i;
186 		mpsc_pbuf_put_word(&buffer, test_1word.item);
187 
188 		zassert_true(mpsc_pbuf_is_pending(&buffer));
189 
190 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
191 		zassert_true(t);
192 		zassert_equal(t->data.data, i);
193 		mpsc_pbuf_free(&buffer, &t->item);
194 	}
195 
196 	for (int i = 0; i < repeat + 1; i++) {
197 		test_1word.data.data = i;
198 		mpsc_pbuf_put_word(&buffer, test_1word.item);
199 	}
200 
201 	for (int i = 0; i < repeat; i++) {
202 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
203 		zassert_true(t);
204 		zassert_equal(t->data.data, i);
205 		mpsc_pbuf_free(&buffer, &t->item);
206 	}
207 
208 	zassert_is_null(mpsc_pbuf_claim(&buffer));
209 }
210 
ZTEST(log_buffer,test_item_put_saturate)211 ZTEST(log_buffer, test_item_put_saturate)
212 {
213 	item_put_saturate(true);
214 	item_put_saturate(false);
215 }
216 
benchmark_item_put(bool pow2)217 void benchmark_item_put(bool pow2)
218 {
219 	struct mpsc_pbuf_buffer buffer;
220 
221 	init(&buffer, ARRAY_SIZE(buf32) - !pow2, true);
222 
223 	int repeat = buffer.size - 1;
224 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
225 	uint32_t t = get_cyc();
226 
227 	for (int i = 0; i < repeat; i++) {
228 		test_1word.data.data = i;
229 		mpsc_pbuf_put_word(&buffer, test_1word.item);
230 	}
231 
232 	t = get_cyc() - t;
233 	PRINT("%s buffer\n", pow2 ? "pow2" : "non-pow2");
234 	PRINT("single word put time: %d cycles\n", t/repeat);
235 
236 	t = get_cyc();
237 	for (int i = 0; i < repeat; i++) {
238 		union test_item *ti;
239 
240 		ti = (union test_item *)mpsc_pbuf_claim(&buffer);
241 		zassert_true(ti);
242 		zassert_equal(ti->data.data, i);
243 		mpsc_pbuf_free(&buffer, &ti->item);
244 	}
245 
246 	t = get_cyc() - t;
247 	PRINT("single word item claim,free: %d cycles\n", t/repeat);
248 
249 	zassert_is_null(mpsc_pbuf_claim(&buffer));
250 }
251 
ZTEST(log_buffer,test_benchmark_item_put)252 ZTEST(log_buffer, test_benchmark_item_put)
253 {
254 	benchmark_item_put(true);
255 	benchmark_item_put(false);
256 }
257 
item_put_ext_no_overwrite(bool pow2)258 void item_put_ext_no_overwrite(bool pow2)
259 {
260 	struct mpsc_pbuf_buffer buffer;
261 
262 	init(&buffer, 8 - !pow2, false);
263 
264 	int repeat = buffer.size * 2;
265 	union test_item test_ext_item = {
266 		.data = {
267 			.valid = 1,
268 			.len = PUT_EXT_LEN
269 		}
270 	};
271 	void *data;
272 
273 	for (uintptr_t i = 0; i < repeat; i++) {
274 		union test_item *t;
275 
276 		data = (void *)i;
277 		test_ext_item.data.data = i;
278 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
279 
280 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
281 		zassert_true(t);
282 		zassert_equal(t->data_ext.hdr.data, i);
283 		zassert_equal(t->data_ext.data, (void *)i);
284 		mpsc_pbuf_free(&buffer, &t->item);
285 	}
286 
287 	zassert_is_null(mpsc_pbuf_claim(&buffer));
288 }
289 
ZTEST(log_buffer,test_item_put_ext_no_overwrite)290 ZTEST(log_buffer, test_item_put_ext_no_overwrite)
291 {
292 	item_put_ext_no_overwrite(true);
293 	item_put_ext_no_overwrite(false);
294 }
295 
item_put_word_ext_overwrite(bool pow2)296 void item_put_word_ext_overwrite(bool pow2)
297 {
298 	struct mpsc_pbuf_buffer buffer;
299 
300 	init(&buffer, 8 - !pow2, true);
301 
302 	size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
303 	int repeat = 1 + buffer.size / w;
304 	union test_item test_ext_item = {
305 		.data = {
306 			.valid = 1,
307 			.len = PUT_EXT_LEN
308 		}
309 	};
310 
311 	exp_dropped_data[0] = 0;
312 	exp_dropped_len[0] = w;
313 	exp_drop_cnt = 1;
314 
315 	for (uintptr_t i = 0; i < repeat; i++) {
316 		test_ext_item.data.data = i;
317 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, (void *)i);
318 	}
319 
320 	zassert_equal(drop_cnt, exp_drop_cnt,
321 			"Unexpected number of dropped messages: %d (exp: %d)",
322 			drop_cnt, exp_drop_cnt);
323 }
324 
ZTEST(log_buffer,test_item_put_word_ext_overwrite)325 ZTEST(log_buffer, test_item_put_word_ext_overwrite)
326 {
327 	item_put_word_ext_overwrite(true);
328 	item_put_word_ext_overwrite(false);
329 }
330 
item_put_ext_saturate(bool pow2)331 void item_put_ext_saturate(bool pow2)
332 {
333 	struct mpsc_pbuf_buffer buffer;
334 
335 	init(&buffer, 8 - !pow2, false);
336 
337 	int repeat = buffer.size / PUT_EXT_LEN;
338 	union test_item test_ext_item = {
339 		.data = {
340 			.valid = 1,
341 			.len = PUT_EXT_LEN
342 		}
343 	};
344 	void *data;
345 	union test_item *t;
346 
347 	for (uintptr_t i = 0; i < repeat/2; i++) {
348 		test_ext_item.data.data = i;
349 		data = (void *)i;
350 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
351 
352 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
353 		zassert_true(t);
354 		zassert_equal(t->data.data, i);
355 		mpsc_pbuf_free(&buffer, &t->item);
356 	}
357 
358 	for (uintptr_t i = 0; i < repeat; i++) {
359 		test_ext_item.data.data = i;
360 		data = (void *)i;
361 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
362 	}
363 
364 	for (uintptr_t i = 0; i < repeat; i++) {
365 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
366 		zassert_true(t);
367 		zassert_equal(t->data_ext.data, (void *)i);
368 		zassert_equal(t->data_ext.hdr.data, i);
369 		mpsc_pbuf_free(&buffer, &t->item);
370 	}
371 
372 	zassert_is_null(mpsc_pbuf_claim(&buffer));
373 }
374 
ZTEST(log_buffer,test_item_put_ext_saturate)375 ZTEST(log_buffer, test_item_put_ext_saturate)
376 {
377 	item_put_ext_saturate(true);
378 	item_put_ext_saturate(false);
379 }
380 
benchmark_item_put_ext(bool pow2)381 void benchmark_item_put_ext(bool pow2)
382 {
383 	struct mpsc_pbuf_buffer buffer;
384 
385 	init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
386 
387 	int repeat = (buffer.size - 1) / PUT_EXT_LEN;
388 	union test_item test_ext_item = {
389 		.data = {
390 			.valid = 1,
391 			.len = PUT_EXT_LEN
392 		}
393 	};
394 	void *data = NULL;
395 	uint32_t t = get_cyc();
396 
397 	for (int i = 0; i < repeat; i++) {
398 		test_ext_item.data.data = i;
399 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
400 	}
401 
402 	t = get_cyc() - t;
403 	PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
404 	PRINT("put_ext time: %d cycles\n", t/repeat);
405 
406 	t = get_cyc();
407 	for (int i = 0; i < repeat; i++) {
408 		union test_item *ti;
409 
410 		ti = (union test_item *)mpsc_pbuf_claim(&buffer);
411 		zassert_true(ti);
412 		zassert_equal(ti->data.data, i);
413 		mpsc_pbuf_free(&buffer, &ti->item);
414 	}
415 
416 	t = get_cyc() - t;
417 	PRINT("ext item claim,free: %d cycles\n", t/repeat);
418 
419 	zassert_is_null(mpsc_pbuf_claim(&buffer));
420 }
421 
ZTEST(log_buffer,test_benchmark_item_put_ext)422 ZTEST(log_buffer, test_benchmark_item_put_ext)
423 {
424 	benchmark_item_put_ext(true);
425 	benchmark_item_put_ext(false);
426 }
427 
benchmark_item_put_data(bool pow2)428 void benchmark_item_put_data(bool pow2)
429 {
430 	struct mpsc_pbuf_buffer buffer;
431 
432 	init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
433 
434 	int repeat = (buffer.size - 1) / PUT_EXT_LEN;
435 	union test_item test_ext_item = {
436 		.data_ext = {
437 			.hdr = {
438 				.valid = 1,
439 				.len = PUT_EXT_LEN
440 			},
441 			.data = NULL
442 		}
443 	};
444 	uint32_t cyc = get_cyc();
445 
446 	for (uintptr_t i = 0; i < repeat; i++) {
447 		test_ext_item.data_ext.hdr.data = i;
448 		test_ext_item.data_ext.data = (void *)i;
449 		mpsc_pbuf_put_data(&buffer, (uint32_t *)&test_ext_item,
450 				    PUT_EXT_LEN);
451 	}
452 
453 	cyc = get_cyc() - cyc;
454 	PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
455 	PRINT("put_ext time: %d cycles\n", cyc/repeat);
456 
457 	cyc = get_cyc();
458 	for (int i = 0; i < repeat; i++) {
459 		union test_item *ti;
460 
461 		ti = (union test_item *)mpsc_pbuf_claim(&buffer);
462 		zassert_true(ti);
463 		zassert_equal(ti->data.data, i);
464 		mpsc_pbuf_free(&buffer, &ti->item);
465 	}
466 
467 	cyc = get_cyc() - cyc;
468 	PRINT("ext item claim,free: %d cycles\n", cyc/repeat);
469 
470 	zassert_is_null(mpsc_pbuf_claim(&buffer));
471 }
472 
ZTEST(log_buffer,test_benchmark_item_put_data)473 ZTEST(log_buffer, test_benchmark_item_put_data)
474 {
475 	benchmark_item_put_data(true);
476 	benchmark_item_put_data(false);
477 }
478 
item_put_data_overwrite(bool pow2)479 void item_put_data_overwrite(bool pow2)
480 {
481 	struct mpsc_pbuf_buffer buffer;
482 
483 	init(&buffer, 8 - !pow2, true);
484 
485 	size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
486 	int repeat = 1 + buffer.size / w;
487 	static const int len = sizeof(struct test_data_ext) / sizeof(uint32_t);
488 	struct test_data_ext item = {
489 		.hdr = {
490 			.valid = 1,
491 			.len = len
492 		}
493 	};
494 
495 	exp_dropped_data[0] = 0;
496 	exp_dropped_len[0] = w;
497 	exp_drop_cnt = 1;
498 
499 	for (uintptr_t i = 0; i < repeat; i++) {
500 		void *vitem;
501 		item.data = (void *)i;
502 		item.hdr.data = i;
503 		vitem = (uint32_t *)&item;
504 		zassert_true(IS_PTR_ALIGNED(vitem, uint32_t), "unaligned ptr");
505 		mpsc_pbuf_put_data(&buffer, (uint32_t *)vitem, len);
506 	}
507 
508 	zassert_equal(drop_cnt, exp_drop_cnt,
509 			"Unexpected number of dropped messages: %d", drop_cnt);
510 }
511 
ZTEST(log_buffer,test_put_data_overwrite)512 ZTEST(log_buffer, test_put_data_overwrite)
513 {
514 	item_put_data_overwrite(true);
515 	item_put_data_overwrite(false);
516 }
517 
item_alloc_commit(bool pow2)518 void item_alloc_commit(bool pow2)
519 {
520 	struct mpsc_pbuf_buffer buffer;
521 
522 	init(&buffer, 16 - !pow2, false);
523 
524 	struct test_data_var *packet;
525 	uint32_t len = 5;
526 	int repeat = 1024;
527 
528 	for (int i = 0; i < repeat; i++) {
529 		packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
530 								 K_NO_WAIT);
531 		packet->hdr.len = len;
532 		for (int j = 0; j < len - 1; j++) {
533 			packet->data[j] = i + j;
534 		}
535 
536 		mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
537 
538 		packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
539 		zassert_true(packet);
540 		zassert_equal(packet->hdr.len, len);
541 
542 		for (int j = 0; j < len - 1; j++) {
543 			zassert_equal(packet->data[j], i + j);
544 		}
545 
546 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
547 	}
548 }
549 
ZTEST(log_buffer,test_item_alloc_commit)550 ZTEST(log_buffer, test_item_alloc_commit)
551 {
552 	item_alloc_commit(true);
553 	item_alloc_commit(false);
554 }
555 
item_max_alloc(bool overwrite)556 void item_max_alloc(bool overwrite)
557 {
558 	struct mpsc_pbuf_buffer buffer;
559 	struct test_data_var *packet;
560 
561 	init(&buffer, 8, overwrite);
562 
563 	/* First try to allocate the biggest possible packet. */
564 	for (int i = 0; i < 2; i++) {
565 		packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
566 								 buffer.size,
567 								 K_NO_WAIT);
568 		zassert_true(packet != NULL);
569 		packet->hdr.len = buffer.size;
570 		mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
571 
572 		packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
573 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
574 	}
575 
576 	/* Too big packet cannot be allocated. */
577 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
578 							 buffer.size + 1,
579 							 K_NO_WAIT);
580 	zassert_true(packet == NULL);
581 }
582 
ZTEST(log_buffer,test_item_max_alloc)583 ZTEST(log_buffer, test_item_max_alloc)
584 {
585 	item_max_alloc(true);
586 	item_max_alloc(false);
587 }
588 
saturate_buffer_uneven(struct mpsc_pbuf_buffer * buffer,uint32_t len)589 static uint32_t saturate_buffer_uneven(struct mpsc_pbuf_buffer *buffer,
590 					uint32_t len)
591 {
592 	struct test_data_var *packet;
593 	uint32_t uneven = 3;
594 	uint32_t cnt = 0;
595 	int repeat =
596 		uneven + ((buffer->size - (uneven * len)) / len);
597 
598 	/* Put some data to include wrapping */
599 	for (int i = 0; i < uneven; i++) {
600 		packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
601 								 K_NO_WAIT);
602 		packet->hdr.len = len;
603 		mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
604 
605 		packet = (struct test_data_var *)mpsc_pbuf_claim(buffer);
606 		zassert_true(packet);
607 		mpsc_pbuf_free(buffer, (union mpsc_pbuf_generic *)packet);
608 	}
609 
610 	for (int i = 0; i < repeat; i++) {
611 		packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
612 								 K_NO_WAIT);
613 		zassert_true(packet);
614 		packet->hdr.len = len;
615 		packet->hdr.data = i;
616 		for (int j = 0; j < len - 1; j++) {
617 			packet->data[j] = i + j;
618 		}
619 
620 		mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
621 		cnt++;
622 	}
623 
624 	return cnt;
625 }
626 
item_alloc_commit_saturate(bool pow2)627 void item_alloc_commit_saturate(bool pow2)
628 {
629 	struct mpsc_pbuf_buffer buffer;
630 
631 	init(&buffer, 32 - !pow2, false);
632 
633 	saturate_buffer_uneven(&buffer, 5);
634 
635 	struct test_data_var *packet;
636 	uint32_t len = 5;
637 
638 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
639 							 K_NO_WAIT);
640 	zassert_is_null(packet);
641 
642 	/* Get one packet from the buffer. */
643 	packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
644 	zassert_true(packet);
645 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
646 
647 	/* and try to allocate one more time, this time with success. */
648 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
649 							 K_NO_WAIT);
650 	zassert_true(packet);
651 }
652 
ZTEST(log_buffer,test_item_alloc_commit_saturate)653 ZTEST(log_buffer, test_item_alloc_commit_saturate)
654 {
655 	item_alloc_commit_saturate(true);
656 	item_alloc_commit_saturate(false);
657 }
658 
item_alloc_preemption(bool pow2)659 void item_alloc_preemption(bool pow2)
660 {
661 	struct mpsc_pbuf_buffer buffer;
662 
663 	init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
664 
665 	struct test_data_var *p0;
666 	struct test_data_var *p1;
667 	struct test_data_var *p;
668 
669 	p0 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 10, K_NO_WAIT);
670 	zassert_true(p0);
671 	p0->hdr.len = 10;
672 
673 	/* Check that no packet is yet available */
674 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
675 	zassert_is_null(p);
676 
677 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 20, K_NO_WAIT);
678 	zassert_true(p1);
679 	p1->hdr.len = 20;
680 
681 	/* Commit p1, p0 is still not committed, there should be no packets
682 	 * available for reading.
683 	 */
684 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
685 
686 	/* Check that no packet is yet available */
687 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
688 	zassert_is_null(p);
689 
690 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p0);
691 
692 	/* Validate that p0 is the first one. */
693 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
694 	zassert_true(p);
695 	zassert_equal(p->hdr.len, 10);
696 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
697 
698 	/* Validate that p1 is the next one. */
699 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
700 	zassert_true(p);
701 	zassert_equal(p->hdr.len, 20);
702 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
703 
704 	/* No more packets. */
705 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
706 	zassert_is_null(p);
707 }
708 
ZTEST(log_buffer,test_item_alloc_preemption)709 ZTEST(log_buffer, test_item_alloc_preemption)
710 {
711 	item_alloc_preemption(true);
712 	item_alloc_preemption(false);
713 }
714 
overwrite(bool pow2)715 void overwrite(bool pow2)
716 {
717 	struct test_data_var *p;
718 	uint32_t fill_len = 5;
719 	uint32_t len0, len1;
720 	struct mpsc_pbuf_buffer buffer;
721 
722 	init(&buffer, 32 - !pow2, true);
723 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
724 
725 	zassert_equal(drop_cnt, exp_drop_cnt);
726 
727 	exp_dropped_data[0] = 0;
728 	exp_dropped_len[0] = fill_len;
729 	exp_drop_cnt++;
730 	exp_dropped_data[1] = 1;
731 	exp_dropped_len[1] = fill_len;
732 	exp_drop_cnt++;
733 
734 	len0 = 6;
735 	p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len0, K_NO_WAIT);
736 
737 	p->hdr.len = len0;
738 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
739 	zassert_equal(drop_cnt, exp_drop_cnt);
740 
741 	/* Request allocation which will require dropping 2 packets. */
742 	len1 = 9;
743 	exp_dropped_data[1] = 1;
744 	exp_dropped_len[1] = fill_len;
745 	exp_dropped_data[2] = 2;
746 	exp_dropped_len[2] = fill_len;
747 	exp_drop_cnt = 3;
748 
749 	p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len1, K_NO_WAIT);
750 
751 	p->hdr.len = len1;
752 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
753 	zassert_equal(drop_cnt, exp_drop_cnt);
754 
755 	for (int i = 0; i < (packet_cnt - drop_cnt); i++) {
756 		p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
757 		zassert_true(p);
758 		zassert_equal(p->hdr.len, fill_len);
759 		zassert_equal(p->hdr.data, i + drop_cnt);
760 		for (int j = 0; j < fill_len - 1; j++) {
761 			zassert_equal(p->data[j], p->hdr.data + j);
762 		}
763 
764 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
765 	}
766 
767 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
768 	zassert_true(p);
769 	zassert_equal(p->hdr.len, len0);
770 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
771 
772 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
773 	zassert_true(p);
774 	zassert_equal(p->hdr.len, len1);
775 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
776 
777 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
778 	zassert_is_null(p);
779 }
780 
ZTEST(log_buffer,test_overwrite)781 ZTEST(log_buffer, test_overwrite)
782 {
783 	overwrite(true);
784 	overwrite(false);
785 }
786 
overwrite_while_claimed(bool pow2)787 void overwrite_while_claimed(bool pow2)
788 {
789 	struct test_data_var *p0;
790 	struct test_data_var *p1;
791 	struct mpsc_pbuf_buffer buffer;
792 
793 	init(&buffer, 32 - !pow2, true);
794 
795 	uint32_t fill_len = 5;
796 	uint32_t len = 6;
797 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
798 
799 	/* Start by claiming a packet. Buffer is now full. Allocation shall
800 	 * skip claimed packed and drop the next one.
801 	 */
802 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
803 	zassert_true(p0);
804 	zassert_equal(p0->hdr.len, fill_len);
805 
806 	exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
807 	exp_dropped_len[0] = fill_len;
808 	exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
809 	exp_dropped_len[1] = fill_len;
810 	exp_drop_cnt = 2;
811 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 6, K_NO_WAIT);
812 	zassert_equal(drop_cnt, exp_drop_cnt);
813 	p1->hdr.len = len;
814 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
815 
816 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
817 
818 	for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
819 		p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
820 		zassert_true(p0);
821 		zassert_equal(p0->hdr.len, fill_len);
822 		zassert_equal(p0->hdr.data, i + drop_cnt + 1);
823 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
824 	}
825 
826 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
827 	zassert_true(p0);
828 	zassert_equal(p0->hdr.len, len);
829 
830 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
831 	zassert_is_null(p0);
832 }
833 
ZTEST(log_buffer,test_overwrite_while_claimed)834 ZTEST(log_buffer, test_overwrite_while_claimed)
835 {
836 	overwrite_while_claimed(true);
837 	overwrite_while_claimed(false);
838 }
839 
overwrite_while_claimed2(bool pow2)840 void overwrite_while_claimed2(bool pow2)
841 {
842 	struct test_data_var *p0;
843 	struct test_data_var *p1;
844 	struct mpsc_pbuf_buffer buffer;
845 
846 	init(&buffer, 32 - !pow2, true);
847 
848 	uint32_t fill_len = 1;
849 	uint32_t len = 3;
850 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
851 
852 	/* Start by claiming a packet. Buffer is now full. Allocation shall
853 	 * skip claimed packed and drop the next one.
854 	 */
855 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
856 	zassert_true(p0);
857 	zassert_equal(p0->hdr.len, fill_len);
858 
859 	exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
860 	exp_dropped_len[0] = fill_len;
861 	exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
862 	exp_dropped_len[1] = fill_len;
863 	exp_dropped_data[2] = p0->hdr.data + 3; /* next packet is dropped */
864 	exp_dropped_len[2] = fill_len;
865 	exp_drop_cnt = 3;
866 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
867 
868 	zassert_equal(drop_cnt, exp_drop_cnt);
869 	p1->hdr.len = len;
870 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
871 
872 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
873 
874 	for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
875 		p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
876 		zassert_true(p0);
877 		zassert_equal(p0->hdr.len, fill_len);
878 		zassert_equal(p0->hdr.data, i + drop_cnt + 1);
879 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
880 	}
881 
882 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
883 	zassert_true(p0);
884 	zassert_equal(p0->hdr.len, len);
885 
886 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
887 	zassert_is_null(p0);
888 }
889 
ZTEST(log_buffer,test_overwrite_while_claimed2)890 ZTEST(log_buffer, test_overwrite_while_claimed2)
891 {
892 	overwrite_while_claimed2(true);
893 	overwrite_while_claimed2(false);
894 }
895 
896 static uintptr_t current_rd_idx;
897 
validate_packet(struct test_data_var * packet)898 static void validate_packet(struct test_data_var *packet)
899 {
900 	zassert_equal((uintptr_t)packet->hdr.data, current_rd_idx,
901 			"Got %x, expected: %x",
902 			(uint32_t)packet->hdr.data, (uint32_t)current_rd_idx);
903 	current_rd_idx++;
904 }
905 
consistent_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)906 static void consistent_drop(const struct mpsc_pbuf_buffer *buffer,
907 			    const union mpsc_pbuf_generic *item)
908 {
909 	validate_packet((struct test_data_var *)item);
910 }
911 
rand_get(uint32_t min,uint32_t max)912 uint32_t rand_get(uint32_t min, uint32_t max)
913 {
914 	return min + (sys_rand32_get() % max);
915 }
916 
ZTEST(log_buffer,test_overwrite_consistency)917 ZTEST(log_buffer, test_overwrite_consistency)
918 {
919 	struct mpsc_pbuf_buffer buffer;
920 	static struct mpsc_pbuf_buffer_config cfg = {
921 		.buf = buf32,
922 		.size = ARRAY_SIZE(buf32),
923 		.notify_drop = consistent_drop,
924 		.get_wlen = get_wlen,
925 		.flags = MPSC_PBUF_MODE_OVERWRITE
926 	};
927 
928 	mpsc_pbuf_init(&buffer, &cfg);
929 	int repeat = 50000;
930 	int id = 0;
931 
932 	while (id < repeat) {
933 		struct test_data_var *tdv = NULL;
934 		bool alloc_during_claim = (rand_get(1, 5) <= 2);
935 
936 		/* Occasionally claim buffer to simulate that claiming is
937 		 * interrupted by allocation.
938 		 */
939 		if (alloc_during_claim) {
940 			tdv = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
941 			if (tdv) {
942 				validate_packet(tdv);
943 			}
944 		}
945 
946 		uint32_t wr_cnt = rand_get(1, 15);
947 
948 		for (int i = 0; i < wr_cnt; i++) {
949 			uint32_t wlen = rand_get(1, 15);
950 			struct test_data_var *tdv2;
951 
952 			tdv2 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
953 								       wlen,
954 								       K_NO_WAIT);
955 			tdv2->hdr.len = wlen;
956 			tdv2->hdr.data = id++;
957 			mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)tdv2);
958 		}
959 
960 		/* Put back item claimed before committing new items. */
961 		if (tdv) {
962 			mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)tdv);
963 		}
964 
965 		uint32_t rd_cnt = rand_get(1, 30);
966 
967 		for (int i = 0; i < rd_cnt; i++) {
968 			struct test_data_var *tdv2;
969 
970 			tdv2 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
971 			if (!tdv2) {
972 				continue;
973 			}
974 
975 			validate_packet(tdv2);
976 			mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)tdv2);
977 		}
978 	}
979 }
980 
981 K_THREAD_STACK_DEFINE(t1_stack, 1024);
982 K_THREAD_STACK_DEFINE(t2_stack, 1024);
983 
984 static k_thread_stack_t *stacks[2] = {t1_stack, t2_stack};
985 static struct k_thread threads[2];
986 static k_tid_t tids[2];
987 
t_entry(void * p0,void * p1,void * p2)988 void t_entry(void *p0, void *p1, void *p2)
989 {
990 	struct mpsc_pbuf_buffer *buffer = p0;
991 	uintptr_t wait_ms = (uintptr_t)p1;
992 	struct test_data_ext *t;
993 	void *vt;
994 
995 	t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
996 						    sizeof(*t) / sizeof(uint32_t),
997 						    K_MSEC(1));
998 	zassert_is_null(t);
999 
1000 	t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
1001 						    sizeof(*t) / sizeof(uint32_t),
1002 						    K_MSEC(wait_ms));
1003 	t->hdr.len = PUT_EXT_LEN;
1004 	t->data = k_current_get();
1005 
1006 	vt = t;
1007 	zassert_true(IS_PTR_ALIGNED(vt, union mpsc_pbuf_generic), "unaligned ptr");
1008 	mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)vt);
1009 	while (1) {
1010 		k_sleep(K_MSEC(10));
1011 	}
1012 }
1013 
start_threads(struct mpsc_pbuf_buffer * buffer)1014 void start_threads(struct mpsc_pbuf_buffer *buffer)
1015 {
1016 	int prio = 2;
1017 	uintptr_t wait_ms = 1000;
1018 
1019 	for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1020 		tids[i] = k_thread_create(&threads[i], stacks[i], 1024, t_entry,
1021 					  buffer, (void *)wait_ms, NULL,
1022 					  prio--,
1023 					  0, K_NO_WAIT);
1024 	}
1025 
1026 	k_sleep(K_MSEC(10));
1027 
1028 	for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1029 		k_ticks_t t = k_thread_timeout_remaining_ticks(tids[i]);
1030 		k_ticks_t exp_wait = k_ms_to_ticks_ceil32(wait_ms);
1031 
1032 		/* Threads shall be blocked, waiting for available space. */
1033 		zassert_within(t, exp_wait, k_ms_to_ticks_ceil32(20));
1034 	}
1035 }
1036 
1037 static uint32_t buf32_1[128];
1038 struct test_msg_data {
1039 	union mpsc_pbuf_generic hdr;
1040 	uint32_t buf_len; /*contain buf_len and buf*/
1041 	uint8_t buf[sizeof(buf32_1)];
1042 };
1043 struct test_msg_hnd {
1044 	struct mpsc_pbuf_buffer mpsc_buffer;
1045 	uint32_t product_max_cnt;
1046 	uint32_t product_cnt;
1047 	uint32_t consumer_cnt;
1048 };
1049 
1050 K_THREAD_STACK_DEFINE(t3_stack, 1024);
1051 static struct k_thread threads_t3;
1052 static k_tid_t tid3;
1053 
test_mpsc_get_used_len(const union mpsc_pbuf_generic * packet)1054 static uint32_t test_mpsc_get_used_len(const union mpsc_pbuf_generic *packet)
1055 {
1056 	uint32_t size = 0;
1057 	struct test_msg_data *msg_data = NULL;
1058 
1059 	msg_data =  CONTAINER_OF(packet, struct test_msg_data, hdr);
1060 	size = msg_data->buf_len + sizeof(union mpsc_pbuf_generic);
1061 	size = ROUND_UP(size, sizeof(uint32_t)); /*return number  of uint32_t */
1062 	size = size / sizeof(uint32_t);
1063 	return size;
1064 }
1065 
t_data_consumer_entry(void * p0,void * p1,void * p2)1066 static void t_data_consumer_entry(void *p0, void *p1, void *p2)
1067 {
1068 	uint32_t read_cnt = 0;
1069 	bool wait = true;
1070 	const union mpsc_pbuf_generic *msg = NULL;
1071 	const struct test_msg_data *test_data = NULL;
1072 	struct test_msg_hnd *test_hnd = (struct test_msg_hnd *)p0;
1073 
1074 	while (1) {
1075 		if (msg == NULL) {
1076 			msg = mpsc_pbuf_claim(&test_hnd->mpsc_buffer);
1077 		}
1078 		test_data = (const struct test_msg_data *)msg;
1079 		if (test_data == NULL) {
1080 			continue;
1081 		}
1082 		if (test_data && test_hnd->mpsc_buffer.wr_idx == 0) {
1083 			wait = false;
1084 		}
1085 		if (wait == true) {
1086 			continue;
1087 		}
1088 		read_cnt++;
1089 		mpsc_pbuf_free(&test_hnd->mpsc_buffer, msg);
1090 		msg = NULL;
1091 		if (read_cnt == test_hnd->product_max_cnt) {
1092 			break;
1093 		}
1094 
1095 	}
1096 	test_hnd->consumer_cnt = read_cnt;
1097 }
1098 
1099 /* test mpsc_pbuf_alloc can get sem_take
1100  * one thread product data, one thread consumer data
1101  * requirement:
1102  *      consumer slow process data
1103  * step:
1104  *  1:product data len is  0.75 of cfg.size
1105  *  2:run product times
1106  *
1107  */
ZTEST(log_buffer,test_sema_lock)1108 ZTEST(log_buffer, test_sema_lock)
1109 {
1110 	struct test_msg_hnd  test_hnd = {};
1111 	struct test_msg_data  test_data;
1112 	struct test_msg_data  *item = NULL;
1113 	struct mpsc_pbuf_buffer_config  cfg;
1114 	uint32_t loop = 0;
1115 	size_t wlen = 0;
1116 	bool fist_wait = true;
1117 
1118 	if (CONFIG_SYS_CLOCK_TICKS_PER_SEC < 10000) {
1119 		ztest_test_skip();
1120 	}
1121 
1122 	cfg.buf = buf32_1;
1123 	cfg.size = ARRAY_SIZE(buf32_1);
1124 	cfg.get_wlen = test_mpsc_get_used_len;
1125 
1126 	mpsc_pbuf_init(&test_hnd.mpsc_buffer, &cfg);
1127 	test_hnd.product_max_cnt = 2;
1128 
1129 	tid3 = k_thread_create(&threads_t3, t3_stack, 1024,
1130 			t_data_consumer_entry,
1131 			&test_hnd, NULL, NULL,
1132 			10, 0, K_NO_WAIT);
1133 	k_thread_name_set(&threads_t3, "test_mpsc_consumer");
1134 	for (loop = 0; loop < test_hnd.product_max_cnt; loop++) {
1135 		if (loop == 0) {
1136 			test_data.buf_len = sizeof(buf32_1) / 2;
1137 		} else {
1138 			test_data.buf_len = sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4;
1139 		}
1140 		test_data.buf_len = ROUND_UP(test_data.buf_len, sizeof(uint32_t));
1141 		memset(test_data.buf, loop + 1, test_data.buf_len);
1142 
1143 		wlen = test_data.buf_len + sizeof(test_data.buf_len) +
1144 			 sizeof(test_data.hdr);
1145 		wlen = ROUND_UP(wlen, sizeof(uint32_t));
1146 		wlen = wlen / sizeof(uint32_t);
1147 
1148 		if (fist_wait &&
1149 		   test_data.buf_len == sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4) {
1150 			PRINT(" mpsc sema wait\n");
1151 		}
1152 		item = (struct test_msg_data *)mpsc_pbuf_alloc(&test_hnd.mpsc_buffer,
1153 								wlen, K_FOREVER);
1154 		item->hdr.raw = 0;
1155 		memcpy(item->buf, test_data.buf, test_data.buf_len);
1156 		item->buf_len = test_data.buf_len + sizeof(test_data.buf_len);
1157 		mpsc_pbuf_commit(&test_hnd.mpsc_buffer, &item->hdr);
1158 		if (fist_wait &&
1159 		    test_data.buf_len == sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4) {
1160 			PRINT(" mpsc sema wake\n");
1161 			fist_wait = false;
1162 		}
1163 		test_hnd.product_cnt++;
1164 	}
1165 	k_thread_join(tid3, K_FOREVER);
1166 	zassert_equal(test_hnd.product_cnt,
1167 		      test_hnd.consumer_cnt, "product %d consume %d",
1168 		      test_hnd.product_cnt, test_hnd.consumer_cnt);
1169 
1170 }
1171 /* Test creates two threads which pends on the buffer until there is a space
1172  * available. When enough buffers is released threads are woken up and they
1173  * allocate packets.
1174  */
ZTEST(log_buffer,test_pending_alloc)1175 ZTEST(log_buffer, test_pending_alloc)
1176 {
1177 	int prio = k_thread_priority_get(k_current_get());
1178 	struct mpsc_pbuf_buffer buffer;
1179 	void *vt;
1180 
1181 	k_thread_priority_set(k_current_get(), 3);
1182 
1183 	init(&buffer, ARRAY_SIZE(buf32) - 1, true);
1184 
1185 	uint32_t fill_len = 1;
1186 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
1187 
1188 	start_threads(&buffer);
1189 
1190 	k_sleep(K_MSEC(1));
1191 
1192 	for (int i = 0; i < packet_cnt; i++) {
1193 		union test_item *t = (union test_item *)mpsc_pbuf_claim(&buffer);
1194 
1195 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
1196 	}
1197 
1198 
1199 	for (int i = 0; i < 2; i++) {
1200 		struct test_data_ext *t =
1201 			(struct test_data_ext *)mpsc_pbuf_claim(&buffer);
1202 
1203 		zassert_true(t);
1204 		zassert_equal(t->data, tids[ARRAY_SIZE(tids) - 1 - i]);
1205 		vt = t;
1206 		zassert_true(IS_PTR_ALIGNED(vt, union mpsc_pbuf_generic), "unaligned ptr");
1207 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)vt);
1208 	}
1209 
1210 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, "No more packets.");
1211 	k_thread_priority_set(k_current_get(), prio);
1212 }
1213 
check_packet(struct mpsc_pbuf_buffer * buffer,char exp_c)1214 static void check_packet(struct mpsc_pbuf_buffer *buffer, char exp_c)
1215 {
1216 	union test_item claimed_item;
1217 	const union mpsc_pbuf_generic *claimed;
1218 
1219 	claimed = mpsc_pbuf_claim(buffer);
1220 	zassert_true(claimed);
1221 	claimed_item.item = *claimed;
1222 	zassert_equal(claimed_item.data.data, exp_c);
1223 
1224 	mpsc_pbuf_free(buffer, claimed);
1225 }
1226 
ZTEST(log_buffer,test_put_while_claim)1227 ZTEST(log_buffer, test_put_while_claim)
1228 {
1229 	struct mpsc_pbuf_buffer buffer;
1230 	uint32_t buffer_storage[4];
1231 	const union mpsc_pbuf_generic *claimed;
1232 	struct mpsc_pbuf_buffer_config buffer_config = {
1233 		.buf = buffer_storage,
1234 		.size = 4,
1235 		.notify_drop = drop,
1236 		.get_wlen = get_wlen,
1237 		.flags = MPSC_PBUF_SIZE_POW2 | MPSC_PBUF_MODE_OVERWRITE
1238 	};
1239 	union test_item claimed_item;
1240 	union test_item item = {
1241 		.data = {
1242 			.valid = 1,
1243 			.busy = 0,
1244 			.len = 1,
1245 			.data = (uint32_t)'a'
1246 		}
1247 	};
1248 
1249 	exp_drop_cnt = 0;
1250 	drop_cnt = 0;
1251 	mpsc_pbuf_init(&buffer, &buffer_config);
1252 	/* Expect buffer = {} */
1253 
1254 	for (int i = 0; i < buffer.size; ++i) {
1255 		mpsc_pbuf_put_word(&buffer, item.item);
1256 		item.data.data++;
1257 	}
1258 
1259 	/* Expect buffer = {a, b, c, d}. Adding new word will drop 'a'. */
1260 	exp_dropped_data[exp_drop_cnt] = (uint32_t)'a';
1261 	exp_dropped_len[exp_drop_cnt] = 1;
1262 	exp_drop_cnt++;
1263 
1264 	item.data.data = 'e';
1265 	mpsc_pbuf_put_word(&buffer, item.item);
1266 	zassert_equal(drop_cnt, exp_drop_cnt);
1267 	/* Expect buffer = {e, b, c, d} */
1268 
1269 	claimed = mpsc_pbuf_claim(&buffer);
1270 	zassert_true(claimed);
1271 	claimed_item.item = *claimed;
1272 	zassert_equal(claimed_item.data.data, (uint32_t)'b');
1273 
1274 	/* Expect buffer = {e, B, c, d}. Adding new will drop 'c'. */
1275 	exp_dropped_data[exp_drop_cnt] = (int)'c';
1276 	exp_dropped_len[exp_drop_cnt] = 1;
1277 	exp_drop_cnt++;
1278 
1279 	item.data.data = 'f';
1280 	mpsc_pbuf_put_word(&buffer, item.item);
1281 	zassert_equal(drop_cnt, exp_drop_cnt);
1282 	/* Expect buffer = {e, B, f, d}, Adding new will drop 'd'. */
1283 
1284 	exp_dropped_data[exp_drop_cnt] = (int)'d';
1285 	exp_dropped_len[exp_drop_cnt] = 1;
1286 	exp_drop_cnt++;
1287 	item.data.data = 'g';
1288 	mpsc_pbuf_put_word(&buffer, item.item);
1289 	zassert_equal(drop_cnt, exp_drop_cnt);
1290 	/* Expect buffer = {e, B, f, g} */
1291 
1292 	mpsc_pbuf_free(&buffer, claimed);
1293 	/* Expect buffer = {e -, f, g} */
1294 
1295 	check_packet(&buffer, 'e');
1296 	/* Expect buffer = {-, -, f, g} */
1297 
1298 	check_packet(&buffer, 'f');
1299 	/* Expect buffer = {-, -, -, g} */
1300 
1301 	check_packet(&buffer, 'g');
1302 	/* Expect buffer = {-, -, -, -} */
1303 
1304 	claimed = mpsc_pbuf_claim(&buffer);
1305 	zassert_equal(claimed, NULL);
1306 }
1307 
check_usage(struct mpsc_pbuf_buffer * buffer,uint32_t now,int exp_err,uint32_t max,uint32_t line)1308 static void check_usage(struct mpsc_pbuf_buffer *buffer,
1309 			uint32_t now, int exp_err, uint32_t max, uint32_t line)
1310 {
1311 	uint32_t size;
1312 	uint32_t usage;
1313 	int err;
1314 
1315 	mpsc_pbuf_get_utilization(buffer, &size, &usage);
1316 	zassert_equal(size / sizeof(int), buffer->size - 1, "%d: got:%d, exp:%d",
1317 			line, (uint32_t)(size / sizeof(int)), buffer->size - 1);
1318 	zassert_equal(usage, now, "%d: got:%d, exp:%d", line, usage, now);
1319 
1320 	err = mpsc_pbuf_get_max_utilization(buffer, &usage);
1321 	zassert_equal(err, exp_err);
1322 	if (err == 0) {
1323 		zassert_equal(usage, max, "%d: got:%d, exp:%d", line, usage, max);
1324 	}
1325 }
1326 
1327 #define CHECK_USAGE(buffer, now, max) \
1328 	check_usage(buffer, (now) * sizeof(int), 0, (max) * sizeof(int), __LINE__)
1329 
ignore_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)1330 static void ignore_drop(const struct mpsc_pbuf_buffer *buffer,
1331 			const union mpsc_pbuf_generic *item)
1332 {
1333 	ARG_UNUSED(buffer);
1334 	ARG_UNUSED(item);
1335 }
1336 
ZTEST(log_buffer,test_utilization)1337 ZTEST(log_buffer, test_utilization)
1338 {
1339 	struct mpsc_pbuf_buffer buffer;
1340 	struct mpsc_pbuf_buffer_config config = {
1341 		.buf = buf32,
1342 		.size = ARRAY_SIZE(buf32),
1343 		.notify_drop = ignore_drop,
1344 		.get_wlen = get_wlen,
1345 		.flags = 0 /* Utilization not supported. */
1346 	};
1347 
1348 	mpsc_pbuf_init(&buffer, &config);
1349 
1350 	check_usage(&buffer, 0, -ENOTSUP, 0, __LINE__);
1351 
1352 	/* Initialize with max utilization support. */
1353 	config.flags = MPSC_PBUF_MAX_UTILIZATION;
1354 	mpsc_pbuf_init(&buffer, &config);
1355 
1356 	CHECK_USAGE(&buffer, 0, 0);
1357 
1358 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
1359 	union test_item test_ext_item = {
1360 		.data = {
1361 			.valid = 1,
1362 			.len = PUT_EXT_LEN
1363 		}
1364 	};
1365 	union test_item *t;
1366 
1367 	mpsc_pbuf_put_word(&buffer, test_1word.item);
1368 
1369 	CHECK_USAGE(&buffer, 1, 1);
1370 
1371 	mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, NULL);
1372 
1373 	CHECK_USAGE(&buffer, 1 + PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1374 
1375 	t = (union test_item *)mpsc_pbuf_claim(&buffer);
1376 
1377 	zassert_true(t != NULL);
1378 	CHECK_USAGE(&buffer, 1 + PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1379 	mpsc_pbuf_free(&buffer, &t->item);
1380 
1381 	t = (union test_item *)mpsc_pbuf_claim(&buffer);
1382 	zassert_true(t != NULL);
1383 
1384 	CHECK_USAGE(&buffer, PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1385 
1386 	mpsc_pbuf_free(&buffer, &t->item);
1387 
1388 	CHECK_USAGE(&buffer, 0, 1 + PUT_EXT_LEN);
1389 
1390 	union test_item test_ext_item2 = {
1391 		.data_ext = {
1392 			.hdr = {
1393 				.valid = 1,
1394 				.len = PUT_EXT_LEN
1395 			},
1396 			.data = NULL
1397 		}
1398 	};
1399 
1400 	mpsc_pbuf_put_data(&buffer, (uint32_t *)&test_ext_item2, PUT_EXT_LEN);
1401 
1402 	CHECK_USAGE(&buffer, PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1403 
1404 	t = (union test_item *)mpsc_pbuf_claim(&buffer);
1405 	zassert_true(t != NULL);
1406 	mpsc_pbuf_free(&buffer, &t->item);
1407 
1408 	CHECK_USAGE(&buffer, 0, 1 + PUT_EXT_LEN);
1409 
1410 	memset(&buffer, 0, sizeof(buffer));
1411 	/* Initialize to reset indexes. */
1412 	mpsc_pbuf_init(&buffer, &config);
1413 
1414 	struct test_data_var *packet;
1415 	uint32_t len = 5;
1416 	uint32_t i;
1417 
1418 	for (i = 0; i < (buffer.size - 1) / len; i++) {
1419 		packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
1420 		packet->hdr.len = len;
1421 
1422 		mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
1423 		CHECK_USAGE(&buffer, len * (i + 1), len * (i + 1));
1424 	}
1425 
1426 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
1427 
1428 	zassert_true(packet == NULL);
1429 }
1430 
1431 /* Make sure that `mpsc_pbuf_alloc()` works in spinlock-held context when buf is not available */
ZTEST(log_buffer,test_alloc_in_spinlock)1432 ZTEST(log_buffer, test_alloc_in_spinlock)
1433 {
1434 	struct mpsc_pbuf_buffer buffer;
1435 	struct test_data_var *packet;
1436 	struct k_spinlock l = {0};
1437 
1438 	init(&buffer, 32, false);
1439 
1440 	/* Allocate all available buffer */
1441 	packet = (struct test_data_var *)mpsc_pbuf_alloc(
1442 		&buffer, 32, K_MSEC(10));
1443 	zassert_not_null(packet);
1444 
1445 	K_SPINLOCK(&l) {
1446 		/* Try to allocate another buf */
1447 		packet = (struct test_data_var *)mpsc_pbuf_alloc(
1448 			&buffer, 32, K_MSEC(10));
1449 		/* No buf is available this time */
1450 		zassert_is_null(packet);
1451 	}
1452 }
1453 
1454 /*test case main entry*/
1455 ZTEST_SUITE(log_buffer, NULL, NULL, NULL, NULL, NULL);
1456