diff --git a/tests/thread_zombie/Makefile b/tests/thread_zombie/Makefile new file mode 100644 index 0000000000..c798269d73 --- /dev/null +++ b/tests/thread_zombie/Makefile @@ -0,0 +1,7 @@ +include ../Makefile.tests_common + +DISABLE_MODULE += auto_init +# For better testing use ps +#USEMODULE += ps + +include $(RIOTBASE)/Makefile.include diff --git a/tests/thread_zombie/Makefile.ci b/tests/thread_zombie/Makefile.ci new file mode 100644 index 0000000000..af61efb31c --- /dev/null +++ b/tests/thread_zombie/Makefile.ci @@ -0,0 +1,9 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-nano \ + arduino-uno \ + atmega328p \ + nucleo-f031k6 \ + stm32f030f4-demo + # diff --git a/tests/thread_zombie/main.c b/tests/thread_zombie/main.c new file mode 100644 index 0000000000..b92dd88853 --- /dev/null +++ b/tests/thread_zombie/main.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin, + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Thread test application + * + * + * @author Julian Holzwarth + * + */ + +#include +#include "thread.h" +#include "test_utils/interactive_sync.h" +#ifdef MODULE_PS +#include "ps.h" +#endif /* MODULE_PS */ + +#define TEST_THREAD_STACKSIZE ((2 * THREAD_STACKSIZE_IDLE) + \ + THREAD_EXTRA_STACKSIZE_PRINTF) + +/* stacks for testing threads */ +static char t2_stack[TEST_THREAD_STACKSIZE]; +static char t3_stack[TEST_THREAD_STACKSIZE]; +static char t4_stack[TEST_THREAD_STACKSIZE]; + +/* function for testing threads */ +void *second_thread(void *arg) +{ + printf("Thread: %d is starting\n", (int)arg); + printf("Thread: %d calls zombify\n", (int)arg); + thread_zombify(); + puts("ERROR zombie runs again!"); + return NULL; +} + +int main(void) +{ + test_utils_interactive_sync(); + + /* save thread count on test start */ + int current_thread_count; + int start_thread_count = sched_num_threads; + + printf("Number of threads before the test = %d\n", start_thread_count); + + /* creating threads for testing */ + puts("Creating first thread (sleeping)"); + kernel_pid_t first_pid = thread_create( + t2_stack, sizeof(t2_stack), + THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_SLEEPING | THREAD_CREATE_STACKTEST, + second_thread, (void *)1, "nr1"); + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + puts("Creating second thread (sleeping)"); + kernel_pid_t second_pid = thread_create( + t3_stack, sizeof(t3_stack), + THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_SLEEPING | THREAD_CREATE_STACKTEST, + second_thread, (void *)2, "nr2"); + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + puts("Creating third thread (sleeping)"); + kernel_pid_t third_pid = thread_create( + t4_stack, sizeof(t4_stack), + THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_SLEEPING | THREAD_CREATE_STACKTEST, + second_thread, (void *)3, "nr3"); + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + current_thread_count = sched_num_threads; + printf("Current number of threads = %d\n", current_thread_count); + + /* check if all threads got created */ + if (start_thread_count + 3 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + + /* wakeup first thread and check if the thread zombified itself */ + puts("Waking up first thread"); + thread_wakeup(first_pid); + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + current_thread_count = sched_num_threads; + printf("Current number of threads = %d\n", current_thread_count); + if (thread_getstatus(first_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: first thread is not a zombie!"); + } + else { + if (start_thread_count + 3 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + } + + /* wakeup second thread and check if the thread zombified itself */ + puts("Waking up second thread"); + thread_wakeup(second_pid); + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + current_thread_count = sched_num_threads; + printf("Current number of threads = %d\n", current_thread_count); + + if (thread_getstatus(first_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: first thread is not a zombie!"); + } + else { + if (thread_getstatus(second_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: second thread is not a zombie!"); + } + else { + if (start_thread_count + 3 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + + } + } + + /* kill first zombie thread and check if the thread still exist (it should not) */ + puts("Kill first thread"); + + if (thread_kill_zombie(first_pid) != 1) { + puts("Error thread_kill_zombie returned an error"); + } + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + current_thread_count = sched_num_threads; + printf("Current number of threads = %d\n", current_thread_count); + + if (thread_getstatus(first_pid) != STATUS_NOT_FOUND) { + puts("Error first Thread does still exist"); + } + else { + if (thread_getstatus(second_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: second thread is not a zombie!"); + } + else { + if (start_thread_count + 2 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + } + } + + /* wakeup third thread and check if the thread zombified itself */ + puts("Waking up third thread"); + thread_wakeup(third_pid); + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + if (thread_getstatus(first_pid) != STATUS_NOT_FOUND) { + puts("Error first Thread does still exist"); + } + else { + if (thread_getstatus(second_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: third thread is not a zombie!"); + } + else { + if (thread_getstatus(third_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: second thread is not a zombie!"); + } + else { + if (start_thread_count + 2 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + } + } + } + + /* check if threads are created normally after killing a zombie */ + puts("Creating fourth thread (sleeping)"); + kernel_pid_t last_pid = thread_create( + t2_stack, sizeof(t2_stack), + THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_SLEEPING | THREAD_CREATE_STACKTEST, + second_thread, (void *)4, "nr4"); + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + if (thread_getstatus(last_pid) != STATUS_SLEEPING) { + puts("Error last Thread is not sleeping"); + } + else { + if (last_pid != first_pid) { + puts("Error thread did not reuse first thread pid"); + } + else { + if (thread_getstatus(second_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: third thread is not a zombie!"); + } + else { + if (thread_getstatus(third_pid) != STATUS_ZOMBIE) { + puts("Error Wrong Status: second thread is not a zombie!"); + } + else { + if (start_thread_count + 2 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + } + } + } + } + + #ifdef MODULE_PS + ps(); + puts(""); + #endif /* MODULE_PS */ + + current_thread_count = sched_num_threads; + printf("Current number of threads = %d\n", current_thread_count); + + /* check if all threads got created */ + if (start_thread_count + 3 != current_thread_count) { + puts("Error wrong thread count"); + } + else { + puts("OK"); + } + + return 0; +} diff --git a/tests/thread_zombie/tests/01-run.py b/tests/thread_zombie/tests/01-run.py new file mode 100755 index 0000000000..6347ec5d85 --- /dev/null +++ b/tests/thread_zombie/tests/01-run.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2019 Freie Universität Berlin, +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect("OK") + child.expect("OK") + child.expect("OK") + child.expect("OK") + child.expect("OK") + child.expect("OK") + child.expect("OK") + + +if __name__ == "__main__": + sys.exit(run(testfunc))