|
19 | 19 | */ |
20 | 20 |
|
21 | 21 | #include <stdio.h> |
22 | | -#include <stdlib.h> |
23 | 22 | #include "shell.h" |
24 | 23 | #include "xtimer.h" |
| 24 | +#include "thread.h" |
| 25 | +#include "msg.h" |
| 26 | +#include "irq.h" |
25 | 27 |
|
26 | 28 | /* timeout at one millisecond (1000 us) to make sure it does not spin. */ |
27 | 29 | #define LONG_MUTEX_TIMEOUT 1000 |
28 | 30 |
|
| 31 | +/* main Thread PID */ |
| 32 | +static kernel_pid_t main_thread_pid; |
| 33 | + |
29 | 34 | /** |
30 | 35 | * Foward declarations |
31 | 36 | */ |
32 | 37 | static int cmd_test_xtimer_mutex_lock_timeout_long_unlocked(int argc, |
33 | 38 | char **argv); |
34 | 39 | static int cmd_test_xtimer_mutex_lock_timeout_long_locked(int argc, |
35 | 40 | char **argv); |
| 41 | +static int cmd_test_xtimer_mutex_lock_timeout_low_prio_thread(int argc, |
| 42 | + char **argv); |
36 | 43 |
|
37 | 44 | /** |
38 | 45 | * @brief List of command for this application. |
39 | 46 | */ |
40 | 47 | static const shell_command_t shell_commands[] = { |
41 | | - { "mutex_timeout_long_unlocked", "unlocked mutex with long timeout", |
| 48 | + { "mutex_timeout_long_unlocked", "unlocked mutex (no-spin timeout)", |
42 | 49 | cmd_test_xtimer_mutex_lock_timeout_long_unlocked, }, |
43 | | - { "mutex_timeout_long_locked", "locked mutex with long timeout", |
| 50 | + { "mutex_timeout_long_locked", "locked mutex (no-spin timeout)", |
44 | 51 | cmd_test_xtimer_mutex_lock_timeout_long_locked, }, |
| 52 | + { "mutex_timeout_long_locked_low", |
| 53 | + "lock low-prio-locked-mutex from high-prio-thread (no-spin timeout)", |
| 54 | + cmd_test_xtimer_mutex_lock_timeout_low_prio_thread, }, |
45 | 55 | { NULL, NULL, NULL } |
46 | 56 | }; |
47 | 57 |
|
| 58 | +/** |
| 59 | + * @brief stack for |
| 60 | + * cmd_test_xtimer_mutex_lock_timeout_low_prio_thread |
| 61 | + * not enough stack for doing printf only use puts |
| 62 | + */ |
| 63 | +static char t_stack[THREAD_STACKSIZE_DEFAULT]; |
| 64 | + |
| 65 | +/** |
| 66 | + * @brief send message and suicide thread |
| 67 | + * |
| 68 | + * This function will send a message to a thread without yielding |
| 69 | + * and terminates the calling thread. This can be used to wakeup a |
| 70 | + * thread and terminating yourself. |
| 71 | + * This function calls sched_task_exit() |
| 72 | + * |
| 73 | + * @param[in] m Pointer to preallocated @ref msg_t structure, must |
| 74 | + * not be NULL. |
| 75 | + * @param[in] target_pid PID of target thread |
| 76 | + * |
| 77 | + */ |
| 78 | +static NORETURN void msg_send_sched_task_exit(msg_t *m, kernel_pid_t target_pid) |
| 79 | +{ |
| 80 | + (void)irq_disable(); |
| 81 | + msg_send_int(m, target_pid); |
| 82 | + sched_task_exit(); |
| 83 | +} |
| 84 | + |
| 85 | +/** |
| 86 | + * @brief thread function for |
| 87 | + * cmd_test_xtimer_mutex_lock_timeout_low_prio_thread |
| 88 | + */ |
| 89 | +void *thread_low_prio_test(void *arg) |
| 90 | +{ |
| 91 | + mutex_t *test_mutex = (mutex_t *)arg; |
| 92 | + msg_t msg; |
| 93 | + |
| 94 | + puts("THREAD low prio: start"); |
| 95 | + |
| 96 | + mutex_lock(test_mutex); |
| 97 | + thread_wakeup(main_thread_pid); |
| 98 | + |
| 99 | + mutex_unlock(test_mutex); |
| 100 | + |
| 101 | + puts("THREAD low prio: exiting low"); |
| 102 | + msg_send_sched_task_exit(&msg, main_thread_pid); |
| 103 | +} |
| 104 | + |
48 | 105 | /** |
49 | 106 | * @brief shell command to test xtimer_mutex_lock_timeout |
50 | 107 | * |
@@ -77,6 +134,8 @@ static int cmd_test_xtimer_mutex_lock_timeout_long_unlocked(int argc, |
77 | 134 | else { |
78 | 135 | puts("error: mutex timed out"); |
79 | 136 | } |
| 137 | + /* to make the test easier to read */ |
| 138 | + printf("\n"); |
80 | 139 |
|
81 | 140 | return 0; |
82 | 141 | } |
@@ -114,6 +173,76 @@ static int cmd_test_xtimer_mutex_lock_timeout_long_locked(int argc, |
114 | 173 | puts("error mutex not locked"); |
115 | 174 | } |
116 | 175 | } |
| 176 | + /* to make the test easier to read */ |
| 177 | + printf("\n"); |
| 178 | + |
| 179 | + return 0; |
| 180 | +} |
| 181 | + |
| 182 | +/** |
| 183 | + * @brief shell command to test xtimer_mutex_lock_timeout |
| 184 | + * |
| 185 | + * This function will create a new thread with lower prio |
| 186 | + * than the main thread (this function should be called from |
| 187 | + * the main thread). The new thread will get a mutex and will |
| 188 | + * lock it. This function (main thread) calls xtimer_mutex_lock_timeout. |
| 189 | + * The other thread will then unlock the mutex. The main |
| 190 | + * thread gets the mutex and wakes up. The timer will not |
| 191 | + * trigger because the main threads gets the mutex. |
| 192 | + * |
| 193 | + * @param[in] argc Number of arguments |
| 194 | + * @param[in] argv Array of arguments |
| 195 | + * |
| 196 | + * @return 0 always |
| 197 | + */ |
| 198 | +static int cmd_test_xtimer_mutex_lock_timeout_low_prio_thread(int argc, |
| 199 | + char **argv) |
| 200 | +{ |
| 201 | + (void)argc; |
| 202 | + (void)argv; |
| 203 | + puts("starting test: xtimer mutex lock timeout with thread"); |
| 204 | + mutex_t test_mutex = MUTEX_INIT; |
| 205 | + main_thread_pid = thread_getpid(); |
| 206 | + int current_thread_count = sched_num_threads; |
| 207 | + printf("threads = %d\n", current_thread_count); |
| 208 | + kernel_pid_t test_thread = thread_create(t_stack, sizeof(t_stack), |
| 209 | + THREAD_PRIORITY_MAIN + 1, |
| 210 | + THREAD_CREATE_STACKTEST, |
| 211 | + thread_low_prio_test, |
| 212 | + (void *)&test_mutex, |
| 213 | + "thread_low_prio_test"); |
| 214 | + (void)test_thread; |
| 215 | + |
| 216 | + thread_sleep(); |
| 217 | + |
| 218 | + puts("MAIN THREAD: calling xtimer_mutex_lock_timeout"); |
| 219 | + |
| 220 | + if (xtimer_mutex_lock_timeout(&test_mutex, LONG_MUTEX_TIMEOUT) == 0) { |
| 221 | + /* mutex has to be locked */ |
| 222 | + if (mutex_trylock(&test_mutex) == 0) { |
| 223 | + puts("OK"); |
| 224 | + } |
| 225 | + else { |
| 226 | + puts("error mutex not locked"); |
| 227 | + } |
| 228 | + } |
| 229 | + else { |
| 230 | + puts("error: mutex timed out"); |
| 231 | + } |
| 232 | + |
| 233 | + current_thread_count = sched_num_threads; |
| 234 | + printf("threads = %d\n", current_thread_count); |
| 235 | + |
| 236 | + /* to end the created thread */ |
| 237 | + msg_t msg; |
| 238 | + puts("MAIN THREAD: waiting for created thread to end"); |
| 239 | + msg_receive(&msg); |
| 240 | + |
| 241 | + current_thread_count = sched_num_threads; |
| 242 | + printf("threads = %d\n", current_thread_count); |
| 243 | + |
| 244 | + /* to make the test easier to read */ |
| 245 | + printf("\n"); |
117 | 246 |
|
118 | 247 | return 0; |
119 | 248 | } |
|
0 commit comments