diff options
| author | xqyjlj <[email protected]> | 2023-07-17 20:11:58 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-07-17 20:11:58 +0800 |
| commit | 0eb75ced70a514051fcc6a8f1d232e195b15b4a0 (patch) | |
| tree | a025fe349198fa0fe6f972ea1100ac31ba64787a /components/ktime/src | |
| parent | b424169e1742c1b19d039f9871dd3c672ea7b729 (diff) | |
[time]时钟框架重构 (#7794)
Diffstat (limited to 'components/ktime/src')
| -rw-r--r-- | components/ktime/src/aarch64/cputimer.c | 32 | ||||
| -rw-r--r-- | components/ktime/src/boottime.c | 51 | ||||
| -rw-r--r-- | components/ktime/src/cputimer.c | 31 | ||||
| -rw-r--r-- | components/ktime/src/hrtimer.c | 382 | ||||
| -rw-r--r-- | components/ktime/src/risc-v/virt64/cputimer.c | 33 |
5 files changed, 529 insertions, 0 deletions
diff --git a/components/ktime/src/aarch64/cputimer.c b/components/ktime/src/aarch64/cputimer.c new file mode 100644 index 0000000000..53c60736d4 --- /dev/null +++ b/components/ktime/src/aarch64/cputimer.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "gtimer.h" +#include "ktime.h" + +unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq(); +} + +unsigned long rt_ktime_cputimer_getfrq(void) +{ + return rt_hw_get_gtimer_frq(); +} + +unsigned long rt_ktime_cputimer_getcnt(void) +{ + return rt_hw_get_cntpct_val(); +} + +unsigned long rt_ktime_cputimer_getstep(void) +{ + return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND; +} diff --git a/components/ktime/src/boottime.c b/components/ktime/src/boottime.c new file mode 100644 index 0000000000..9d05266d71 --- /dev/null +++ b/components/ktime/src/boottime.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +#define __KTIME_MUL ((1000UL * 1000 * 1000) / RT_TICK_PER_SECOND) + +rt_err_t rt_ktime_boottime_get_us(struct timeval *tv) +{ + RT_ASSERT(tv != RT_NULL); + + rt_tick_t ms = rt_tick_get(); + unsigned long ns = + ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL; + ns = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns; + + tv->tv_sec = ms / RT_TICK_PER_SECOND; + tv->tv_usec = ns / 1000; + + return RT_EOK; +} + +rt_err_t rt_ktime_boottime_get_s(time_t *t) +{ + RT_ASSERT(t != RT_NULL); + + *t = rt_tick_get() / RT_TICK_PER_SECOND; + + return RT_EOK; +} + +rt_err_t rt_ktime_boottime_get_ns(struct timespec *ts) +{ + RT_ASSERT(ts != RT_NULL); + + rt_tick_t ms = rt_tick_get(); + unsigned long ns = + ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL; + + ts->tv_sec = ms / RT_TICK_PER_SECOND; + ts->tv_nsec = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns; + + return RT_EOK; +} diff --git a/components/ktime/src/cputimer.c b/components/ktime/src/cputimer.c new file mode 100644 index 0000000000..c878581cdf --- /dev/null +++ b/components/ktime/src/cputimer.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +rt_weak unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_cputimer_getfrq(void) +{ + return RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_cputimer_getcnt(void) +{ + return rt_tick_get(); +} + +rt_weak unsigned long rt_ktime_cputimer_getstep(void) +{ + return 1; +} diff --git a/components/ktime/src/hrtimer.c b/components/ktime/src/hrtimer.c new file mode 100644 index 0000000000..81954c3e00 --- /dev/null +++ b/components/ktime/src/hrtimer.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include <rtdevice.h> +#include <rthw.h> +#include <rtthread.h> + +#include "ktime.h" + +#ifdef ARCH_CPU_64BIT +#define _HRTIMER_MAX_CNT UINT64_MAX +#else +#define _HRTIMER_MAX_CNT UINT32_MAX +#endif + +static rt_list_t _timer_list = RT_LIST_OBJECT_INIT(_timer_list); +static rt_ktime_hrtimer_t _nowtimer = RT_NULL; +static struct rt_spinlock _spinlock; + +rt_weak unsigned long rt_ktime_hrtimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_hrtimer_getfrq(void) +{ + return RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_hrtimer_getcnt(void) +{ + return rt_tick_get(); +} + +static void (*_outcb)(void *param) = RT_NULL; + +static void _hrtimer_timeout(void *parameter) +{ + if (_outcb) + _outcb(parameter); +} + +rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param) +{ + static rt_timer_t timer = RT_NULL; + + if (timer == RT_NULL) + { + timer = rt_timer_create("shrtimer", _hrtimer_timeout, param, cnt, RT_TIMER_FLAG_ONE_SHOT); + } + else + { + rt_tick_t tick = cnt; + rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, param); + } + + _outcb = timeout; + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + rt_timer_stop(timer); + } + rt_timer_start(timer); + return RT_EOK; +} + +/** + * @brief convert cnt from cputimer cnt to hrtimer cnt + * + * @param cnt + * @return unsigned long + */ +static unsigned long _cnt_convert(unsigned long cnt) +{ + int64_t count = cnt - rt_ktime_cputimer_getcnt(); + if (count <= 0) + return 0; + + return (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres(); +} + +static void _sleep_timeout(void *parameter) +{ + struct rt_semaphore *sem; + sem = (struct rt_semaphore *)parameter; + rt_sem_release(sem); +} + +static void _set_next_timeout(void); +static void _timeout_callback(void *parameter) +{ + rt_ktime_hrtimer_t timer; + timer = (rt_ktime_hrtimer_t)parameter; + rt_base_t level; + + level = rt_spin_lock_irqsave(&_spinlock); + _nowtimer = RT_NULL; + rt_list_remove(&(timer->row)); + rt_spin_unlock_irqrestore(&_spinlock, level); + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + timer->timeout_func(timer->parameter); + } + + _set_next_timeout(); +} + +static void _set_next_timeout(void) +{ + rt_ktime_hrtimer_t t; + rt_base_t level; + + if (&_timer_list != _timer_list.prev) + { + level = rt_spin_lock_irqsave(&_spinlock); + t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row); + if (_nowtimer != RT_NULL) + { + if (t != _nowtimer && t->timeout_cnt < _nowtimer->timeout_cnt) + { + _nowtimer = t; + rt_spin_unlock_irqrestore(&_spinlock, level); + rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t); + } + else + { + rt_spin_unlock_irqrestore(&_spinlock, level); + } + } + else + { + _nowtimer = t; + rt_spin_unlock_irqrestore(&_spinlock, level); + rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t); + } + } + else + { + _nowtimer = RT_NULL; + rt_ktime_hrtimer_settimeout(RT_NULL, RT_NULL, RT_NULL); + } +} + +void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer, + const char *name, + unsigned long cnt, + rt_uint8_t flag, + void (*timeout)(void *parameter), + void *parameter) +{ + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(timeout != RT_NULL); + RT_ASSERT(cnt < (_HRTIMER_MAX_CNT / 2)); + + /* set flag */ + timer->parent.flag = flag; + + /* set deactivated */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + timer->timeout_func = timeout; + timer->parameter = parameter; + timer->timeout_cnt = cnt + rt_ktime_cputimer_getcnt(); + timer->init_cnt = cnt; + + rt_list_init(&(timer->row)); + rt_sem_init(&(timer->sem), "hrtimer", 0, RT_IPC_FLAG_PRIO); +} + +rt_err_t rt_ktime_hrtimer_delete(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* stop timer */ + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer) +{ + rt_list_t *timer_list; + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); /* remove timer from list */ + /* change status of timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + timer_list = &_timer_list; + for (; timer_list != _timer_list.prev; timer_list = timer_list->next) + { + rt_ktime_hrtimer_t t; + rt_list_t *p = timer_list->next; + + t = rt_list_entry(p, struct rt_ktime_hrtimer, row); + + if ((t->timeout_cnt - timer->timeout_cnt) == 0) + { + continue; + } + else if ((t->timeout_cnt - timer->timeout_cnt) < (_HRTIMER_MAX_CNT / 2)) + { + break; + } + } + rt_list_insert_after(timer_list, &(timer->row)); + timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + RT_ASSERT(timer != RT_NULL); /* timer check */ + + level = rt_spin_lock_irqsave(&_spinlock); + if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + rt_spin_unlock_irqrestore(&_spinlock, level); + return -RT_ERROR; + } + rt_list_remove(&timer->row); + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* change status */ + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + switch (cmd) + { + case RT_TIMER_CTRL_GET_TIME: + *(unsigned long *)arg = timer->init_cnt; + break; + + case RT_TIMER_CTRL_SET_TIME: + RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2)); + timer->init_cnt = *(unsigned long *)arg; + timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt(); + 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: + *(unsigned long *)arg = timer->timeout_cnt; + 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_spin_unlock_irqrestore(&_spinlock, level); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + rt_sem_detach(&(timer->sem)); + + return RT_EOK; +} + +/************************** delay ***************************/ + +rt_err_t rt_ktime_hrtimer_sleep(unsigned long cnt) +{ + struct rt_ktime_hrtimer timer; + + if (cnt == 0) + return -RT_EINVAL; + + rt_ktime_hrtimer_init(&timer, "hrtimer_sleep", cnt, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER, + _sleep_timeout, &(timer.sem)); + + rt_ktime_hrtimer_start(&timer); /* reset the timeout of thread timer and start it */ + rt_sem_take_interruptible(&(timer.sem), RT_WAITING_FOREVER); + + rt_ktime_hrtimer_detach(&timer); + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_ndelay(unsigned long ns) +{ + unsigned long res = rt_ktime_cputimer_getres(); + return rt_ktime_hrtimer_sleep((ns * RT_KTIME_RESMUL) / res); +} + +rt_err_t rt_ktime_hrtimer_udelay(unsigned long us) +{ + return rt_ktime_hrtimer_ndelay(us * 1000); +} + +rt_err_t rt_ktime_hrtimer_mdelay(unsigned long ms) +{ + return rt_ktime_hrtimer_ndelay(ms * 1000000); +} + +static int rt_ktime_hrtimer_lock_init(void) +{ + RT_UNUSED(_spinlock); + rt_spin_lock_init(&_spinlock); + return 0; +} +INIT_BOARD_EXPORT(rt_ktime_hrtimer_lock_init); diff --git a/components/ktime/src/risc-v/virt64/cputimer.c b/components/ktime/src/risc-v/virt64/cputimer.c new file mode 100644 index 0000000000..9b0f754751 --- /dev/null +++ b/components/ktime/src/risc-v/virt64/cputimer.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / CPUTIME_TIMER_FREQ; +} + +unsigned long rt_ktime_cputimer_getfrq(void) +{ + return CPUTIME_TIMER_FREQ; +} + +unsigned long rt_ktime_cputimer_getcnt(void) +{ + unsigned long time_elapsed; + __asm__ __volatile__("rdtime %0" : "=r"(time_elapsed)); + return time_elapsed; +} + +unsigned long rt_ktime_cputimer_getstep(void) +{ + return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND; +} |
