Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | /* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include <ztest.h> #include <irq_offload.h> #include <misc/stack.h> #define SLEEP_MS 100 #define NUM_OF_WORK 2 #define TEST_STRING "TEST" static struct k_work work[NUM_OF_WORK]; static struct k_sem sync_sema; #define STACKSIZE 512 K_THREAD_STACK_DEFINE(test_stack, STACKSIZE); __kernel struct k_thread test_thread; static int tcount; static bool thread_flag; static bool stack_flag; /**TESTPOINT: stack analyze*/ static void tdata_dump_callback(const struct k_thread *thread, void *user_data) { stack_analyze("Test", (char *)thread->stack_info.start, thread->stack_info.size); } /*power hook functions*/ int _sys_soc_suspend(s32_t ticks) { static bool test_flag; /* Call k_thread_foreach only once otherwise it will * flood the console with stack dumps. */ if (!test_flag) { k_thread_foreach(tdata_dump_callback, NULL); test_flag = true; } return 0; } void _sys_soc_resume(void) { } /*work handler*/ static void work_handler(struct k_work *w) { k_thread_foreach(tdata_dump_callback, NULL); k_sem_give(&sync_sema); } /*test cases*/ void test_call_stacks_analyze_main(void) { TC_PRINT("from main thread:\n"); k_thread_foreach(tdata_dump_callback, NULL); } void test_call_stacks_analyze_idle(void) { TC_PRINT("from idle thread:\n"); k_sleep(SLEEP_MS); } void test_call_stacks_analyze_workq(void) { TC_PRINT("from workq:\n"); k_sem_init(&sync_sema, 0, NUM_OF_WORK); for (int i = 0; i < NUM_OF_WORK; i++) { k_work_init(&work[i], work_handler); k_work_submit(&work[i]); k_sem_take(&sync_sema, K_FOREVER); } } static void thread_entry(void *p1, void *p2, void *p3) { k_sleep(SLEEP_MS); } static void thread_callback(const struct k_thread *thread, void *user_data) { char *str = (char *)user_data; if (thread == &test_thread) { TC_PRINT("%s: Newly added thread found\n", str); TC_PRINT("%s: tid: %p, prio: %d\n", str, thread, thread->base.prio); thread_flag = true; } if ((char *)thread->stack_info.start == K_THREAD_STACK_BUFFER(test_stack)) { TC_PRINT("%s: Newly added thread stack found\n", str); TC_PRINT("%s: stack:%p, size:%u\n", str, (char *)thread->stack_info.start, thread->stack_info.size); stack_flag = true; } tcount++; } static void test_k_thread_foreach(void) { int count; /* Call k_thread_foreach() and check * thread_callback is getting called. */ k_thread_foreach(thread_callback, TEST_STRING); /* Check thread_count non-zero, thread_flag * and stack_flag are not set. */ zassert_true(tcount && !thread_flag && !stack_flag, "thread_callback() not getting called"); /* Save the initial thread count */ count = tcount; /* Create new thread which should add a new entry to the thread list */ k_tid_t tid = k_thread_create(&test_thread, test_stack, STACKSIZE, (k_thread_entry_t)thread_entry, NULL, NULL, NULL, K_PRIO_PREEMPT(0), 0, 0); k_sleep(1); /* Call k_thread_foreach() and check * thread_callback is getting called for * the newly added thread. */ tcount = 0; k_thread_foreach(thread_callback, TEST_STRING); /* Check thread_count > temp, thread_flag and stack_flag are set */ zassert_true((tcount > count) && thread_flag && stack_flag, "thread_callback() not getting called"); k_thread_abort(tid); } /*TODO: add test case to capture the usage of interrupt call stack*/ void test_main(void) { ztest_test_suite(profiling_api, ztest_unit_test(test_call_stacks_analyze_main), ztest_unit_test(test_call_stacks_analyze_idle), ztest_unit_test(test_call_stacks_analyze_workq), ztest_unit_test(test_k_thread_foreach)); ztest_run_test_suite(profiling_api); } |