1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include "test_mslab.h"
9 
10 #define THREAD_NUM 3
11 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
12 
13 K_MEM_SLAB_DEFINE(mslab1, BLK_SIZE, BLK_NUM, BLK_ALIGN);
14 
15 static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREAD_NUM, STACK_SIZE);
16 static struct k_thread tdata[THREAD_NUM];
17 static struct k_sem sync_sema;
18 static void *block_ok;
19 
20 /*thread entry*/
tmslab_alloc_wait_timeout(void * p1,void * p2,void * p3)21 void tmslab_alloc_wait_timeout(void *p1, void *p2, void *p3)
22 {
23 	void *block;
24 
25 	zassert_true(k_mem_slab_alloc(&mslab1, &block, TIMEOUT) == -EAGAIN,
26 		     NULL);
27 	k_sem_give(&sync_sema);
28 }
29 
tmslab_alloc_wait_ok(void * p1,void * p2,void * p3)30 void tmslab_alloc_wait_ok(void *p1, void *p2, void *p3)
31 {
32 	zassert_true(k_mem_slab_alloc(&mslab1, &block_ok, TIMEOUT) == 0);
33 	k_sem_give(&sync_sema);
34 }
35 
36 /*test cases*/
37 /**
38  * @brief Verify alloc with multiple threads
39  *
40  * @details The test allocates all blocks of memory slab and
41  * then spawns 3 threads with lowest priority and 2 more with
42  * same priority higher than first thread with delay 10ms and
43  * 20ms. Checks the behavior of alloc when requested by multiple
44  * threads
45  *
46  * @ingroup kernel_memory_slab_tests
47  *
48  * @see k_mem_slab_alloc()
49  * @see k_mem_slab_free()
50  */
ZTEST(mslab_concept,test_mslab_alloc_wait_prio)51 ZTEST(mslab_concept, test_mslab_alloc_wait_prio)
52 {
53 	void *block[BLK_NUM];
54 	k_tid_t tid[THREAD_NUM];
55 
56 	k_sem_init(&sync_sema, 0, THREAD_NUM);
57 	/*allocated up all blocks*/
58 	for (int i = 0; i < BLK_NUM; i++) {
59 		zassert_equal(k_mem_slab_alloc(&mslab1, &block[i], K_NO_WAIT),
60 			      0, NULL);
61 	}
62 
63 	/**
64 	 * TESTPOINT: Any number of threads may wait on an empty memory slab
65 	 * simultaneously; when a memory block becomes available, it is given to
66 	 * the highest-priority thread that has waited the longest.
67 	 */
68 	/**
69 	 * TESTPOINT: If all the blocks are currently in use, a thread can
70 	 * optionally wait for one to become available.
71 	 */
72 	/*the low-priority thread*/
73 	tid[0] = k_thread_create(&tdata[0], tstack[0], STACK_SIZE,
74 				 tmslab_alloc_wait_timeout, NULL, NULL, NULL,
75 				 K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
76 	/*the highest-priority thread that has waited the longest*/
77 	tid[1] = k_thread_create(&tdata[1], tstack[1], STACK_SIZE,
78 				 tmslab_alloc_wait_ok, NULL, NULL, NULL,
79 				 K_PRIO_PREEMPT(0), 0, K_MSEC(10));
80 	/*the highest-priority thread that has waited shorter*/
81 	tid[2] = k_thread_create(&tdata[2], tstack[2], STACK_SIZE,
82 				 tmslab_alloc_wait_timeout, NULL, NULL, NULL,
83 				 K_PRIO_PREEMPT(0), 0, K_MSEC(20));
84 	/*relinquish CPU for above threads to start */
85 	k_msleep(30);
86 	/*free one block, expected to unblock thread "tid[1]"*/
87 	k_mem_slab_free(&mslab1, block[0]);
88 	/*wait for all threads exit*/
89 	for (int i = 0; i < THREAD_NUM; i++) {
90 		k_sem_take(&sync_sema, K_FOREVER);
91 	}
92 
93 	/*test case tear down*/
94 	for (int i = 0; i < THREAD_NUM; i++) {
95 		k_thread_abort(tid[i]);
96 	}
97 	k_mem_slab_free(&mslab1, block_ok);
98 	for (int i = 1; i < BLK_NUM; i++) {
99 		k_mem_slab_free(&mslab1, block[i]);
100 	}
101 }
102