diff --git a/components/drivers/ipc/workqueue.c b/components/drivers/ipc/workqueue.c index 6862a35843..fb3657b192 100644 --- a/components/drivers/ipc/workqueue.c +++ b/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; } diff --git a/examples/utest/testcases/kernel/timer_tc.c b/examples/utest/testcases/kernel/timer_tc.c index e7fffcb617..b914d5d06b 100644 --- a/examples/utest/testcases/kernel/timer_tc.c +++ b/examples/utest/testcases/kernel/timer_tc.c @@ -12,6 +12,16 @@ #include #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; + timer_call->callbacks++; - /* check expect tick */ - if (rt_tick_get() - timer_call->expect_tick > 1) - { - uassert_true(RT_FALSE); - } - - 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++; - /* 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) { - uassert_true(RT_FALSE); + timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick; + } + else + { + timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick; } - /* periodic timer can stop */ - result = rt_timer_stop(&timer_call->static_timer); - if (RT_EOK != result) + if (timer_call->callbacks == 5) { - uassert_true(RT_FALSE); - } + /* 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); + } - return; + 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; } } - - timer.test_flag = RT_FALSE; - uassert_true(RT_TRUE); - - return; } -static void static_timer_control(void *param) +static void test_static_timer_start_twice(void) +{ + rt_err_t result; + + timer.callbacks = 0; + timer.is_static = RT_TRUE; + + /* 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 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) { - uassert_true(RT_FALSE); + result = rt_timer_stop(&timer_call->static_timer); + } + else + { + 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); + } + else + { + timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick; + result = rt_timer_start(timer_call->dynamic_timer); } - if (timer.test_flag != RT_TRUE) + uassert_true(result == RT_EOK); +} + +static void timer_start_stop_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; + result = rt_timer_start(&timer_call->static_timer); + } + else + { + result = rt_timer_start(timer_call->dynamic_timer); } - timer.test_flag = RT_FALSE; - uassert_true(RT_TRUE); + uassert_true(result == RT_EOK); + + 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_op_in_callback(void) +{ + rt_err_t result; + + timer.callbacks = 0; + timer.is_static = RT_TRUE; + + /* start in callback test */ + 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", + 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; + } + } + + /* 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++) + { + 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; + + /* 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; + } + } } #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) -{ - 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); - } - - return; -} -static void dynamic_timer_periodic(void *param) +static void test_dynamic_timer(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) - { - 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_create(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(RT_FALSE); - return; - } - - if (timer.test_flag != RT_TRUE) - { - uassert_true(RT_FALSE); - return; - } - - timer.test_flag = RT_FALSE; - uassert_true(RT_TRUE); + 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++) + { + 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; + + timer.callbacks = 0; + timer.is_static = RT_FALSE; + + /* start in callback test */ + 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", + 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; + } + } + + /* 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); diff --git a/include/rtdef.h b/include/rtdef.h index 26a1647ee6..2fc3bd671c 100644 --- a/include/rtdef.h +++ b/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 */ diff --git a/src/Kconfig b/src/Kconfig index bf14182939..30105c3956 100644 --- a/src/Kconfig +++ b/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 diff --git a/src/timer.c b/src/timer.c index fd362a5b05..eee8a41959 100644 --- a/src/timer.c +++ b/src/timer.c @@ -31,9 +31,11 @@ #define DBG_LVL DBG_INFO #include +#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",