From 970c7c6f7a8b6e26e3254de5c9c0877b18fa0627 Mon Sep 17 00:00:00 2001 From: xqyjlj Date: Thu, 13 Apr 2023 16:00:19 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix(components/drivers):=20fix?= =?UTF-8?q?=20cpu=20timer=20in=20multithreading=20(#7222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐞 fix(components/drivers): fix cpu timer in multithreading * 🎈 perf(components): change double to uint64_t * 🎈 perf(components): add UL suffix --- components/drivers/cputime/cputime.c | 12 +- components/drivers/cputime/cputime_cortexm.c | 6 +- components/drivers/cputime/cputime_riscv.c | 6 +- components/drivers/cputime/cputimer.c | 181 ++++++------------ components/drivers/include/drivers/cputime.h | 4 +- components/drivers/include/drivers/cputimer.h | 1 + components/libc/compilers/common/ctime.c | 32 ++-- 7 files changed, 90 insertions(+), 152 deletions(-) diff --git a/components/drivers/cputime/cputime.c b/components/drivers/cputime/cputime.c index d87e39199c..b8060299b1 100644 --- a/components/drivers/cputime/cputime.c +++ b/components/drivers/cputime/cputime.c @@ -18,9 +18,9 @@ static const struct rt_clock_cputime_ops *_cputime_ops = RT_NULL; * The clock_cpu_getres() function shall return the resolution of CPU time, the * number of nanosecond per tick. * - * @return the number of nanosecond per tick + * @return the number of nanosecond per tick(x (1000UL * 1000)) */ -double clock_cpu_getres(void) +uint64_t clock_cpu_getres(void) { if (_cputime_ops) return _cputime_ops->cputime_getres(); @@ -78,9 +78,9 @@ int clock_cpu_issettimeout(void) */ uint64_t clock_cpu_microsecond(uint64_t cpu_tick) { - double unit = clock_cpu_getres(); + uint64_t unit = clock_cpu_getres(); - return (uint64_t)((cpu_tick * unit) / 1000); + return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / 1000); } /** @@ -93,9 +93,9 @@ uint64_t clock_cpu_microsecond(uint64_t cpu_tick) */ uint64_t clock_cpu_millisecond(uint64_t cpu_tick) { - double unit = clock_cpu_getres(); + uint64_t unit = clock_cpu_getres(); - return (uint64_t)((cpu_tick * unit) / (1000 * 1000)); + return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / (1000UL * 1000)); } /** diff --git a/components/drivers/cputime/cputime_cortexm.c b/components/drivers/cputime/cputime_cortexm.c index 247e4fcf2d..52626a2f98 100644 --- a/components/drivers/cputime/cputime_cortexm.c +++ b/components/drivers/cputime/cputime_cortexm.c @@ -19,11 +19,11 @@ #endif /* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */ -static double cortexm_cputime_getres(void) +static uint64_t cortexm_cputime_getres(void) { - double ret = 1000UL * 1000 * 1000; + uint64_t ret = 1000UL * 1000 * 1000; - ret = ret / SystemCoreClock; + ret = (ret * (1000UL * 1000)) / SystemCoreClock; return ret; } diff --git a/components/drivers/cputime/cputime_riscv.c b/components/drivers/cputime/cputime_riscv.c index a486c0a5f5..597157c226 100644 --- a/components/drivers/cputime/cputime_riscv.c +++ b/components/drivers/cputime/cputime_riscv.c @@ -6,11 +6,11 @@ /* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */ -static double riscv_cputime_getres(void) +static uint64_t riscv_cputime_getres(void) { - double ret = 1000UL * 1000 * 1000; + uint64_t ret = 1000UL * 1000 * 1000; - ret = ret / CPUTIME_TIMER_FREQ; + ret = (ret * (1000UL * 1000)) / CPUTIME_TIMER_FREQ; return ret; } diff --git a/components/drivers/cputime/cputimer.c b/components/drivers/cputime/cputimer.c index 12be40356e..22253e3590 100644 --- a/components/drivers/cputime/cputimer.c +++ b/components/drivers/cputime/cputimer.c @@ -5,78 +5,87 @@ * * Change Logs: * Date Author Notes - * 2023-02-13 zhkag first version + * 2023-02-13 zhkag first version + * 2023-04-03 xqyjlj fix cputimer in multithreading */ -#include -#include #include +#include +#include -static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list); +static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list); +static struct rt_cputimer *_cputimer_nowtimer = RT_NULL; -static void _cputime_timeout(void *parameter) +static void _cputime_sleep_timeout(void *parameter) +{ + struct rt_semaphore *sem; + sem = (struct rt_semaphore *)parameter; + rt_sem_release(sem); +} + +static void _cputime_timeout_callback(void *parameter) { struct rt_cputimer *timer; timer = (struct rt_cputimer *)parameter; - timer->timeout_func(timer->parameter); - rt_list_remove(&timer->row); + rt_base_t level; + level = rt_hw_interrupt_disable(); + _cputimer_nowtimer = RT_NULL; + rt_list_remove(&(timer->row)); + rt_hw_interrupt_enable(level); + timer->timeout_func(&(timer->sem)); +} + +static void _set_next_timeout() +{ + struct rt_cputimer *t; if (&_cputimer_list != _cputimer_list.prev) { - struct rt_cputimer *t; - t = rt_list_entry(_cputimer_list.next, struct rt_cputimer, row); - clock_cpu_settimeout(t->timeout_tick, _cputime_timeout, t); + t = rt_list_entry((&_cputimer_list)->next, struct rt_cputimer, row); + if (_cputimer_nowtimer != RT_NULL) + { + if (t != _cputimer_nowtimer && t->timeout_tick < _cputimer_nowtimer->timeout_tick) + { + _cputimer_nowtimer = t; + clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t); + } + } + else + { + _cputimer_nowtimer = t; + clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t); + } } else - clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL); - if ((timer->parent.flag & RT_TIMER_FLAG_PERIODIC) && - (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { - /* start it */ - timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - rt_cputimer_start(timer); + _cputimer_nowtimer = NULL; } } void rt_cputimer_init(rt_cputimer_t timer, - const char *name, + const char *name, void (*timeout)(void *parameter), - void *parameter, + void *parameter, rt_uint64_t tick, - rt_uint8_t flag) + rt_uint8_t flag) { /* parameter check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(timeout != RT_NULL); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); - /* timer object initialization */ - rt_object_init(&(timer->parent), RT_Object_Class_Timer, name); - /* set flag */ timer->parent.flag = flag; /* set deactivated */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - timer->timeout_func = timeout; - timer->parameter = parameter; + timer->parameter = parameter; + timer->timeout_tick = tick + clock_cpu_gettime(); + timer->init_tick = tick; - timer->timeout_tick = 0; - timer->init_tick = tick; rt_list_init(&(timer->row)); -} - -static void _set_next_timeout() -{ - struct rt_cputimer *t; - if (&_cputimer_list != _cputimer_list.prev) - { - t = rt_list_entry((&_cputimer_list)->next, struct rt_cputimer, row); - clock_cpu_settimeout(t->timeout_tick, _cputime_timeout, t); - } - else - clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL); + rt_sem_init(&(timer->sem), "cputime", 0, RT_IPC_FLAG_PRIO); } rt_err_t rt_cputimer_delete(rt_cputimer_t timer) @@ -85,8 +94,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer) /* parameter check */ RT_ASSERT(timer != RT_NULL); - RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); - RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); /* disable interrupt */ @@ -99,7 +106,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer) /* enable interrupt */ rt_hw_interrupt_enable(level); - rt_object_delete(&(timer->parent)); _set_next_timeout(); return RT_EOK; @@ -108,11 +114,10 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer) rt_err_t rt_cputimer_start(rt_cputimer_t timer) { rt_list_t *timer_list; - rt_base_t level; + rt_base_t level; /* parameter check */ RT_ASSERT(timer != RT_NULL); - RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); /* stop timer firstly */ @@ -123,8 +128,6 @@ rt_err_t rt_cputimer_start(rt_cputimer_t timer) /* change status of timer */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - timer->timeout_tick = clock_cpu_gettime() + timer->init_tick; - timer_list = &_cputimer_list; for (; timer_list != _cputimer_list.prev; @@ -165,7 +168,6 @@ rt_err_t rt_cputimer_stop(rt_cputimer_t timer) /* timer check */ RT_ASSERT(timer != RT_NULL); - RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) @@ -191,7 +193,6 @@ rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg) /* parameter check */ RT_ASSERT(timer != RT_NULL); - RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); level = rt_hw_interrupt_disable(); @@ -260,8 +261,6 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer) /* parameter check */ RT_ASSERT(timer != RT_NULL); - RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); - RT_ASSERT(rt_object_is_systemobject(&timer->parent)); RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); /* disable interrupt */ @@ -275,52 +274,19 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer) /* enable interrupt */ rt_hw_interrupt_enable(level); - rt_object_detach(&(timer->parent)); + rt_sem_detach(&(timer->sem)); return RT_EOK; } -static void _cputime_sleep_timeout(void *parameter) -{ - struct rt_thread *thread; - rt_base_t level; - - thread = (struct rt_thread *)parameter; - - /* parameter check */ - RT_ASSERT(thread != RT_NULL); - RT_ASSERT((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK); - RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); - - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - - /* set error number */ - thread->error = -RT_ETIMEOUT; - - /* remove from suspend list */ - rt_list_remove(&(thread->tlist)); - - /* insert to schedule ready list */ - rt_schedule_insert_thread(thread); - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - - /* do schedule */ - rt_schedule(); -} - rt_err_t rt_cputime_sleep(rt_uint64_t tick) { - rt_base_t level; - struct rt_thread *thread; + rt_base_t level; struct rt_cputimer cputimer; - int err; if (!clock_cpu_issettimeout()) { - rt_int32_t ms = tick * clock_cpu_getres() / 1000000; + rt_int32_t ms = clock_cpu_millisecond(tick); return rt_thread_delay(rt_tick_from_millisecond(ms)); } @@ -329,53 +295,24 @@ rt_err_t rt_cputime_sleep(rt_uint64_t tick) return -RT_EINVAL; } - /* set to current thread */ - thread = rt_thread_self(); - RT_ASSERT(thread != RT_NULL); - RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); - - /* current context checking */ - RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE); - - rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, thread, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, &(cputimer.sem), tick, + RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); /* disable interrupt */ level = rt_hw_interrupt_disable(); - /* reset thread error */ - thread->error = RT_EOK; - - /* suspend thread */ - err = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE); - - /* reset the timeout of thread timer and start it */ - if (err == RT_EOK) - { - rt_cputimer_control(&cputimer, RT_TIMER_CTRL_SET_TIME, &tick); - rt_cputimer_start(&cputimer); - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - - thread->error = -RT_EINTR; - - rt_schedule(); - if (thread->error == -RT_ETIMEOUT) - thread->error = RT_EOK; - } - else - { - rt_hw_interrupt_enable(level); - } + rt_cputimer_start(&cputimer); /* reset the timeout of thread timer and start it */ + rt_hw_interrupt_enable(level); + rt_sem_take_interruptible(&(cputimer.sem), RT_WAITING_FOREVER); rt_cputimer_detach(&cputimer); - return err; + return RT_EOK; } rt_err_t rt_cputime_ndelay(rt_uint64_t ns) { - double unit = clock_cpu_getres(); - return rt_cputime_sleep(ns / unit); + uint64_t unit = clock_cpu_getres(); + return rt_cputime_sleep(ns * (1000UL * 1000) / unit); } rt_err_t rt_cputime_udelay(rt_uint64_t us) diff --git a/components/drivers/include/drivers/cputime.h b/components/drivers/include/drivers/cputime.h index bbcbe440cc..9c32cd97f8 100644 --- a/components/drivers/include/drivers/cputime.h +++ b/components/drivers/include/drivers/cputime.h @@ -16,12 +16,12 @@ struct rt_clock_cputime_ops { - double (*cputime_getres)(void); + uint64_t (*cputime_getres)(void); uint64_t (*cputime_gettime)(void); int (*cputime_settimeout)(uint64_t tick, void (*timeout)(void *param), void *param); }; -double clock_cpu_getres(void); +uint64_t clock_cpu_getres(void); uint64_t clock_cpu_gettime(void); int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *param); int clock_cpu_issettimeout(void); diff --git a/components/drivers/include/drivers/cputimer.h b/components/drivers/include/drivers/cputimer.h index f15f0c615c..371992a41e 100644 --- a/components/drivers/include/drivers/cputimer.h +++ b/components/drivers/include/drivers/cputimer.h @@ -21,6 +21,7 @@ struct rt_cputimer void *parameter; rt_uint64_t init_tick; rt_uint64_t timeout_tick; + struct rt_semaphore sem; }; typedef struct rt_cputimer *rt_cputimer_t; diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index c1573bf661..88f4560d3c 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -536,9 +536,9 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) return -1; } #ifdef RT_USING_CPUTIME - double unit = clock_cpu_getres(); + rt_uint64_t unit = clock_cpu_getres(); rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; - rt_uint64_t tick = ns / unit; + rt_uint64_t tick = (ns * (1000UL * 1000)) / unit; rt_cputime_sleep(tick); if (rt_get_errno() == -RT_EINTR) @@ -546,8 +546,8 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) if (rmtp) { uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); - rmtp->tv_sec = ((time_t)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND; - rmtp->tv_nsec = ((long)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND; + rmtp->tv_sec = ((time_t)((rmtp_cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; + rmtp->tv_nsec = ((long)((rmtp_cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; } rt_set_errno(EINTR); return -1; @@ -634,7 +634,7 @@ int clock_getres(clockid_t clockid, struct timespec *res) #ifdef RT_USING_CPUTIME case CLOCK_CPUTIME_ID: res->tv_sec = 0; - res->tv_nsec = clock_cpu_getres(); + res->tv_nsec = (clock_cpu_getres() / (1000UL * 1000)); break; #endif @@ -684,14 +684,14 @@ int clock_gettime(clockid_t clockid, struct timespec *tp) case CLOCK_MONOTONIC: case CLOCK_CPUTIME_ID: { - double unit = 0; + uint64_t unit = 0; uint64_t cpu_tick; unit = clock_cpu_getres(); cpu_tick = clock_cpu_gettime(); - tp->tv_sec = ((uint64_t)(cpu_tick * unit)) / NANOSECOND_PER_SECOND; - tp->tv_nsec = ((uint64_t)(cpu_tick * unit)) % NANOSECOND_PER_SECOND; + tp->tv_sec = ((uint64_t)((cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; + tp->tv_nsec = ((uint64_t)((cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; } break; #endif @@ -757,9 +757,9 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s case CLOCK_CPUTIME_ID: { rt_uint64_t cpu_tick_old = clock_cpu_gettime(); - double unit = clock_cpu_getres(); + uint64_t unit = clock_cpu_getres(); rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; - rt_uint64_t tick = ns / unit; + rt_uint64_t tick = (ns * (1000UL * 1000)) / unit; if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) tick -= cpu_tick_old; rt_cputime_sleep(tick); @@ -769,8 +769,8 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s if (rmtp) { uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); - rmtp->tv_sec = ((time_t)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND; - rmtp->tv_nsec = ((long)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND; + rmtp->tv_sec = ((time_t)((rmtp_cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; + rmtp->tv_nsec = ((long)((rmtp_cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; } rt_set_errno(EINTR); return -1; @@ -906,7 +906,7 @@ static void rtthread_timer_wrapper(void *timerobj) #ifdef RT_USING_CPUTIME if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { - timer->reload = (timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) / clock_cpu_getres(); + timer->reload = ((timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) * (1000UL * 1000)) / clock_cpu_getres(); if (timer->reload) rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); } @@ -1174,7 +1174,7 @@ int timer_gettime(timer_t timerid, struct itimerspec *its) rt_uint64_t remain_tick; rt_uint64_t remaining; rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); - remaining = (remain_tick - clock_cpu_gettime()) / clock_cpu_getres(); + remaining = ((remain_tick - clock_cpu_gettime()) * (1000UL * 1000)) / clock_cpu_getres(); seconds = remaining / NANOSECOND_PER_SECOND; nanoseconds = remaining % NANOSECOND_PER_SECOND; } @@ -1278,9 +1278,9 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { rt_uint64_t tick; - double unit = clock_cpu_getres(); + uint64_t unit = clock_cpu_getres(); - tick = (value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) / unit; + tick = ((value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) * (1000UL * 1000)) / unit; if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) { tick -= clock_cpu_gettime();