Browse Source

fix: [kernel] [thread] Resolve delayed thread wakeup bug when calling suspend repeatedly (#10970)

* Enhance thread suspend function with stricter checks

Refactor thread suspension logic to improve clarity and correctness.

* Clean up formatting in thread.c

Removed unnecessary blank line in thread.c.

* Refactor thread suspend state handling

Refactor thread suspension logic to improve clarity and maintainability.

* Update thread.c

* Fix indentation for RT_THREAD_SUSPEND_KILLABLE case
Kurngsy 1 month ago
parent
commit
e4dce1df7d
1 changed files with 28 additions and 16 deletions
  1. 28 16
      src/thread.c

+ 28 - 16
src/thread.c

@@ -885,26 +885,27 @@ RTM_EXPORT(rt_thread_control);
 #include <lwp_signal.h>
 #endif
 
-static void _thread_set_suspend_state(struct rt_thread *thread, int suspend_flag)
+/* Convert suspend_flag to corresponding thread suspend state value */
+static rt_uint8_t _thread_get_suspend_state(int suspend_flag)
 {
-    rt_uint8_t stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
-
-    RT_ASSERT(thread != RT_NULL);
     switch (suspend_flag)
     {
     case RT_INTERRUPTIBLE:
-        stat = RT_THREAD_SUSPEND_INTERRUPTIBLE;
-        break;
+        return RT_THREAD_SUSPEND_INTERRUPTIBLE;
     case RT_KILLABLE:
-        stat = RT_THREAD_SUSPEND_KILLABLE;
-        break;
+        return RT_THREAD_SUSPEND_KILLABLE;
     case RT_UNINTERRUPTIBLE:
-        stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
-        break;
     default:
-        RT_ASSERT(0);
-        break;
+        return RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
     }
+}
+
+static void _thread_set_suspend_state(struct rt_thread *thread, int suspend_flag)
+{
+    rt_uint8_t stat;
+
+    RT_ASSERT(thread != RT_NULL);
+    stat = _thread_get_suspend_state(suspend_flag);
     RT_SCHED_CTX(thread).stat = stat | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
 }
 
@@ -943,20 +944,31 @@ rt_err_t rt_thread_suspend_to_list(rt_thread_t thread, rt_list_t *susp_list, int
     RT_ASSERT(thread != RT_NULL);
     RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
 
-    LOG_D("thread suspend:  %s", thread->parent.name);
+    LOG_D("thread suspend: %s", thread->parent.name);
 
     rt_sched_lock(&slvl);
 
     stat = rt_sched_thread_get_stat(thread);
-    if (stat == RT_THREAD_SUSPEND)
+    if (stat & RT_THREAD_SUSPEND_MASK)
     {
+        if (RT_SCHED_CTX(thread).sched_flag_ttmr_set == 1)
+        {
+            /* The new suspend operation will halt the tick timer. */
+            LOG_D("Thread [%s]'s timer has been halted.\n", thread->parent.name);
+            rt_sched_thread_timer_stop(thread);
+        }
+        /* Upgrade suspend state if new state is stricter */
+        if (stat < _thread_get_suspend_state(suspend_flag))
+        {
+            _thread_set_suspend_state(thread, suspend_flag);
+        }
         rt_sched_unlock(slvl);
-        /* Already suspended, just set status to success.  */
+        /* Already suspended, just set the status to success. */
         return RT_EOK;
     }
     else if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
     {
-        LOG_D("thread suspend: thread disorder, 0x%2x", RT_SCHED_CTX(thread).stat);
+        LOG_W("thread suspend: thread disorder, 0x%02x", RT_SCHED_CTX(thread).stat);
         rt_sched_unlock(slvl);
         return -RT_ERROR;
     }