From 0f85648cfbe5aa0c0158620917a98845811fefc3 Mon Sep 17 00:00:00 2001 From: zhkag Date: Wed, 15 Feb 2023 20:46:22 +0800 Subject: [PATCH] Improve timer accuracy and realize (#6926) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add cputimer frame * add cputime sleep * ctime use cputime * Processing cputime has no timeout function * Migration cputime Code * formatting file * 整理代码 * add document copyright information * 改 cputime_timer 为 cputimer * 简化 _cputimer_list 初始化 * rt_cputimer_create -> rt_cputimer_init * Remove RT_USING_CPUTIME and code cleanup. * Remove RT_USING_CPUTIME in cputimer.c * Set set_next_timeout as static function. --------- Co-authored-by: Bernard Xiong --- components/drivers/cputime/SConscript | 1 + components/drivers/cputime/cputime.c | 7 + components/drivers/cputime/cputimer.c | 388 ++++++++++++++++++ components/drivers/include/drivers/cputime.h | 2 + components/drivers/include/drivers/cputimer.h | 47 +++ components/libc/compilers/common/ctime.c | 243 +++++++---- 6 files changed, 607 insertions(+), 81 deletions(-) create mode 100644 components/drivers/cputime/cputimer.c create mode 100644 components/drivers/include/drivers/cputimer.h diff --git a/components/drivers/cputime/SConscript b/components/drivers/cputime/SConscript index e1b447e16b..9fec4641e5 100644 --- a/components/drivers/cputime/SConscript +++ b/components/drivers/cputime/SConscript @@ -4,6 +4,7 @@ cwd = GetCurrentDir() CPPPATH = [cwd + '/../include'] src = Split(''' cputime.c +cputimer.c ''') if GetDepend('RT_USING_CPUTIME_CORTEXM'): diff --git a/components/drivers/cputime/cputime.c b/components/drivers/cputime/cputime.c index 97fbc328fe..d87e39199c 100644 --- a/components/drivers/cputime/cputime.c +++ b/components/drivers/cputime/cputime.c @@ -61,6 +61,13 @@ int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *para return 0; } +int clock_cpu_issettimeout(void) +{ + if (_cputime_ops) + return _cputime_ops->cputime_settimeout != RT_NULL; + return RT_FALSE; +} + /** * The clock_cpu_microsecond() fucntion shall return the microsecond according to * cpu_tick parameter. diff --git a/components/drivers/cputime/cputimer.c b/components/drivers/cputime/cputimer.c new file mode 100644 index 0000000000..27e64a1354 --- /dev/null +++ b/components/drivers/cputime/cputimer.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-13 zhkag first version + */ + +#include +#include +#include + +static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list); + +static void _cputime_timeout(void *parameter) +{ + struct rt_cputimer *timer; + timer = (struct rt_cputimer *)parameter; + timer->timeout_func(timer->parameter); + rt_list_remove(&timer->row); + + 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); + } + 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); + } +} + +void rt_cputimer_init(rt_cputimer_t timer, + const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_uint64_t tick, + 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->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_err_t rt_cputimer_delete(rt_cputimer_t timer) +{ + 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(rt_object_is_systemobject(&timer->parent) == RT_FALSE); + RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + rt_list_remove(&timer->row); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_object_delete(&(timer->parent)); + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_cputimer_start(rt_cputimer_t timer) +{ + rt_list_t *timer_list; + 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 */ + level = rt_hw_interrupt_disable(); + /* remove timer from list */ + + rt_list_remove(&timer->row); + /* 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; + timer_list = timer_list->next) + { + struct rt_cputimer *t; + rt_list_t *p = timer_list->next; + + t = rt_list_entry(p, struct rt_cputimer, row); + + if ((t->timeout_tick - timer->timeout_tick) == 0) + { + continue; + } + else if ((t->timeout_tick - timer->timeout_tick) < 0x7fffffffffffffff) + { + break; + } + } + + rt_list_insert_after(timer_list, &(timer->row)); + + timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; + + _set_next_timeout(); + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t rt_cputimer_stop(rt_cputimer_t timer) +{ + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* 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)) + { + rt_hw_interrupt_enable(level); + return -RT_ERROR; + } + + rt_list_remove(&timer->row); + /* change status */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + + _set_next_timeout(); + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg) +{ + 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); + + level = rt_hw_interrupt_disable(); + switch (cmd) + { + case RT_TIMER_CTRL_GET_TIME: + *(rt_uint64_t *)arg = timer->init_tick; + break; + + case RT_TIMER_CTRL_SET_TIME: + RT_ASSERT((*(rt_uint64_t *)arg) < 0x7fffffffffffffff); + timer->init_tick = *(rt_uint64_t *)arg; + break; + + case RT_TIMER_CTRL_SET_ONESHOT: + timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; + break; + + case RT_TIMER_CTRL_SET_PERIODIC: + timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; + break; + + case RT_TIMER_CTRL_GET_STATE: + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + /*timer is start and run*/ + *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED; + } + else + { + /*timer is stop*/ + *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED; + } + break; + + case RT_TIMER_CTRL_GET_REMAIN_TIME: + *(rt_uint64_t *)arg = timer->timeout_tick; + break; + case RT_TIMER_CTRL_GET_FUNC: + arg = (void *)timer->timeout_func; + break; + + case RT_TIMER_CTRL_SET_FUNC: + timer->timeout_func = (void (*)(void *))arg; + break; + + case RT_TIMER_CTRL_GET_PARM: + *(void **)arg = timer->parameter; + break; + + case RT_TIMER_CTRL_SET_PARM: + timer->parameter = arg; + break; + + default: + break; + } + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t rt_cputimer_detach(rt_cputimer_t timer) +{ + 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(rt_object_is_systemobject(&timer->parent)); + RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + rt_list_remove(&timer->row); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + + _set_next_timeout(); + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_object_detach(&(timer->parent)); + + 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; + struct rt_cputimer cputimer; + int err; + + if (!clock_cpu_issettimeout()) + { + rt_int32_t ms = tick * clock_cpu_getres() / 1000000; + return rt_thread_delay(rt_tick_from_millisecond(ms)); + } + + if (tick == 0) + { + 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); + + /* 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_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, thread, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + 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(); + rt_cputimer_detach(&cputimer); + if (thread->error == -RT_ETIMEOUT) + thread->error = RT_EOK; + } + else + { + rt_hw_interrupt_enable(level); + } + + return err; +} + +rt_err_t rt_cputime_ndelay(rt_uint64_t ns) +{ + double unit = clock_cpu_getres(); + return rt_cputime_sleep(ns / unit); +} + +rt_err_t rt_cputime_udelay(rt_uint64_t us) +{ + return rt_cputime_ndelay(us * 1000); +} + +rt_err_t rt_cputime_mdelay(rt_uint64_t ms) +{ + return rt_cputime_ndelay(ms * 1000000); +} diff --git a/components/drivers/include/drivers/cputime.h b/components/drivers/include/drivers/cputime.h index 665c89fb68..bbcbe440cc 100644 --- a/components/drivers/include/drivers/cputime.h +++ b/components/drivers/include/drivers/cputime.h @@ -12,6 +12,7 @@ #define CPUTIME_H__ #include +#include "cputimer.h" struct rt_clock_cputime_ops { @@ -23,6 +24,7 @@ struct rt_clock_cputime_ops double 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); uint64_t clock_cpu_microsecond(uint64_t cpu_tick); uint64_t clock_cpu_millisecond(uint64_t cpu_tick); diff --git a/components/drivers/include/drivers/cputimer.h b/components/drivers/include/drivers/cputimer.h new file mode 100644 index 0000000000..f15f0c615c --- /dev/null +++ b/components/drivers/include/drivers/cputimer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-13 zhkag first version + */ + +#ifndef CPUTIMER_H__ +#define CPUTIMER_H__ + +#include + +struct rt_cputimer +{ + struct rt_object parent; /**< inherit from rt_object */ + rt_list_t row; + void (*timeout_func)(void *parameter); + void *parameter; + rt_uint64_t init_tick; + rt_uint64_t timeout_tick; +}; +typedef struct rt_cputimer *rt_cputimer_t; + +rt_err_t rt_cputimer_detach(rt_cputimer_t timer); + +#ifdef RT_USING_HEAP +void rt_cputimer_init(rt_cputimer_t timer, + const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_uint64_t tick, + rt_uint8_t flag); +rt_err_t rt_cputimer_delete(rt_cputimer_t timer); +#endif + +rt_err_t rt_cputimer_start(rt_cputimer_t timer); +rt_err_t rt_cputimer_stop(rt_cputimer_t timer); +rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg); +rt_err_t rt_cputime_sleep(rt_uint64_t tick); +rt_err_t rt_cputime_ndelay(rt_uint64_t ns); +rt_err_t rt_cputime_udelay(rt_uint64_t us); +rt_err_t rt_cputime_mdelay(rt_uint64_t ms); + +#endif diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index 8a6767e194..7e182b5ba9 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2022, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -32,7 +32,7 @@ #ifdef RT_USING_POSIX_DELAY #include #endif -#ifdef RT_USING_RTC +#if defined( RT_USING_RTC ) || defined( RT_USING_CPUTIME) #include #endif @@ -535,28 +535,22 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) return -1; } #ifdef RT_USING_CPUTIME - uint64_t cpu_tick, cpu_tick_old; - cpu_tick_old = clock_cpu_gettime(); - rt_tick_t tick; double unit = clock_cpu_getres(); - - cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / NANOSECOND_PER_SECOND) / unit; - tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); - rt_thread_delay(tick); + rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; + rt_uint64_t tick = ns / unit; + rt_cputime_sleep(tick); if (rt_get_errno() == -RT_EINTR) { if (rmtp) { - uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime(); + 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; } rt_set_errno(EINTR); return -1; } - else - while (clock_cpu_gettime() - cpu_tick_old < cpu_tick); #else rt_tick_t tick, tick_old = rt_tick_get(); tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; @@ -761,30 +755,25 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s case CLOCK_MONOTONIC: case CLOCK_CPUTIME_ID: { - uint64_t cpu_tick, cpu_tick_old; - cpu_tick_old = clock_cpu_gettime(); - rt_tick_t tick; + rt_uint64_t cpu_tick_old = clock_cpu_gettime(); double unit = clock_cpu_getres(); - - cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec * (NANOSECOND_PER_SECOND / NANOSECOND_PER_SECOND)) / unit; + rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; + rt_uint64_t tick = ns / unit; if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old; - tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); - rt_thread_delay(tick); + tick -= cpu_tick_old; + rt_cputime_sleep(tick); if (rt_get_errno() == -RT_EINTR) { if (rmtp) { - uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime(); + 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; } rt_set_errno(EINTR); return -1; } - else - while (clock_cpu_gettime() - cpu_tick_old < cpu_tick); } break; #endif @@ -882,14 +871,21 @@ RTM_EXPORT(rt_timespec_to_tick); struct timer_obj { - struct rt_timer timer; + union + { + struct rt_timer timer; +#ifdef RT_USING_CPUTIME + struct rt_cputimer cputimer; +#endif + }; void (*sigev_notify_function)(union sigval val); union sigval val; struct timespec interval; /* Reload value */ struct timespec value; /* Reload value */ - rt_uint32_t reload; /* Reload value in ms */ + rt_uint64_t reload; /* Reload value in ms */ rt_uint32_t status; int sigev_signo; + clockid_t clockid; #ifdef RT_USING_SMART pid_t pid; #endif @@ -906,9 +902,20 @@ static void rtthread_timer_wrapper(void *timerobj) timer->status = NOT_ACTIVE; } - timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; - if (timer->reload) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); +#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(); + if (timer->reload) + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + } + else +#endif /* RT_USING_CPUTIME */ + { + timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; + if (timer->reload) + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + } #ifdef RT_USING_SMART sys_kill(timer->pid, timer->sigev_signo); @@ -1024,14 +1031,20 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) timer->interval.tv_nsec = 0; timer->reload = 0U; timer->status = NOT_ACTIVE; + timer->clockid = clockid; - if (evp->sigev_notify == SIGEV_NONE) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { - rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + rt_cputimer_init(&timer->cputimer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); } else +#endif /* RT_USING_CPUTIME */ { - rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + if (evp->sigev_notify == SIGEV_NONE) + rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); + else + rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); } timer_id_lock(); @@ -1069,19 +1082,32 @@ int timer_delete(timer_t timerid) timer = _g_timerid[(rt_ubase_t)timerid]; timer_id_put((rt_ubase_t)timerid); timer_id_unlock(); - - if (timer == RT_NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer) + if (timer == RT_NULL) { rt_set_errno(EINVAL); return -1; } - if (timer->status == ACTIVE) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { - timer->status = NOT_ACTIVE; - rt_timer_stop(&timer->timer); + if (timer->status == ACTIVE) + { + timer->status = NOT_ACTIVE; + rt_cputimer_stop(&timer->cputimer); + } + rt_cputimer_detach(&timer->cputimer); + } + else +#endif /* RT_USING_CPUTIME */ + { + if (timer->status == ACTIVE) + { + timer->status = NOT_ACTIVE; + rt_timer_stop(&timer->timer); + } + rt_timer_detach(&timer->timer); } - rt_timer_detach(&timer->timer); rt_free(timer); return 0; @@ -1107,10 +1133,9 @@ int timer_getoverrun(timer_t timerid) int timer_gettime(timer_t timerid, struct itimerspec *its) { struct timer_obj *timer = timer_id_get((rt_ubase_t)timerid); - rt_tick_t remaining; rt_uint32_t seconds, nanoseconds; - if (timer == NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer) + if (timer == NULL) { rt_set_errno(EINVAL); return -1; @@ -1124,31 +1149,45 @@ int timer_gettime(timer_t timerid, struct itimerspec *its) if (timer->status == ACTIVE) { - rt_tick_t remain_tick; +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + 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(); + seconds = remaining / NANOSECOND_PER_SECOND; + nanoseconds = remaining % NANOSECOND_PER_SECOND; + } + else +#endif /* RT_USING_CPUTIME */ + { + rt_tick_t remain_tick; + rt_tick_t remaining; - rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); + rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); - /* 'remain_tick' is minimum-unit in the RT-Thread' timer, - * so the seconds, nanoseconds will be calculated by 'remain_tick'. - */ - remaining = remain_tick - rt_tick_get(); + /* 'remain_tick' is minimum-unit in the RT-Thread' timer, + * so the seconds, nanoseconds will be calculated by 'remain_tick'. + */ + remaining = remain_tick - rt_tick_get(); - /* calculate 'second' */ - seconds = remaining / RT_TICK_PER_SECOND; - - /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. - * - * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND - * ------------------------- = -------------------------- ---> millisecond = ------------------------------------------- - * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND - * - * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND - * millisecond = ---------------------------------------- ---> nanosecond = ------------------------------------------------------------------- - * RT_TICK_PER_SECOND RT_TICK_PER_SECOND - * - */ - nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND ; + /* calculate 'second' */ + seconds = remaining / RT_TICK_PER_SECOND; + /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. + * + * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND + * ------------------------- = -------------------------- ---> millisecond = ------------------------------------------- + * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND + * + * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND + * millisecond = ---------------------------------------- ---> nanosecond = ------------------------------------------------------------------- + * RT_TICK_PER_SECOND RT_TICK_PER_SECOND + * + */ + nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND; + } its->it_value.tv_sec = (rt_int32_t)seconds; its->it_value.tv_nsec = (rt_int32_t)nanoseconds; } @@ -1175,7 +1214,6 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, { struct timer_obj *timer = timer_id_get((rt_ubase_t)timerid); if (timer == NULL || - rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer || value->it_interval.tv_nsec < 0 || value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND || value->it_interval.tv_sec < 0 || @@ -1198,7 +1236,12 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, { if (timer->status == ACTIVE) { - rt_timer_stop(&timer->timer); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + rt_cputimer_stop(&timer->cputimer); + else +#endif /* RT_USING_CPUTIME */ + rt_timer_stop(&timer->timer); } timer->status = NOT_ACTIVE; @@ -1212,21 +1255,39 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, * RT_TICK_PER_SECOND NANOSECOND_PER_SECOND NANOSECOND_PER_SECOND * */ - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) { -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; -#else - rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); - rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); - rt_int64_t reload = ts + tns; - rt_tick_t rt_tick = rt_tick_get(); - timer->reload = reload < rt_tick ? 0 : reload - rt_tick; -#endif + rt_uint64_t tick; + double unit = clock_cpu_getres(); + + tick = (value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) / unit; + if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) + { + tick -= clock_cpu_gettime(); + } + timer->reload = tick; } else - timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); +#endif /* RT_USING_CPUTIME */ + { + if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) + { +#ifndef RT_USING_RTC + LOG_W(_WARNING_NO_RTC); + return -1; +#else + rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); + rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); + rt_int64_t reload = ts + tns; + rt_tick_t rt_tick = rt_tick_get(); + + timer->reload = reload < rt_tick ? 0 : reload - rt_tick; +#endif + } + else + timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); + } timer->interval.tv_sec = value->it_interval.tv_sec; timer->interval.tv_nsec = value->it_interval.tv_nsec; timer->value.tv_sec = value->it_value.tv_sec; @@ -1234,18 +1295,38 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, if (timer->status == ACTIVE) { - rt_timer_stop(&timer->timer); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + rt_cputimer_stop(&timer->cputimer); + else +#endif /* RT_USING_CPUTIME */ + rt_timer_stop(&timer->timer); } timer->status = ACTIVE; - if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); - else - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); +#ifdef RT_USING_CPUTIME + if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + { + if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); + else + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); - rt_timer_start(&timer->timer); + rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_cputimer_start(&timer->cputimer); + } + else +#endif /* RT_USING_CPUTIME */ + { + if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); + else + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); + + rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_timer_start(&timer->timer); + } return 0; }