Browse Source

[timer]add all soft timer config (#9048)

* add all soft timer

* update wq

* add timer test

* shield LOG_D
zms123456 10 tháng trước cách đây
mục cha
commit
59193dfeeb
5 tập tin đã thay đổi với 513 bổ sung319 xóa
  1. 12 23
      components/drivers/ipc/workqueue.c
  2. 450 244
      examples/utest/testcases/kernel/timer_tc.c
  3. 3 4
      include/rtdef.h
  4. 4 0
      src/Kconfig
  5. 44 48
      src/timer.c

+ 12 - 23
components/drivers/ipc/workqueue.c

@@ -94,7 +94,7 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
                                        struct rt_work *work, rt_tick_t ticks)
 {
     rt_base_t level;
-    rt_err_t err;
+    rt_err_t err = RT_EOK;
 
     level = rt_spin_lock_irqsave(&(queue->spinlock));
 
@@ -113,13 +113,7 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
         {
             /* resume work thread, and do a re-schedule if succeed */
             rt_thread_resume(queue->work_thread);
-            rt_spin_unlock_irqrestore(&(queue->spinlock), level);
         }
-        else
-        {
-            rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-        }
-        return RT_EOK;
     }
     else if (ticks < RT_TICK_MAX / 2)
     {
@@ -139,12 +133,14 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
         rt_list_insert_after(queue->delayed_list.prev, &(work->list));
 
         err = rt_timer_start(&(work->timer));
-        rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-
-        return err;
     }
+    else
+    {
+        err = - RT_ERROR;
+    }
+
     rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-    return -RT_ERROR;
+    return err;
 }
 
 static rt_err_t _workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work)
@@ -160,14 +156,14 @@ static rt_err_t _workqueue_cancel_work(struct rt_workqueue *queue, struct rt_wor
     {
         if ((err = rt_timer_stop(&(work->timer))) != RT_EOK)
         {
-            rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-            return err;
+            goto exit;
         }
         rt_timer_detach(&(work->timer));
         work->flags &= ~RT_WORK_STATE_SUBMITTING;
     }
     err = queue->work_current != work ? RT_EOK : -RT_EBUSY;
     work->workqueue = RT_NULL;
+exit:
     rt_spin_unlock_irqrestore(&(queue->spinlock), level);
     return err;
 }
@@ -200,12 +196,9 @@ static void _delayed_work_timeout_handler(void *parameter)
     {
         /* resume work thread, and do a re-schedule if succeed */
         rt_thread_resume(queue->work_thread);
-        rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-    }
-    else
-    {
-        rt_spin_unlock_irqrestore(&(queue->spinlock), level);
     }
+
+    rt_spin_unlock_irqrestore(&(queue->spinlock), level);
 }
 
 /**
@@ -358,13 +351,9 @@ rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *wo
     {
         /* resume work thread, and do a re-schedule if succeed */
         rt_thread_resume(queue->work_thread);
-        rt_spin_unlock_irqrestore(&(queue->spinlock), level);
-    }
-    else
-    {
-        rt_spin_unlock_irqrestore(&(queue->spinlock), level);
     }
 
+    rt_spin_unlock_irqrestore(&(queue->spinlock), level);
     return RT_EOK;
 }
 

+ 450 - 244
examples/utest/testcases/kernel/timer_tc.c

@@ -12,6 +12,16 @@
 #include <stdlib.h>
 #include "utest.h"
 
+#undef uassert_true
+#define uassert_true(value)                                 \
+    do                                                      \
+    {                                                       \
+        if (!(value))                                       \
+        {                                                   \
+            __utest_assert(value, "(" #value ") is false"); \
+        }                                                   \
+    } while (0)
+
 static rt_uint8_t timer_flag_oneshot[] = {
     RT_TIMER_FLAG_ONE_SHOT,
     RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
@@ -29,64 +39,69 @@ typedef struct test_timer_struct
     struct rt_timer static_timer; /* static timer handler */
     rt_timer_t dynamic_timer;     /* dynamic timer pointer */
     rt_tick_t expect_tick;        /* expect tick */
-    rt_uint8_t test_flag;         /* timer callback done flag */
+    rt_ubase_t callbacks;         /* timer callback times */
+    rt_bool_t is_static;          /* static or dynamic timer */
 } timer_struct;
 static timer_struct timer;
 
-#define test_static_timer_start test_static_timer_init
-#define test_static_timer_stop test_static_timer_init
-#define test_static_timer_detach test_static_timer_init
-
-static void static_timer_oneshot(void *param)
+static void timer_oneshot(void *param)
 {
     timer_struct *timer_call;
     timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
-
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
-    {
-        uassert_true(RT_FALSE);
-    }
+    timer_call->callbacks++;
 
-    return;
+    uassert_true(rt_tick_get() == timer_call->expect_tick);
 }
-static void static_timer_periodic(void *param)
+
+static void timer_periodic(void *param)
 {
     rt_err_t result;
     timer_struct *timer_call;
     timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
+    timer_call->callbacks++;
+
+    uassert_true(rt_tick_get() == timer_call->expect_tick);
 
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
+    if (timer_call->is_static)
     {
-        uassert_true(RT_FALSE);
+        timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
     }
-
-    /* periodic timer can stop */
-    result = rt_timer_stop(&timer_call->static_timer);
-    if (RT_EOK != result)
+    else
     {
-        uassert_true(RT_FALSE);
+        timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
     }
 
-    return;
+    if (timer_call->callbacks == 5)
+    {
+        /* periodic timer can stop */
+        if (timer_call->is_static)
+        {
+            result = rt_timer_stop(&timer_call->static_timer);
+        }
+        else
+        {
+            result = rt_timer_stop(timer_call->dynamic_timer);
+        }
+
+        uassert_true(result == RT_EOK);
+    }
 }
 
-static void test_static_timer_init(void)
+static void test_static_timer(void)
 {
     rt_err_t result;
-    int rand_num = rand() % 10;
+
+    timer.callbacks = 0;
+    timer.is_static = RT_TRUE;
 
     /* one shot timer test */
-    for (int time_out = 0; time_out < rand_num; time_out++)
+    for (int time_out = 1; time_out < 10; time_out++)
     {
         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
         {
             rt_timer_init(&timer.static_timer,
                           "static_timer",
-                          static_timer_oneshot,
+                          timer_oneshot,
                           &timer,
                           time_out,
                           timer_flag_oneshot[i]);
@@ -96,39 +111,28 @@ static void test_static_timer_init(void)
 
             /* start timer */
             result = rt_timer_start(&timer.static_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
 
             /* wait for timerout */
-            rt_thread_delay(time_out + 1);
+            rt_thread_delay(3 * time_out + 1);
+
+            uassert_true(timer.callbacks == 1);
 
             /* detach timer */
             result = rt_timer_detach(&timer.static_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
-
-            if (timer.test_flag != RT_TRUE)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
         }
     }
 
     /* periodic timer test */
-    for (int time_out = 0; time_out < rand_num; time_out++)
+    for (int time_out = 1; time_out < 10; time_out++)
     {
         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
         {
             rt_timer_init(&timer.static_timer,
                           "static_timer",
-                          static_timer_periodic,
+                          timer_periodic,
                           &timer,
                           time_out,
                           timer_flag_periodic[i]);
@@ -138,181 +142,279 @@ static void test_static_timer_init(void)
 
             /* start timer */
             result = rt_timer_start(&timer.static_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
 
             /* wait for timerout */
-            rt_thread_delay(time_out + 1);
+            rt_thread_delay(5 * time_out + 1);
+
+            uassert_true(timer.callbacks >= 5);
 
             /* detach timer */
             result = rt_timer_detach(&timer.static_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
-
-            if (timer.test_flag != RT_TRUE)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
         }
     }
+}
+
+static void test_static_timer_start_twice(void)
+{
+    rt_err_t result;
 
-    timer.test_flag = RT_FALSE;
-    uassert_true(RT_TRUE);
+    timer.callbacks = 0;
+    timer.is_static = RT_TRUE;
 
-    return;
+    /* timer start twice test */
+    for (int time_out = 2; time_out < 10; time_out++)
+    {
+        for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
+        {
+            rt_timer_init(&timer.static_timer,
+                          "static_timer",
+                          timer_oneshot,
+                          &timer,
+                          time_out,
+                          timer_flag_oneshot[i]);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(&timer.static_timer);
+            uassert_true(result == RT_EOK);
+
+            rt_thread_delay(1);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(&timer.static_timer);
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(3 * time_out + 1);
+
+            uassert_true(timer.callbacks == 1);
+
+            /* detach timer */
+            result = rt_timer_detach(&timer.static_timer);
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
+        }
+    }
 }
 
-static void static_timer_control(void *param)
+static void timer_control(void *param)
 {
     rt_err_t result;
     timer_struct *timer_call;
     timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
+    timer_call->callbacks++;
 
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
-    {
-        uassert_true(RT_FALSE);
-    }
+    uassert_true(rt_tick_get() == timer_call->expect_tick);
 
     /* periodic timer can stop */
-    result = rt_timer_stop(&timer_call->static_timer);
-    if (RT_EOK != result)
+    if (timer_call->is_static)
+    {
+        result = rt_timer_stop(&timer_call->static_timer);
+    }
+    else
     {
-        uassert_true(RT_FALSE);
+        result = rt_timer_stop(timer_call->dynamic_timer);
     }
 
-    return;
+    uassert_true(result == RT_EOK);
 }
 
 static void test_static_timer_control(void)
 {
     rt_err_t result;
-    int rand_num = rand() % 10;
     int set_data;
     int get_data;
 
+    timer.callbacks = 0;
+    timer.is_static = RT_TRUE;
+
     rt_timer_init(&timer.static_timer,
                   "static_timer",
-                  static_timer_control,
+                  timer_control,
                   &timer,
                   5,
                   RT_TIMER_FLAG_PERIODIC);
 
     /* test set data */
-    set_data = rand_num;
+    set_data = 10;
     result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-    }
+
+    uassert_true(result == RT_EOK);
 
     /* test get data */
     result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-    }
 
-    /* a set of test */
-    if (set_data != get_data)
-    {
-        uassert_true(RT_FALSE);
-    }
+    uassert_true(result == RT_EOK);
+    uassert_true(set_data == get_data);
 
     /* calc expect tick */
     timer.expect_tick = rt_tick_get() + set_data;
 
     /* start timer */
     result = rt_timer_start(&timer.static_timer);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-        return;
-    }
+    uassert_true(result == RT_EOK);
 
-    rt_thread_delay(set_data + 1);
+    rt_thread_delay(3 * set_data + 1);
 
     /* detach timer */
     result = rt_timer_detach(&timer.static_timer);
-    if (RT_EOK != result)
+    uassert_true(result == RT_EOK);
+    uassert_true(timer.callbacks == 1);
+}
+
+static void timer_start_in_callback(void *param)
+{
+    rt_err_t result;
+    timer_struct *timer_call;
+    timer_call = (timer_struct *)param;
+    timer_call->callbacks++;
+
+    uassert_true(rt_tick_get() == timer_call->expect_tick);
+
+    if (timer_call->is_static)
     {
-        uassert_true(RT_FALSE);
-        return;
+        timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
+        result = rt_timer_start(&timer_call->static_timer);
     }
-
-    if (timer.test_flag != RT_TRUE)
+    else
     {
-        uassert_true(RT_FALSE);
-        return;
+        timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
+        result = rt_timer_start(timer_call->dynamic_timer);
     }
 
-    timer.test_flag = RT_FALSE;
-    uassert_true(RT_TRUE);
+    uassert_true(result == RT_EOK);
 }
 
-#ifdef RT_USING_HEAP
-
-#define test_dynamic_timer_start test_dynamic_timer_create
-#define test_dynamic_timer_stop test_dynamic_timer_create
-#define test_dynamic_timer_delete test_dynamic_timer_create
-
-static void dynamic_timer_oneshot(void *param)
+static void timer_start_stop_in_callback(void *param)
 {
+    rt_err_t result;
     timer_struct *timer_call;
     timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
+    timer_call->callbacks++;
 
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
+    uassert_true(rt_tick_get() == timer_call->expect_tick);
+
+    if (timer_call->is_static)
+    {
+        result = rt_timer_start(&timer_call->static_timer);
+    }
+    else
+    {
+        result = rt_timer_start(timer_call->dynamic_timer);
+    }
+
+    uassert_true(result == RT_EOK);
+
+    if (timer_call->is_static)
+    {
+        result = rt_timer_stop(&timer_call->static_timer);
+    }
+    else
     {
-        uassert_true(RT_FALSE);
+        result = rt_timer_stop(timer_call->dynamic_timer);
     }
 
-    return;
+    uassert_true(result == RT_EOK);
 }
-static void dynamic_timer_periodic(void *param)
+
+static void test_static_timer_op_in_callback(void)
 {
     rt_err_t result;
-    timer_struct *timer_call;
-    timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
 
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
+    timer.callbacks = 0;
+    timer.is_static = RT_TRUE;
+
+    /* start in callback test */
+    for (int time_out = 1; time_out < 10; time_out++)
     {
-        uassert_true(RT_FALSE);
+        for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
+        {
+            rt_timer_init(&timer.static_timer,
+                          "static_timer",
+                          timer_start_in_callback,
+                          &timer,
+                          time_out,
+                          timer_flag_oneshot[i]);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(&timer.static_timer);
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(5 * time_out + 1);
+
+            uassert_true(timer.callbacks >= 5);
+
+            /* detach timer */
+            result = rt_timer_detach(&timer.static_timer);
+            uassert_true(result == RT_EOK);
+
+            timer.callbacks = 0;
+        }
     }
 
-    /* periodic timer can stop */
-    result = rt_timer_stop(timer_call->dynamic_timer);
-    if (RT_EOK != result)
+    /* start & stop in callback test */
+    for (int time_out = 1; time_out < 10; time_out++)
     {
-        uassert_true(RT_FALSE);
-    }
+        for (int i = 0; i < sizeof(timer_flag_periodic); i++)
+        {
+            rt_timer_init(&timer.static_timer,
+                          "static_timer",
+                          timer_start_stop_in_callback,
+                          &timer,
+                          time_out,
+                          timer_flag_periodic[i]);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
 
-    return;
+            /* start timer */
+            result = rt_timer_start(&timer.static_timer);
+
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(3 * time_out + 1);
+
+            uassert_true(timer.callbacks == 1);
+
+            /* detach timer */
+            result = rt_timer_detach(&timer.static_timer);
+
+            uassert_true(result == RT_EOK);
+
+            timer.callbacks = 0;
+        }
+    }
 }
 
-static void test_dynamic_timer_create(void)
+#ifdef RT_USING_HEAP
+
+static void test_dynamic_timer(void)
 {
     rt_err_t result;
-    int rand_num = rand() % 10;
+
+    timer.callbacks = 0;
+    timer.is_static = RT_FALSE;
 
     /* one shot timer test */
-    for (int time_out = 0; time_out < rand_num; time_out++)
+    for (int time_out = 1; time_out < 10; time_out++)
     {
         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
         {
             timer.dynamic_timer = rt_timer_create("dynamic_timer",
-                                                  dynamic_timer_oneshot,
+                                                  timer_oneshot,
                                                   &timer,
                                                   time_out,
                                                   timer_flag_oneshot[i]);
@@ -322,38 +424,26 @@ static void test_dynamic_timer_create(void)
 
             /* start timer */
             result = rt_timer_start(timer.dynamic_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
 
             /* wait for timerout */
-            rt_thread_delay(time_out + 1);
+            rt_thread_delay(3 * time_out + 1);
+            uassert_true(timer.callbacks == 1);
 
             /* detach timer */
             result = rt_timer_delete(timer.dynamic_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
-
-            if (timer.test_flag != RT_TRUE)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
         }
     }
 
     /* periodic timer test */
-    for (int time_out = 0; time_out < rand_num; time_out++)
+    for (int time_out = 1; time_out < 10; time_out++)
     {
         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
         {
             timer.dynamic_timer = rt_timer_create("dynamic_timer",
-                                                  dynamic_timer_periodic,
+                                                  timer_periodic,
                                                   &timer,
                                                   time_out,
                                                   timer_flag_periodic[i]);
@@ -363,131 +453,248 @@ static void test_dynamic_timer_create(void)
 
             /* start timer */
             result = rt_timer_start(timer.dynamic_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
 
             /* wait for timerout */
-            rt_thread_delay(time_out + 1);
+            rt_thread_delay(5 * time_out + 1);
+            uassert_true(timer.callbacks >= 5);
 
             /* detach timer */
             result = rt_timer_delete(timer.dynamic_timer);
-            if (RT_EOK != result)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
-
-            if (timer.test_flag != RT_TRUE)
-            {
-                uassert_true(RT_FALSE);
-                return;
-            }
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
         }
     }
-
-    timer.test_flag = RT_FALSE;
-    uassert_true(RT_TRUE);
-
-    return;
-}
-
-static void dynamic_timer_control(void *param)
-{
-    rt_err_t result;
-    timer_struct *timer_call;
-    timer_call = (timer_struct *)param;
-    timer_call->test_flag = RT_TRUE;
-
-    /* check expect tick */
-    if (rt_tick_get() - timer_call->expect_tick > 1)
-    {
-        uassert_true(RT_FALSE);
-    }
-
-    /* periodic timer can stop */
-    result = rt_timer_stop(timer_call->dynamic_timer);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-    }
-
-    return;
 }
 
 static void test_dynamic_timer_control(void)
 {
     rt_err_t result;
-    int rand_num = rand() % 10;
     int set_data;
     int get_data;
 
+    timer.callbacks = 0;
+    timer.is_static = RT_FALSE;
+
     timer.dynamic_timer = rt_timer_create("dynamic_timer",
-                                          dynamic_timer_control,
+                                          timer_control,
                                           &timer,
                                           5,
                                           RT_TIMER_FLAG_PERIODIC);
 
     /* test set data */
-    set_data = rand_num;
+    set_data = 10;
     result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-    }
+    uassert_true(result == RT_EOK);
 
     /* test get data */
     result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-    }
 
-    /* a set of test */
-    if (set_data != get_data)
-    {
-        uassert_true(RT_FALSE);
-    }
+    uassert_true(result == RT_EOK);
+    uassert_true(set_data == get_data);
 
     /* calc expect tick */
     timer.expect_tick = rt_tick_get() + set_data;
 
     /* start timer */
     result = rt_timer_start(timer.dynamic_timer);
-    if (RT_EOK != result)
-    {
-        uassert_true(RT_FALSE);
-        return;
-    }
+    uassert_true(result == RT_EOK);
 
-    rt_thread_delay(set_data + 1);
+    rt_thread_delay(3 * set_data + 1);
 
     /* detach timer */
     result = rt_timer_delete(timer.dynamic_timer);
-    if (RT_EOK != result)
+    uassert_true(result == RT_EOK);
+    uassert_true(timer.callbacks == 1);
+}
+
+static void test_dynamic_timer_start_twice(void)
+{
+    rt_err_t result;
+
+    timer.callbacks = 0;
+    timer.is_static = RT_FALSE;
+
+    /* timer start twice test */
+    for (int time_out = 2; time_out < 10; time_out++)
     {
-        uassert_true(RT_FALSE);
-        return;
+        for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
+        {
+            timer.dynamic_timer = rt_timer_create("dynamic_timer",
+                                          timer_oneshot,
+                                          &timer,
+                                          time_out,
+                                          timer_flag_oneshot[i]);
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(timer.dynamic_timer);
+            uassert_true(result == RT_EOK);
+
+            rt_thread_delay(1);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(timer.dynamic_timer);
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(3 * time_out + 1);
+
+            uassert_true(timer.callbacks == 1);
+
+            /* detach timer */
+            result = rt_timer_delete(timer.dynamic_timer);
+            uassert_true(result == RT_EOK);
+            timer.callbacks = 0;
+        }
     }
+}
+
+static void test_dynamic_timer_op_in_callback(void)
+{
+    rt_err_t result;
 
-    if (timer.test_flag != RT_TRUE)
+    timer.callbacks = 0;
+    timer.is_static = RT_FALSE;
+
+    /* start in callback test */
+    for (int time_out = 1; time_out < 10; time_out++)
     {
-        uassert_true(RT_FALSE);
-        return;
+        for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
+        {
+            timer.dynamic_timer = rt_timer_create("dynamic_timer",
+                                      timer_start_in_callback,
+                                      &timer,
+                                      time_out,
+                                      timer_flag_oneshot[i]);
+
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(timer.dynamic_timer);
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(5 * time_out + 1);
+
+            uassert_true(timer.callbacks >= 5);
+
+            /* detach timer */
+            result = rt_timer_delete(timer.dynamic_timer);
+            uassert_true(result == RT_EOK);
+
+            timer.callbacks = 0;
+        }
     }
 
-    timer.test_flag = RT_FALSE;
-    uassert_true(RT_TRUE);
-}
+    /* start & stop in callback test */
+    for (int time_out = 1; time_out < 10; time_out++)
+    {
+        for (int i = 0; i < sizeof(timer_flag_periodic); i++)
+        {
+            timer.dynamic_timer = rt_timer_create("dynamic_timer",
+                                      timer_start_stop_in_callback,
+                                      &timer,
+                                      time_out,
+                                      timer_flag_periodic[i]);
+            /* calc expect tick */
+            timer.expect_tick = rt_tick_get() + time_out;
+
+            /* start timer */
+            result = rt_timer_start(timer.dynamic_timer);
+
+            uassert_true(result == RT_EOK);
+
+            /* wait for timerout */
+            rt_thread_delay(3 * time_out + 1);
+
+            uassert_true(timer.callbacks == 1);
 
+            /* detach timer */
+            result = rt_timer_delete(timer.dynamic_timer);
+
+            uassert_true(result == RT_EOK);
+
+            timer.callbacks = 0;
+        }
+    }
+}
 #endif /* RT_USING_HEAP */
 
+#define TEST_TIME_S 60      // test 60 seconds
+#define STRESS_TIMERS 100
+
+static struct rt_timer stress_timer[STRESS_TIMERS];
+
+static void timer_stress(void *param)
+{
+    rt_timer_t stress_timer = (rt_timer_t)param;
+
+    if (rand() % 2 == 0)
+    {
+        rt_timer_start(stress_timer);
+    }
+    else
+    {
+        rt_timer_stop(stress_timer);
+    }
+}
+
+static void test_timer_stress(void)
+{
+    rt_tick_t start;
+    rt_ubase_t iters = 0;
+
+    LOG_I("timer stress test begin, it will take %d seconds", 3*TEST_TIME_S);
+
+    for (int i = 0; i < sizeof(timer_flag_periodic); i++)
+    {
+        for (int j = 0; j < STRESS_TIMERS; j++)
+        {
+            rt_timer_init(&stress_timer[j],
+                  "stress_timer",
+                  timer_stress,
+                  &stress_timer[j],
+                  j + 1,
+                  timer_flag_periodic[i]);
+        }
+
+        start = rt_tick_get();
+
+        while (rt_tick_get() - start <= TEST_TIME_S * RT_TICK_PER_SECOND)
+        {
+            for (int j = 0; j < STRESS_TIMERS; j++)
+            {
+                if (rand() % 2 == 0)
+                {
+                    rt_timer_start(&stress_timer[j]);
+                }
+                else
+                {
+                    rt_timer_stop(&stress_timer[j]);
+                }
+            }
+            iters ++;
+        }
+
+        for (int j = 0; j < STRESS_TIMERS; j++)
+        {
+            rt_timer_detach(&stress_timer[j]);
+        }
+    }
+
+    LOG_I("success after %lu iterations", iters);
+}
+
 static rt_err_t utest_tc_init(void)
 {
     timer.dynamic_timer = RT_NULL;
-    timer.test_flag = RT_FALSE;
+    timer.callbacks = 0;
 
     return RT_EOK;
 }
@@ -495,25 +702,24 @@ static rt_err_t utest_tc_init(void)
 static rt_err_t utest_tc_cleanup(void)
 {
     timer.dynamic_timer = RT_NULL;
-    timer.test_flag = RT_FALSE;
+    timer.callbacks = 0;
 
     return RT_EOK;
 }
 
 static void testcase(void)
 {
-    UTEST_UNIT_RUN(test_static_timer_init);
-    UTEST_UNIT_RUN(test_static_timer_start);
-    UTEST_UNIT_RUN(test_static_timer_stop);
-    UTEST_UNIT_RUN(test_static_timer_detach);
+    UTEST_UNIT_RUN(test_static_timer);
     UTEST_UNIT_RUN(test_static_timer_control);
+    UTEST_UNIT_RUN(test_static_timer_start_twice);
+    UTEST_UNIT_RUN(test_static_timer_op_in_callback);
 #ifdef RT_USING_HEAP
-    UTEST_UNIT_RUN(test_dynamic_timer_create);
-    UTEST_UNIT_RUN(test_dynamic_timer_start);
-    UTEST_UNIT_RUN(test_dynamic_timer_stop);
-    UTEST_UNIT_RUN(test_dynamic_timer_delete);
+    UTEST_UNIT_RUN(test_dynamic_timer);
     UTEST_UNIT_RUN(test_dynamic_timer_control);
+    UTEST_UNIT_RUN(test_dynamic_timer_start_twice);
+    UTEST_UNIT_RUN(test_dynamic_timer_op_in_callback);
 #endif /* RT_USING_HEAP */
+    UTEST_UNIT_RUN(test_timer_stress);
 }
 UTEST_TC_EXPORT(testcase, "testcases.kernel.timer_tc", utest_tc_init, utest_tc_cleanup, 1000);
 

+ 3 - 4
include/rtdef.h

@@ -579,14 +579,13 @@ struct rt_object_information
  */
 #define RT_TIMER_FLAG_DEACTIVATED       0x0             /**< timer is deactive */
 #define RT_TIMER_FLAG_ACTIVATED         0x1             /**< timer is active */
-#define RT_TIMER_FLAG_PROCESSING        0x2             /**< timer's timeout fuction is processing */
 #define RT_TIMER_FLAG_ONE_SHOT          0x0             /**< one shot timer */
-#define RT_TIMER_FLAG_PERIODIC          0x4             /**< periodic timer */
+#define RT_TIMER_FLAG_PERIODIC          0x2             /**< periodic timer */
 
 #define RT_TIMER_FLAG_HARD_TIMER        0x0             /**< hard timer,the timer's callback function will be called in tick isr. */
-#define RT_TIMER_FLAG_SOFT_TIMER        0x8             /**< soft timer,the timer's callback function will be called in timer thread. */
+#define RT_TIMER_FLAG_SOFT_TIMER        0x4             /**< soft timer,the timer's callback function will be called in timer thread. */
 #define RT_TIMER_FLAG_THREAD_TIMER \
-    (0x10 | RT_TIMER_FLAG_HARD_TIMER)                    /**< thread timer that cooperates with scheduler directly */
+    (0x8 | RT_TIMER_FLAG_HARD_TIMER)                    /**< thread timer that cooperates with scheduler directly */
 
 #define RT_TIMER_CTRL_SET_TIME          0x0             /**< set timer control command */
 #define RT_TIMER_CTRL_GET_TIME          0x1             /**< get timer control command */

+ 4 - 0
src/Kconfig

@@ -176,6 +176,10 @@ if RT_USING_TIMER_SOFT
         int "The stack size of timer thread"
         default 2048 if ARCH_CPU_64BIT
         default 512
+
+    config RT_USING_TIMER_ALL_SOFT
+        bool "Set all timer as soft timer"
+        default n
 endif
 
 config RT_USING_CPU_USAGE_TRACER

+ 44 - 48
src/timer.c

@@ -31,9 +31,11 @@
 #define DBG_LVL           DBG_INFO
 #include <rtdbg.h>
 
+#ifndef RT_USING_TIMER_ALL_SOFT
 /* hard timer list */
 static rt_list_t _timer_list[RT_TIMER_SKIP_LIST_LEVEL];
 static struct rt_spinlock _htimer_lock;
+#endif
 
 #ifdef RT_USING_TIMER_SOFT
 
@@ -93,6 +95,9 @@ void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
 
 rt_inline struct rt_spinlock* _timerlock_idx(struct rt_timer *timer)
 {
+#ifdef RT_USING_TIMER_ALL_SOFT
+    return &_stimer_lock;
+#else
 #ifdef RT_USING_TIMER_SOFT
     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
     {
@@ -103,6 +108,7 @@ rt_inline struct rt_spinlock* _timerlock_idx(struct rt_timer *timer)
     {
         return &_htimer_lock;
     }
+#endif
 }
 
 /**
@@ -130,6 +136,10 @@ static void _timer_init(rt_timer_t timer,
 {
     int i;
 
+#ifdef RT_USING_TIMER_ALL_SOFT
+    flag               |= RT_TIMER_FLAG_SOFT_TIMER;
+#endif
+
     /* set flag */
     timer->parent.flag  = flag;
 
@@ -403,11 +413,6 @@ static rt_err_t _timer_start(rt_list_t *timer_list, rt_timer_t timer)
     unsigned int tst_nr;
     static unsigned int random_nr;
 
-    if (timer->parent.flag & RT_TIMER_FLAG_PROCESSING)
-    {
-        return -RT_ERROR;
-    }
-
     /* remove timer from list */
     _timer_remove(timer);
     /* change status of timer */
@@ -516,7 +521,6 @@ static void _timer_check(rt_list_t *timer_list, struct rt_spinlock *lock)
                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
             }
 
-            t->parent.flag |= RT_TIMER_FLAG_PROCESSING;
             /* add timer to temporary list  */
             rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
 
@@ -529,8 +533,6 @@ static void _timer_check(rt_list_t *timer_list, struct rt_spinlock *lock)
 
             level = rt_spin_lock_irqsave(lock);
 
-            t->parent.flag &= ~RT_TIMER_FLAG_PROCESSING;
-
             /* Check whether the timer object is detached or started again */
             if (rt_list_isempty(&list))
             {
@@ -570,6 +572,10 @@ rt_err_t rt_timer_start(rt_timer_t timer)
     RT_ASSERT(timer != RT_NULL);
     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
 
+#ifdef RT_USING_TIMER_ALL_SOFT
+    timer_list = _soft_timer_list;
+    spinlock = &_stimer_lock;
+#else
 #ifdef RT_USING_TIMER_SOFT
     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
     {
@@ -582,6 +588,7 @@ rt_err_t rt_timer_start(rt_timer_t timer)
         timer_list = _timer_list;
         spinlock = &_htimer_lock;
     }
+#endif
 
     if (timer->parent.flag & RT_TIMER_FLAG_THREAD_TIMER)
     {
@@ -598,13 +605,6 @@ rt_err_t rt_timer_start(rt_timer_t timer)
 
     err = _timer_start(timer_list, timer);
 
-#ifdef RT_USING_TIMER_SOFT
-    if (err == RT_EOK && (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER))
-    {
-        rt_sem_release(&_soft_timer_sem);
-    }
-#endif /* RT_USING_TIMER_SOFT */
-
     rt_spin_unlock_irqrestore(spinlock, level);
 
     if (is_thread_timer)
@@ -756,7 +756,20 @@ void rt_timer_check(void)
         return;
     }
 #endif
+
+#ifdef RT_USING_TIMER_SOFT
+    rt_err_t ret = RT_ERROR;
+    rt_tick_t next_timeout;
+
+    ret = _timer_list_next_timeout(_soft_timer_list, &next_timeout);
+    if ((ret == RT_EOK) && (next_timeout <= rt_tick_get()))
+    {
+        rt_sem_release(&_soft_timer_sem);
+    }
+#endif
+#ifndef RT_USING_TIMER_ALL_SOFT
     _timer_check(_timer_list, &_htimer_lock);
+#endif
 }
 
 /**
@@ -767,13 +780,21 @@ void rt_timer_check(void)
 rt_tick_t rt_timer_next_timeout_tick(void)
 {
     rt_base_t level;
-    rt_tick_t next_timeout = RT_TICK_MAX;
+    rt_tick_t htimer_next_timeout = RT_TICK_MAX, stimer_next_timeout = RT_TICK_MAX;
 
+#ifndef RT_USING_TIMER_ALL_SOFT
     level = rt_spin_lock_irqsave(&_htimer_lock);
-    _timer_list_next_timeout(_timer_list, &next_timeout);
+    _timer_list_next_timeout(_timer_list, &htimer_next_timeout);
     rt_spin_unlock_irqrestore(&_htimer_lock, level);
+#endif
 
-    return next_timeout;
+#ifdef RT_USING_TIMER_SOFT
+    level = rt_spin_lock_irqsave(&_stimer_lock);
+    _timer_list_next_timeout(_soft_timer_list, &stimer_next_timeout);
+    rt_spin_unlock_irqrestore(&_stimer_lock, level);
+#endif
+
+    return htimer_next_timeout < stimer_next_timeout ? htimer_next_timeout : stimer_next_timeout;
 }
 
 #ifdef RT_USING_TIMER_SOFT
@@ -784,41 +805,12 @@ rt_tick_t rt_timer_next_timeout_tick(void)
  */
 static void _timer_thread_entry(void *parameter)
 {
-    rt_err_t ret = RT_ERROR;
-    rt_tick_t next_timeout;
-    rt_base_t level;
-
     RT_UNUSED(parameter);
 
-    rt_sem_control(&_soft_timer_sem, RT_IPC_CMD_SET_VLIMIT, (void*)1);
-
     while (1)
     {
-        /* get the next timeout tick */
-        level = rt_spin_lock_irqsave(&_stimer_lock);
-        ret = _timer_list_next_timeout(_soft_timer_list, &next_timeout);
-        rt_spin_unlock_irqrestore(&_stimer_lock, level);
-
-        if (ret != RT_EOK)
-        {
-            rt_sem_take(&_soft_timer_sem, RT_WAITING_FOREVER);
-        }
-        else
-        {
-            rt_tick_t current_tick;
-
-            /* get current tick */
-            current_tick = rt_tick_get();
-
-            if ((next_timeout - current_tick) < RT_TICK_MAX / 2)
-            {
-                /* get the delta timeout tick */
-                next_timeout = next_timeout - current_tick;
-                rt_sem_take(&_soft_timer_sem, next_timeout);
-            }
-        }
-
         _timer_check(_soft_timer_list, &_stimer_lock); /* check software timer */
+        rt_sem_take(&_soft_timer_sem, RT_WAITING_FOREVER);
     }
 }
 #endif /* RT_USING_TIMER_SOFT */
@@ -830,13 +822,16 @@ static void _timer_thread_entry(void *parameter)
  */
 void rt_system_timer_init(void)
 {
+#ifndef RT_USING_TIMER_ALL_SOFT
     rt_size_t i;
 
     for (i = 0; i < sizeof(_timer_list) / sizeof(_timer_list[0]); i++)
     {
         rt_list_init(_timer_list + i);
     }
+
     rt_spin_lock_init(&_htimer_lock);
+#endif
 }
 
 /**
@@ -857,6 +852,7 @@ void rt_system_timer_thread_init(void)
     }
     rt_spin_lock_init(&_stimer_lock);
     rt_sem_init(&_soft_timer_sem, "stimer", 0, RT_IPC_FLAG_PRIO);
+    rt_sem_control(&_soft_timer_sem, RT_IPC_CMD_SET_VLIMIT, (void*)1);
     /* start software timer thread */
     rt_thread_init(&_timer_thread,
                    "timer",