1 /*
2  * Copyright (c) 2016, 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include "test_mheap.h"
9 
10 #define THREADSAFE_THREAD_NUM 3
11 #define THREADSAFE_BLOCK_SIZE 16
12 #define THREADSAFE_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
13 #define MALLOC_ALIGN4_STACK_SIZE (512 + (BLK_NUM_MAX * sizeof(void *)))
14 
15 struct k_sem threadsafe_sema;
16 static K_THREAD_STACK_ARRAY_DEFINE(threadsafe_tstack, THREADSAFE_THREAD_NUM, THREADSAFE_STACK_SIZE);
17 static struct k_thread threadsafe_tdata[THREADSAFE_THREAD_NUM];
18 
19 static void *threadsafe_pool_blocks[BLK_NUM_MAX];
20 
21 static K_THREAD_STACK_DEFINE(malloc_align4_tstack, MALLOC_ALIGN4_STACK_SIZE);
22 static struct k_thread malloc_align4_tdata;
23 
24 /*test cases*/
25 
tmheap_malloc_align4_handler(void * p1,void * p2,void * p3)26 static void tmheap_malloc_align4_handler(void *p1, void *p2, void *p3)
27 {
28 	void *block[BLK_NUM_MAX];
29 	int i;
30 
31 	/**
32 	 * TESTPOINT: The address of the allocated chunk is guaranteed to be
33 	 * aligned on a word boundary (4 or 8 bytes).
34 	 */
35 	for (i = 0; i < BLK_NUM_MAX; i++) {
36 		block[i] = k_malloc(i);
37 		if (block[i] == NULL) {
38 			break;
39 		}
40 		zassert_false((uintptr_t)block[i] % sizeof(void *));
41 	}
42 
43 	/* test case tear down*/
44 	for (int j = 0; j < i; j++) {
45 		k_free(block[j]);
46 	}
47 }
48 
49 /**
50  * @brief The test validates k_calloc() API.
51  *
52  * @ingroup kernel_heap_tests
53  *
54  * @details The 8 blocks of memory of size 16 bytes are allocated
55  * by k_calloc() API. When allocated using k_calloc() the memory buffers
56  * have to be zeroed. Check is done, if the blocks are memset to 0 and
57  * read/write is allowed. The test is then teared up by freeing all the
58  * blocks allocated.
59  *
60  * @see k_malloc(), k_free()
61  */
ZTEST(mheap_api,test_mheap_malloc_align4)62 ZTEST(mheap_api, test_mheap_malloc_align4)
63 {
64 	if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
65 		return;
66 	}
67 
68 	k_tid_t tid = k_thread_create(&malloc_align4_tdata, malloc_align4_tstack,
69 				 MALLOC_ALIGN4_STACK_SIZE,
70 				 tmheap_malloc_align4_handler,
71 				 NULL, NULL, NULL,
72 				 K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
73 
74 	k_thread_join(tid, K_FOREVER);
75 }
76 
tmheap_threadsafe_handler(void * p1,void * p2,void * p3)77 static void tmheap_threadsafe_handler(void *p1, void *p2, void *p3)
78 {
79 	int thread_id = POINTER_TO_INT(p1);
80 
81 	threadsafe_pool_blocks[thread_id] = k_malloc(THREADSAFE_BLOCK_SIZE);
82 
83 	zassert_not_null(threadsafe_pool_blocks[thread_id], "memory is not allocated");
84 
85 	k_sem_give(&threadsafe_sema);
86 }
87 
88 /**
89  * @brief Verify alloc from multiple equal priority threads
90  *
91  * @details Test creates three preemptive threads of equal priority.
92  * In each child thread , call k_malloc() to alloc a block of memory.
93  * Check These four threads can share the same heap space without
94  * interfering with each other.
95  *
96  * @ingroup kernel_memory_slab_tests
97  */
ZTEST(mheap_api,test_mheap_threadsafe)98 ZTEST(mheap_api, test_mheap_threadsafe)
99 {
100 	if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
101 		return;
102 	}
103 
104 	k_tid_t tid[THREADSAFE_THREAD_NUM];
105 
106 	k_sem_init(&threadsafe_sema, 0, THREADSAFE_THREAD_NUM);
107 
108 	/* create multiple threads to invoke same memory heap APIs*/
109 	for (int i = 0; i < THREADSAFE_THREAD_NUM; i++) {
110 		tid[i] = k_thread_create(&threadsafe_tdata[i], threadsafe_tstack[i],
111 					 THREADSAFE_STACK_SIZE, tmheap_threadsafe_handler,
112 					 INT_TO_POINTER(i), NULL, NULL,
113 					 K_PRIO_PREEMPT(1), 0, K_NO_WAIT);
114 	}
115 
116 	for (int i = 0; i < THREADSAFE_THREAD_NUM; i++) {
117 		k_sem_take(&threadsafe_sema, K_FOREVER);
118 	}
119 
120 	for (int i = 0; i < THREADSAFE_THREAD_NUM; i++) {
121 		/* verify free mheap in main thread */
122 		k_free(threadsafe_pool_blocks[i]);
123 		k_thread_abort(tid[i]);
124 	}
125 }
126