From b49d7e4fb4175db9db074ac276494e357e7ec4b6 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 7 Sep 2016 17:16:33 -0500 Subject: [PATCH 1/2] Properly handle a thread which terminates itself In Thread::terminate() release the join semaphore before terminating the thread. This allows the join semaphore to be properly signaled in the case where a thread is terminating itself. --- rtos/rtos/Thread.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/rtos/rtos/Thread.cpp b/rtos/rtos/Thread.cpp index cb62d77165c..91e80afe2b5 100644 --- a/rtos/rtos/Thread.cpp +++ b/rtos/rtos/Thread.cpp @@ -101,11 +101,14 @@ osStatus Thread::terminate() { osStatus ret; _mutex.lock(); - ret = osThreadTerminate(_tid); + // Set the Thread's tid to NULL and + // release the semaphore before terminating + // since this thread could be terminating itself + osThreadId local_id = _tid; + _join_sem.release(); _tid = (osThreadId)NULL; - // Wake threads joining the terminated thread - _join_sem.release(); + ret = osThreadTerminate(local_id); _mutex.unlock(); return ret; @@ -116,6 +119,14 @@ osStatus Thread::join() { if (ret < 0) { return osErrorOS; } + + // The semaphore has been released so this thread is being + // terminated or has been terminated. Once the mutex has + // been locked it is ensured that the thread is deleted. + _mutex.lock(); + MBED_ASSERT(NULL == _tid); + _mutex.unlock(); + // Release sem so any other threads joining this thread wake up _join_sem.release(); return osOK; From abbd71da9b5cfd12bad4a8a7050493e53f508054 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 7 Sep 2016 17:33:33 -0500 Subject: [PATCH 2/2] Add test case for thread self termination Test that thread self termination works. --- TESTS/mbedmicro-rtos-mbed/threads/main.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/TESTS/mbedmicro-rtos-mbed/threads/main.cpp b/TESTS/mbedmicro-rtos-mbed/threads/main.cpp index 1fb638b3cd9..cebe9b2f847 100644 --- a/TESTS/mbedmicro-rtos-mbed/threads/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/threads/main.cpp @@ -59,6 +59,12 @@ void increment_with_murder(counter_t* counter) { (*counter)++; } +void self_terminate(Thread *self) { + self->terminate(); + // Code should not get here + TEST_ASSERT(0); +} + // Tests that spawn tasks in different configurations template void test_single_thread() { @@ -97,6 +103,13 @@ void test_serial_threads() { TEST_ASSERT_EQUAL(counter, N); } +void test_self_terminate() { + Thread *thread = new Thread(osPriorityNormal, STACK_SIZE); + thread->start(thread, self_terminate); + thread->join(); + delete thread; +} + utest::v1::status_t test_setup(const size_t number_of_cases) { GREENTEA_SETUP(40, "default_auto"); return verbose_test_setup_handler(number_of_cases); @@ -123,6 +136,8 @@ Case cases[] = { Case("Testing single thread with murder", test_single_thread), Case("Testing parallel threads with murder", test_parallel_threads<3, increment_with_murder>), Case("Testing serial threads with murder", test_serial_threads<10, increment_with_murder>), + + Case("Testing thread self terminate", test_self_terminate), }; Specification specification(test_setup, cases);