|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 Intel Corporation |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/kernel.h> |
| 8 | +#include <zephyr/ztest.h> |
| 9 | +#include <stdio.h> |
| 10 | + |
| 11 | + |
| 12 | +/* COMMON DEFFINITIONS */ |
| 13 | +#define STACK_SIZE 500 |
| 14 | +#define LIST_LEN 8 |
| 15 | + |
| 16 | +static struct k_sem sema; |
| 17 | +static struct k_thread tdata; |
| 18 | + |
| 19 | +static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE); |
| 20 | + |
| 21 | + |
| 22 | +/* FIFO SCENARIO */ |
| 23 | +/* Thread A enters items into a fifo, starts Thread B and waits for a semaphore. */ |
| 24 | +/* Thread B extracts all items from the fifo and enters some items back into the fifo. */ |
| 25 | +/* Thread B gives the semaphore for Thread A to continue. */ |
| 26 | +/* Once the control is returned back to Thread A, it extracts all items from the fifo. */ |
| 27 | +/* Verify the data's correctness. */ |
| 28 | + |
| 29 | +static K_FIFO_DEFINE(fifo); |
| 30 | +struct fifo_item_t { |
| 31 | + void *fifo_reserved; /* 1st word reserved for use by FIFO */ |
| 32 | + uint8_t value; |
| 33 | +}; |
| 34 | +static struct fifo_item_t fifo_data[LIST_LEN]; |
| 35 | + |
| 36 | +static void thread_entry_fn_fifo(void *p1, void *p2, void *p3) |
| 37 | +{ |
| 38 | + struct fifo_item_t *rx_data; |
| 39 | + uint32_t i; |
| 40 | + |
| 41 | + /* Get items from fifo */ |
| 42 | + for (i = 0U; i < LIST_LEN; i++) { |
| 43 | + rx_data = k_fifo_get((struct k_fifo *)p1, K_NO_WAIT); |
| 44 | + zassert_equal(rx_data->value, fifo_data[i].value); |
| 45 | + } |
| 46 | + |
| 47 | + /* Put items into fifo */ |
| 48 | + for (i = 0U; i < LIST_LEN; i++) { |
| 49 | + fifo_data[i].value *= i; |
| 50 | + k_fifo_put((struct k_fifo *)p1, &fifo_data[i]); |
| 51 | + } |
| 52 | + |
| 53 | + /* Give control back to Thread A */ |
| 54 | + k_sem_give(&sema); |
| 55 | +} |
| 56 | + |
| 57 | + |
| 58 | +ZTEST(kernel, test_fifo_usage) |
| 59 | +{ |
| 60 | + struct fifo_item_t *rx_data; |
| 61 | + uint32_t i; |
| 62 | + |
| 63 | + /* Init binary semaphore */ |
| 64 | + k_sem_init(&sema, 0, 1); |
| 65 | + |
| 66 | + /* Set and Put items into fifo */ |
| 67 | + for (i = 0U; i < LIST_LEN; i++) { |
| 68 | + fifo_data[i].value = i; |
| 69 | + k_fifo_put(&fifo, &fifo_data[i]); |
| 70 | + } |
| 71 | + |
| 72 | + /* Create the Thread B */ |
| 73 | + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| 74 | + thread_entry_fn_fifo, &fifo, NULL, NULL, |
| 75 | + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); |
| 76 | + |
| 77 | + /* Let the thread B run */ |
| 78 | + k_sem_take(&sema, K_FOREVER); |
| 79 | + |
| 80 | + /* Get items from fifo */ |
| 81 | + for (i = 0U; i < LIST_LEN; i++) { |
| 82 | + rx_data = k_fifo_get(&fifo, K_NO_WAIT); |
| 83 | + zassert_equal(rx_data->value, fifo_data[i].value); |
| 84 | + } |
| 85 | + |
| 86 | + /* Clear the spawn thread */ |
| 87 | + k_thread_abort(tid); |
| 88 | +} |
| 89 | + |
| 90 | +/* LIFO SCENARIO */ |
| 91 | +/* Thread A enters items into a lifo, starts Thread B and waits for a semaphore. */ |
| 92 | +/* Thread B extracts all items from the lifo and enters some items back into the lifo. */ |
| 93 | +/* Thread B gives the semaphore for Thread A to continue. */ |
| 94 | +/* Once the control is returned back to Thread A, it extracts all items from the lifo. */ |
| 95 | +/* Verify the data's correctness. */ |
| 96 | + |
| 97 | +struct lifo_item_t { |
| 98 | + void *LIFO_reserved; /* 1st word reserved for use by LIFO */ |
| 99 | + uint8_t value; |
| 100 | +}; |
| 101 | +static struct lifo_item_t lifo_data[LIST_LEN]; |
| 102 | +K_LIFO_DEFINE(lifo); |
| 103 | + |
| 104 | + |
| 105 | +static void thread_entry_fn_lifo(void *p1, void *p2, void *p3) |
| 106 | +{ |
| 107 | + struct lifo_item_t *rx_data; |
| 108 | + uint32_t i; |
| 109 | + |
| 110 | + /* Get items from lifo */ |
| 111 | + for (i = 0U; i < LIST_LEN; i++) { |
| 112 | + rx_data = k_lifo_get((struct k_lifo *)p1, K_NO_WAIT); |
| 113 | + zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value); |
| 114 | + } |
| 115 | + |
| 116 | + /* Put items into lifo */ |
| 117 | + for (i = 0U; i < LIST_LEN; i++) { |
| 118 | + lifo_data[i].value *= i; |
| 119 | + k_lifo_put((struct k_lifo *)p1, &lifo_data[i]); |
| 120 | + } |
| 121 | + |
| 122 | + /* Give control back to Thread A */ |
| 123 | + k_sem_give(&sema); |
| 124 | +} |
| 125 | + |
| 126 | +ZTEST(kernel, test_lifo_usage) |
| 127 | +{ |
| 128 | + struct lifo_item_t *rx_data; |
| 129 | + uint32_t i; |
| 130 | + |
| 131 | + /* Init binary semaphore */ |
| 132 | + k_sem_init(&sema, 0, 1); |
| 133 | + |
| 134 | + /* Set and Put items into lifo */ |
| 135 | + for (i = 0U; i < LIST_LEN; i++) { |
| 136 | + lifo_data[i].value = i; |
| 137 | + k_lifo_put(&lifo, &lifo_data[i]); |
| 138 | + } |
| 139 | + |
| 140 | + /* Create the Thread B */ |
| 141 | + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| 142 | + thread_entry_fn_lifo, &lifo, NULL, NULL, |
| 143 | + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); |
| 144 | + |
| 145 | + /* Let the thread B run */ |
| 146 | + k_sem_take(&sema, K_FOREVER); |
| 147 | + |
| 148 | + /* Get items from lifo */ |
| 149 | + for (i = 0U; i < LIST_LEN; i++) { |
| 150 | + rx_data = k_lifo_get(&lifo, K_NO_WAIT); |
| 151 | + zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value); |
| 152 | + } |
| 153 | + |
| 154 | + /* Clear the spawn thread */ |
| 155 | + k_thread_abort(tid); |
| 156 | + |
| 157 | +} |
| 158 | + |
| 159 | +/* STACK SCENARIO */ |
| 160 | +/* Thread A enters items into a stack, starts thread B and waits for a semaphore. */ |
| 161 | +/* Thread B extracts all items from the stack and enters some items back into the stack. */ |
| 162 | +/* Thread B gives the semaphore for Thread A to continue. */ |
| 163 | +/* Once the control is returned back to Thread A, it extracts all items from the stack. */ |
| 164 | +/* Verify the data's correctness. */ |
| 165 | + |
| 166 | + |
| 167 | +#define STACK_LEN 8 |
| 168 | +#define MAX_ITEMS 8 |
| 169 | + |
| 170 | +K_STACK_DEFINE(stack, STACK_LEN); |
| 171 | +stack_data_t stack_data[MAX_ITEMS]; |
| 172 | + |
| 173 | + |
| 174 | +static void thread_entry_fn_stack(void *p1, void *p2, void *p3) |
| 175 | +{ |
| 176 | + stack_data_t *rx_data; |
| 177 | + stack_data_t data[MAX_ITEMS]; |
| 178 | + |
| 179 | + /* fill data to compare */ |
| 180 | + for (int i = 0; i < STACK_LEN; i++) { |
| 181 | + data[i] = i; |
| 182 | + } |
| 183 | + |
| 184 | + /* read data from a stack */ |
| 185 | + for (int i = 0; i < STACK_LEN; i++) { |
| 186 | + k_stack_pop((struct k_stack *)p1, (stack_data_t *)&rx_data, K_NO_WAIT); |
| 187 | + } |
| 188 | + |
| 189 | + zassert_false(memcmp(rx_data, data, STACK_LEN), |
| 190 | + "Push & Pop items does not match"); |
| 191 | + |
| 192 | + /* Push data into a stack */ |
| 193 | + for (int i = 0; i < STACK_LEN; i++) { |
| 194 | + stack_data[i] *= i; |
| 195 | + k_stack_push((struct k_stack *)p1, (stack_data_t)&stack_data[i]); |
| 196 | + } |
| 197 | + |
| 198 | + /* Give control back to Thread A */ |
| 199 | + k_sem_give(&sema); |
| 200 | +} |
| 201 | + |
| 202 | + |
| 203 | +ZTEST(kernel, test_stack_usage) |
| 204 | +{ |
| 205 | + stack_data_t *rx_data; |
| 206 | + |
| 207 | + /* Init binary semaphore */ |
| 208 | + k_sem_init(&sema, 0, 1); |
| 209 | + |
| 210 | + /* Push data into a stack */ |
| 211 | + for (int i = 0; i < STACK_LEN; i++) { |
| 212 | + stack_data[i] = i; |
| 213 | + k_stack_push(&stack, (stack_data_t)&stack_data[i]); |
| 214 | + } |
| 215 | + |
| 216 | + /* Create the Thread B */ |
| 217 | + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| 218 | + thread_entry_fn_stack, &stack, NULL, NULL, |
| 219 | + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); |
| 220 | + |
| 221 | + /* Let the thread B run */ |
| 222 | + k_sem_take(&sema, K_FOREVER); |
| 223 | + |
| 224 | + /* read data from a stack */ |
| 225 | + for (int i = 0; i < STACK_LEN; i++) { |
| 226 | + k_stack_pop(&stack, (stack_data_t *)&rx_data, K_NO_WAIT); |
| 227 | + } |
| 228 | + |
| 229 | + |
| 230 | + /* Verify the correctness */ |
| 231 | + zassert_false(memcmp(rx_data, stack_data, STACK_LEN), |
| 232 | + "Push & Pop items does not match"); |
| 233 | + |
| 234 | + /* Clear the spawn thread */ |
| 235 | + k_thread_abort(tid); |
| 236 | +} |
| 237 | + |
| 238 | +/* MUTEX SCENARIO */ |
| 239 | +/* Initialize the mutex. */ |
| 240 | +/* Start the two Threads with the entry points. */ |
| 241 | +/* The entry points change variable and use lock and unlock mutex functions to */ |
| 242 | +/* synchronize the access to that variable. */ |
| 243 | +/* Join all threads. */ |
| 244 | +/* Verify the variable. */ |
| 245 | + |
| 246 | +#define NUMBER_OF_ITERATIONS 10000 |
| 247 | + |
| 248 | +static uint32_t mutex_data; |
| 249 | +static struct k_thread tdata_2; |
| 250 | +static K_THREAD_STACK_DEFINE(tstack_2, STACK_SIZE); |
| 251 | + |
| 252 | +K_MUTEX_DEFINE(mutex); |
| 253 | + |
| 254 | +static void thread_entry_fn_mutex(void *p1, void *p2, void *p3) |
| 255 | +{ |
| 256 | + uint32_t i; |
| 257 | + |
| 258 | + for (i = 0; i < NUMBER_OF_ITERATIONS; i++) { |
| 259 | + k_mutex_lock((struct k_mutex *)p1, K_FOREVER); |
| 260 | + mutex_data += 1; |
| 261 | + k_mutex_unlock((struct k_mutex *)p1); |
| 262 | + } |
| 263 | +} |
| 264 | + |
| 265 | +static void thread_entry_fn_mutex_2(void *p1, void *p2, void *p3) |
| 266 | +{ |
| 267 | + uint32_t i; |
| 268 | + |
| 269 | + for (i = 0; i < NUMBER_OF_ITERATIONS*2; i++) { |
| 270 | + k_mutex_lock((struct k_mutex *)p1, K_FOREVER); |
| 271 | + mutex_data -= 1; |
| 272 | + k_mutex_unlock((struct k_mutex *)p1); |
| 273 | + } |
| 274 | +} |
| 275 | + |
| 276 | +ZTEST(kernel, test_mutex_usage) |
| 277 | +{ |
| 278 | + |
| 279 | + /* Create the Thread A */ |
| 280 | + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| 281 | + thread_entry_fn_mutex, &mutex, &mutex_data, NULL, |
| 282 | + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER); |
| 283 | + |
| 284 | + /* Create the Thread B */ |
| 285 | + k_tid_t tid2 = k_thread_create(&tdata_2, tstack_2, STACK_SIZE, |
| 286 | + thread_entry_fn_mutex_2, &mutex, &mutex_data, NULL, |
| 287 | + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER); |
| 288 | + |
| 289 | + /* Start the Thread A */ |
| 290 | + k_thread_start(tid); |
| 291 | + /* Start the Thread B */ |
| 292 | + k_thread_start(tid2); |
| 293 | + /* Wait for end of Thread A */ |
| 294 | + k_thread_join(&tdata, K_FOREVER); |
| 295 | + /* Wait for end of Thread B */ |
| 296 | + k_thread_join(&tdata_2, K_FOREVER); |
| 297 | + /* Verify data after the end of the threads */ |
| 298 | + zassert_equal(mutex_data, -10000); |
| 299 | + |
| 300 | + /* Clear the spawn threads */ |
| 301 | + k_thread_abort(tid); |
| 302 | + k_thread_abort(tid2); |
| 303 | +} |
| 304 | + |
| 305 | + |
| 306 | +ZTEST_SUITE(kernel, NULL, NULL, |
| 307 | + ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL); |
0 commit comments