diff --git a/bsp/apm32/apm32f030r8-miniboard/rtconfig.py b/bsp/apm32/apm32f030r8-miniboard/rtconfig.py index 2fd6753c9bf..eca7e715d39 100644 --- a/bsp/apm32/apm32f030r8-miniboard/rtconfig.py +++ b/bsp/apm32/apm32f030r8-miniboard/rtconfig.py @@ -28,7 +28,7 @@ if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'debug' +BUILD = 'release' if PLATFORM == 'gcc': # toolchains diff --git a/bsp/apm32/apm32f051r8-evalboard/rtconfig.py b/bsp/apm32/apm32f051r8-evalboard/rtconfig.py index 2fd6753c9bf..eca7e715d39 100644 --- a/bsp/apm32/apm32f051r8-evalboard/rtconfig.py +++ b/bsp/apm32/apm32f051r8-evalboard/rtconfig.py @@ -28,7 +28,7 @@ if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'debug' +BUILD = 'release' if PLATFORM == 'gcc': # toolchains diff --git a/examples/utest/testcases/kernel/mutex_tc.c b/examples/utest/testcases/kernel/mutex_tc.c index d5ec9095e4f..00fbec68fda 100644 --- a/examples/utest/testcases/kernel/mutex_tc.c +++ b/examples/utest/testcases/kernel/mutex_tc.c @@ -26,6 +26,8 @@ static struct rt_mutex static_mutex; static rt_mutex_t dynamic_mutex; #endif /* RT_USING_HEAP */ +static volatile int _sync_flag; + /* init test */ static void test_static_mutex_init(void) { @@ -72,11 +74,15 @@ static void static_mutex_take_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } + static void test_static_mutex_take(void) { rt_err_t result; + _sync_flag = 0; + result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO); if (RT_EOK != result) { @@ -104,8 +110,10 @@ static void test_static_mutex_take(void) /* startup thread take second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_detach(&static_mutex); if (RT_EOK != result) @@ -128,11 +136,14 @@ static void static_mutex_release_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } static void test_static_mutex_release(void) { rt_err_t result; + _sync_flag = 0; + result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO); if (RT_EOK != result) { @@ -140,6 +151,9 @@ static void test_static_mutex_release(void) return; } + result = rt_mutex_release(&static_mutex); + uassert_true(result < 0); + /* take mutex */ result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER); if (RT_EOK != result) @@ -165,8 +179,10 @@ static void test_static_mutex_release(void) /* startup thread and take mutex second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_detach(&static_mutex); if (RT_EOK != result) @@ -188,11 +204,14 @@ static void static_mutex_trytake_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } static void test_static_mutex_trytake(void) { rt_err_t result; + _sync_flag = 0; + result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO); if (RT_EOK != result) { @@ -220,8 +239,10 @@ static void test_static_mutex_trytake(void) /* startup thread and trytake mutex second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_detach(&static_mutex); if (RT_EOK != result) @@ -250,6 +271,7 @@ static void static_thread1_entry(void *param) { uassert_true(RT_TRUE); } + _sync_flag++; } static void static_thread2_entry(void *param) @@ -265,6 +287,7 @@ static void static_thread2_entry(void *param) { rt_mutex_release(mutex); } + _sync_flag++; } static void static_thread3_entry(void *param) { @@ -282,6 +305,7 @@ static void static_thread3_entry(void *param) while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2)); rt_mutex_release(mutex); + _sync_flag++; } static void test_static_pri_reverse(void) @@ -291,6 +315,8 @@ static void test_static_pri_reverse(void) tid2 = RT_NULL; tid3 = RT_NULL; + _sync_flag = 0; + result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO); if (RT_EOK != result) { @@ -328,7 +354,10 @@ static void test_static_pri_reverse(void) if (tid3 != RT_NULL) rt_thread_startup(tid3); - rt_thread_mdelay(1000); + while (_sync_flag != 3) + { + rt_thread_mdelay(10); + } result = rt_mutex_detach(&static_mutex); if (RT_EOK != result) @@ -385,11 +414,15 @@ static void dynamic_mutex_take_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } + static void test_dynamic_mutex_take(void) { rt_err_t result; + _sync_flag = 0; + dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_mutex) { @@ -417,8 +450,10 @@ static void test_dynamic_mutex_take(void) /* startup thread take second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_delete(dynamic_mutex); if (RT_EOK != result) @@ -441,11 +476,13 @@ static void dynamic_mutex_release_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } static void test_dynamic_mutex_release(void) { rt_err_t result; + _sync_flag = 0; dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_mutex) { @@ -453,6 +490,9 @@ static void test_dynamic_mutex_release(void) return; } + result = rt_mutex_release(dynamic_mutex); + uassert_true(result < 0); + /* take mutex */ result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER); if (RT_EOK != result) @@ -478,8 +518,10 @@ static void test_dynamic_mutex_release(void) /* startup thread and take mutex second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_delete(dynamic_mutex); if (RT_EOK != result) @@ -501,11 +543,13 @@ static void dynamic_mutex_trytake_entry(void *param) { uassert_true(RT_FALSE); } + _sync_flag++; } static void test_dynamic_mutex_trytake(void) { rt_err_t result; + _sync_flag = 0; dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_mutex) { @@ -533,8 +577,10 @@ static void test_dynamic_mutex_trytake(void) /* startup thread and trytake mutex second */ rt_thread_startup(tid); - /* let system schedule */ - rt_thread_mdelay(5); + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } result = rt_mutex_delete(dynamic_mutex); if (RT_EOK != result) @@ -559,6 +605,7 @@ static void dynamic_thread1_entry(void *param) { uassert_true(RT_TRUE); } + _sync_flag++; } static void dynamic_thread2_entry(void *param) @@ -574,6 +621,7 @@ static void dynamic_thread2_entry(void *param) { rt_mutex_release(mutex); } + _sync_flag++; } static void dynamic_thread3_entry(void *param) { @@ -591,6 +639,7 @@ static void dynamic_thread3_entry(void *param) while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2)); rt_mutex_release(mutex); + _sync_flag++; } static void test_dynamic_pri_reverse(void) @@ -600,6 +649,7 @@ static void test_dynamic_pri_reverse(void) tid2 = RT_NULL; tid3 = RT_NULL; + _sync_flag = 0; dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_mutex) { @@ -637,7 +687,10 @@ static void test_dynamic_pri_reverse(void) if (tid3 != RT_NULL) rt_thread_startup(tid3); - rt_thread_mdelay(1000); + while (_sync_flag != 3) + { + rt_thread_mdelay(10); + } result = rt_mutex_delete(dynamic_mutex); if (RT_EOK != result) @@ -646,6 +699,66 @@ static void test_dynamic_pri_reverse(void) uassert_true(RT_TRUE); } +static void recursive_lock_test_entry(void *param) +{ + rt_err_t result; + rt_mutex_t mutex = (rt_mutex_t)param; + + result = rt_mutex_take(mutex, RT_WAITING_FOREVER); + uassert_true(result == RT_EOK); + uassert_true(_sync_flag == 0); + result = rt_mutex_take(mutex, RT_WAITING_FOREVER); + uassert_true(result == RT_EOK); + _sync_flag++; +} + +static void test_recurse_lock(void) +{ + rt_err_t result; + + _sync_flag = 0; + result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO); + uassert_true(result == RT_EOK); + + /* take mutex and not release */ + result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER); + uassert_true(result == RT_EOK); + + /* take mutex twice */ + result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER); + uassert_true(result == RT_EOK); + + rt_thread_t tid = rt_thread_create("mutex_th", + recursive_lock_test_entry, + &static_mutex, + THREAD_STACKSIZE, + 10, + 10); + _sync_flag = -1; + + if (tid != RT_NULL) + rt_thread_startup(tid); + + result = rt_mutex_release(&static_mutex); + uassert_true(result == RT_EOK); + + _sync_flag = 0; + + result = rt_mutex_release(&static_mutex); + uassert_true(result == RT_EOK); + + while (_sync_flag != 1) + { + rt_thread_mdelay(10); + } + + result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER); + uassert_true(result == RT_EOK); + + result = rt_mutex_detach(&static_mutex); + uassert_true(result == RT_EOK); +} + static rt_err_t utest_tc_init(void) { #ifdef RT_USING_HEAP @@ -678,6 +791,7 @@ static void testcase(void) UTEST_UNIT_RUN(test_dynamic_mutex_trytake); UTEST_UNIT_RUN(test_dynamic_pri_reverse); #endif + UTEST_UNIT_RUN(test_recurse_lock); } UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_tc", utest_tc_init, utest_tc_cleanup, 1000); diff --git a/src/ipc.c b/src/ipc.c index a1a9c1f2daf..452181cd192 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -1351,7 +1351,7 @@ static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend if (mutex->owner == thread) { - if(mutex->hold < RT_MUTEX_HOLD_MAX) + if (mutex->hold < RT_MUTEX_HOLD_MAX) { /* it's the same thread */ mutex->hold ++; diff --git a/src/thread.c b/src/thread.c index eef7a153763..d9816b52776 100644 --- a/src/thread.c +++ b/src/thread.c @@ -76,6 +76,44 @@ void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread)) RT_OBJECT_HOOKLIST_DEFINE(rt_thread_inited); #endif /* defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR) */ +#ifdef RT_USING_MUTEX +static void _thread_detach_from_mutex(rt_thread_t thread) +{ + rt_list_t *node; + rt_list_t *tmp_list; + struct rt_mutex *mutex; + rt_base_t level; + + level = rt_spin_lock_irqsave(&thread->spinlock); + + /* check if thread is waiting on a mutex */ + if ((thread->pending_object) && + (rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex)) + { + /* remove it from its waiting list */ + struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object; + rt_mutex_drop_thread(mutex, thread); + thread->pending_object = RT_NULL; + } + + /* free taken mutex after detaching from waiting, so we don't lost mutex just got */ + rt_list_for_each_safe(node, tmp_list, &(thread->taken_object_list)) + { + mutex = rt_list_entry(node, struct rt_mutex, taken_list); + LOG_D("Thread [%s] exits while holding mutex [%s].\n", thread->parent.name, mutex->parent.parent.name); + /* recursively take */ + mutex->hold = 1; + rt_mutex_release(mutex); + } + + rt_spin_unlock_irqrestore(&thread->spinlock, level); +} + +#else + +static void _thread_detach_from_mutex(rt_thread_t thread) {} +#endif + static void _thread_exit(void) { struct rt_thread *thread; @@ -88,6 +126,8 @@ static void _thread_exit(void) rt_thread_close(thread); + _thread_detach_from_mutex(thread); + /* insert to defunct thread list */ rt_thread_defunct_enqueue(thread); @@ -133,41 +173,6 @@ static void _thread_timeout(void *parameter) rt_sched_unlock_n_resched(slvl); } -#ifdef RT_USING_MUTEX -static void _thread_detach_from_mutex(rt_thread_t thread) -{ - rt_list_t *node; - rt_list_t *tmp_list; - struct rt_mutex *mutex; - rt_base_t level; - - level = rt_spin_lock_irqsave(&thread->spinlock); - - /* check if thread is waiting on a mutex */ - if ((thread->pending_object) && - (rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex)) - { - /* remove it from its waiting list */ - struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object; - rt_mutex_drop_thread(mutex, thread); - thread->pending_object = RT_NULL; - } - - /* free taken mutex after detaching from waiting, so we don't lost mutex just got */ - rt_list_for_each_safe(node, tmp_list, &(thread->taken_object_list)) - { - mutex = rt_list_entry(node, struct rt_mutex, taken_list); - rt_mutex_release(mutex); - } - - rt_spin_unlock_irqrestore(&thread->spinlock, level); -} - -#else - -static void _thread_detach_from_mutex(rt_thread_t thread) {} -#endif - static rt_err_t _thread_init(struct rt_thread *thread, const char *name, void (*entry)(void *parameter),