确切地说,这部分和之前分析的定时器关系不大,但是由于其实现逻辑和定时器比较类似,因此在分析时也就同步看了。
代码入口
components\drivers\ktime
代码分析
确切的说,ktime模块分为3个组成部分,一个部分叫boottime,可以理解为启动后经历的时间相关的功能。另一个叫cputime,用于系统滴答时钟方式的计时相关功能,最后一个叫hrtime,粗看实现是利用硬件定时器实现的us级精度的延时,休眠等控制,但还需要详细分析。
cputime源码分析
cputime的实现很依赖芯片架构,从目前开源出来的代码看,只有支持aarch64和virt64两种架构的芯片可以使用该模块,而如果是非这两种架构的芯片,cputime也会利用系统的滴答时钟进行计时,但此计时的精度就没那么高了。出于简化分析的考量,后面的分析仅针对aarch64架构源码进行分析。
初始化入口
.globl rt_hw_get_cntpct_val
rt_hw_get_cntpct_val:
MRS X0, CNTPCT_EL0
RET
static volatile unsigned long _init_cnt = 0;
// aarch64架构实现
void rt_ktime_cputimer_init(void)
{
_init_cnt = rt_hw_get_cntpct_val();
}
// 通用入口
rt_weak void rt_ktime_cputimer_init(void)
{
return;
}从实现上看,aarch64的cputimer初始化部分仅仅是读取了当前的芯片系统的滴答值并保存。
获取当前计数值入口
unsigned long rt_ktime_cputimer_getcnt(void)
{
return rt_hw_get_cntpct_val() - _init_cnt;
}
// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getcnt(void)
{
return rt_tick_get();
}可以很明显的看到,在初始化时读到的计数值,是用于初始化计数的部分。也就是说,在调用了rt_ktime_cputimer_init才开始从0往上计数。
获取滴答频率入口
.globl rt_hw_get_gtimer_frq
rt_hw_get_gtimer_frq:
MRS X0,CNTFRQ_EL0
RET
unsigned long rt_ktime_cputimer_getfrq(void)
{
return rt_hw_get_gtimer_frq();
}
// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getfrq(void)
{
return RT_TICK_PER_SECOND;
}这个接口也就是直接读取芯片的滴答频率并上报。
获取步进值入口
// aarch64架构实现
unsigned long rt_ktime_cputimer_getstep(void)
{
return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND;
}
// 通用入口
rt_weak unsigned long rt_ktime_cputimer_getstep(void)
{
return 1;
}获取定时器的分辨率
#define RT_KTIME_RESMUL (1000000UL)
unsigned long rt_ktime_cputimer_getres(void)
{
return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq();
}
// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getres(void)
{
return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}boottime分析
从功能上看,bootime实现的功能是获取启动后所经过的时间,其精度分为s,us和ns。而在实现上,boottime的实现是基于cputime的实现而实现的。
获取秒级计时入口
rt_weak rt_err_t rt_ktime_boottime_get_s(time_t *t)
{
RT_ASSERT(t != RT_NULL);
unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;
*t = ns / (1000UL * 1000 * 1000);
return RT_EOK;
}获取微妙级计时入口
rt_weak rt_err_t rt_ktime_boottime_get_us(struct timeval *tv)
{
RT_ASSERT(tv != RT_NULL);
unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;
tv->tv_sec = ns / (1000UL * 1000 * 1000);
tv->tv_usec = (ns % (1000UL * 1000 * 1000)) / 1000;
return RT_EOK;
}获取纳秒级计时入口
hrtime分析
从hrtime暴露出来的接口看,此模块最主要的功能是实现us,ns和ms级别的延时。而其用法可以在nanosleep中看到,具体如下:
#if defined(RT_USING_POSIX_DELAY) && defined(RT_USING_KTIME)
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
struct timespec old_ts = {0};
struct timespec new_ts = {0};
struct rt_ktime_hrtimer timer;
// 初始化结构体timer
rt_ktime_hrtimer_delay_init(&timer);
if (rqtp == RT_NULL)
{
rt_set_errno(EFAULT);
return -1;
}
if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
{
rt_set_errno(EINVAL);
return -1;
}
unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec;
rt_ktime_boottime_get_ns(&old_ts); // 获取ns精度的启动计时
rt_ktime_hrtimer_ndelay(&timer, ns); // 休眠ns的时长
if (rt_get_errno() == RT_EINTR)
{ // 如果是中断中返回,则说明是执行异常,此时通过rmtp将已执行的时间向上报,以便上层做后续处理
// 并销毁timer运行时占用的资源
if (rmtp)
{
rt_base_t rsec, rnsec;
rt_ktime_boottime_get_ns(&new_ts);
rsec = old_ts.tv_sec + rqtp->tv_sec - new_ts.tv_sec;
rnsec = old_ts.tv_nsec + rqtp->tv_nsec - new_ts.tv_nsec;
if (rnsec < 0)
{
rmtp->tv_sec = rsec - 1;
rmtp->tv_nsec = NANOSECOND_PER_SECOND + rnsec;
}
else
{
rmtp->tv_sec = rsec;
rmtp->tv_nsec = rnsec;
}
}
rt_ktime_hrtimer_delay_detach(&timer);
rt_set_errno(EINTR);
return -1;
}
// 销毁timer运行时所产生的资源
rt_ktime_hrtimer_delay_detach(&timer);
return 0;
}
RTM_EXPORT(nanosleep);
#endif /* RT_USING_POSIX_DELAY && RT_USING_KTIME */rt_ktime_hrtimer_delay_init
static void _sleep_timeout(void *parameter)
{ // 超时后通过完成量唤醒任务,通过nanosleep的实现看,
// 这个等待完成量的操作就在函数rt_ktime_hrtimer_ndelay中执行
struct rt_ktime_hrtimer *timer = parameter;
rt_completion_done(&timer->completion);
}
// 仅仅是做了资源的初始化,并未做具体功能的执行
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_completion_init(&timer->completion);
}
void rt_ktime_hrtimer_delay_init(struct rt_ktime_hrtimer *timer)
{ // 可以发现,nanosleep的执行,依赖系统滴答时钟,本质上属于系统调度的一部分
rt_ktime_hrtimer_init(timer, "hrtimer_sleep", 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
_sleep_timeout, timer);
}rt_ktime_hrtimer_sleep
其实对外暴露的并不是这个入口,而是rt_ktime_hrtimer_ndelay,rt_ktime_hrtimer_udelay和rt_ktime_hrtimer_mdelay,但奈何这三个函数的实现,本质上都是rt_ktime_hrtimer_sleep,因此这里也就分析此函数了。
对外暴露的延时函数实现
会发现三个函数本质上都是基于rt_ktime_hrtimer_sleep实现的。
rt_err_t rt_ktime_hrtimer_ndelay(struct rt_ktime_hrtimer *timer, unsigned long ns)
{
unsigned long res = rt_ktime_cputimer_getres();
return rt_ktime_hrtimer_sleep(timer, (ns * RT_KTIME_RESMUL) / res);
}
rt_err_t rt_ktime_hrtimer_udelay(struct rt_ktime_hrtimer *timer, unsigned long us)
{
return rt_ktime_hrtimer_ndelay(timer, us * 1000);
}
rt_err_t rt_ktime_hrtimer_mdelay(struct rt_ktime_hrtimer *timer, unsigned long ms)
{
return rt_ktime_hrtimer_ndelay(timer, ms * 1000000);
}rt_ktime_hrtimer_sleep
#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 RT_DEFINE_SPINLOCK(_spinlock);
rt_weak unsigned long rt_ktime_hrtimer_getres(void)
{
return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}
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;
_outcb = timeout;
if (cnt == 0)
{
if (timer != RT_NULL)
{
if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
{
rt_timer_stop(timer);
}
}
if (_outcb)
_outcb(param);
return RT_EOK;
}
if (timer == RT_NULL)
{ // 从此处可以发现,其实ktime的实现是依赖系统调度定时器实现的
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);
}
if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
{
rt_timer_stop(timer);
}
rt_timer_start(timer);
return RT_EOK;
}
// 将计数值换算成实际滴答周期数
static unsigned long _cnt_convert(unsigned long cnt)
{
unsigned long rtn = 0;
unsigned long count = cnt - rt_ktime_cputimer_getcnt();
if (count > (_HRTIMER_MAX_CNT / 2))
return 0;
rtn = (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres();
return rtn == 0 ? 1 : rtn; /* at least 1 */
}
static void _set_next_timeout_n_unlock(rt_base_t level)
{
rt_ktime_hrtimer_t t;
if (&_timer_list != _timer_list.prev)
{ // 如果列表非空,则说明存在定时器,此时需要启用定时器
t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row);
if (_nowtimer != RT_NULL)
{ // 如果当前已有定时器在执行,则判断新插入的定时器是否比已有定时器更早执行
// 若有,则将_nowtimer替换成新插入的定时器并执行
// 否则直接启用定时器
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_spin_unlock_irqrestore(&_spinlock, level);
rt_ktime_hrtimer_settimeout(0, RT_NULL, RT_NULL);
}
}
rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer)
{
rt_list_t *timer_list;
rt_base_t level;
/* 检查定时器 */
RT_ASSERT(timer != RT_NULL);
level = rt_spin_lock_irqsave(&_spinlock);
rt_list_remove(&timer->row); /* 将定时器从定时器执行列表中移除 */
/* 禁用定时器 */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
/* 从已有定时器列表中插入timer(列表时间从小到大排列)*/
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;
// 设置下一次定时器超时解锁时间
_set_next_timeout_n_unlock(level);
return RT_EOK;
}
// 记录执行结果
rt_inline void rt_ktime_hrtimer_keep_errno(rt_ktime_hrtimer_t timer, rt_err_t err)
{
RT_ASSERT(timer != RT_NULL);
timer->error = err;
rt_set_errno(-err);
}
rt_err_t rt_ktime_hrtimer_sleep(struct rt_ktime_hrtimer *timer, unsigned long cnt)
{
rt_err_t err;
if (cnt == 0)
return -RT_EINVAL;
// 初始化定时器参数
timer->timeout_cnt = cnt + rt_ktime_cputimer_getcnt();
timer->init_cnt = cnt;
// 启用定时器
rt_ktime_hrtimer_start(timer);
// 等待定时器超时
err = rt_completion_wait_flags(&(timer->completion), RT_WAITING_FOREVER,
RT_INTERRUPTIBLE);
// 记录定时器执行结果
rt_ktime_hrtimer_keep_errno(timer, err);
return RT_EOK;
}rt_ktime_hrtimer_detach
其实对外暴露的是rt_ktime_hrtimer_delay_detach,而rt_ktime_hrtimer_delay_detach的实现,其实只是直接调用rt_ktime_hrtimer_detach,因此直接分析rt_ktime_hrtimer_detach。
rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)
{
rt_base_t level;
/* 有效性检查 */
RT_ASSERT(timer != RT_NULL);
/* 通知定时器结束等待 */
rt_completion_wakeup_by_errno(&timer->completion, RT_ERROR);
level = rt_spin_lock_irqsave(&_spinlock);
/* 关闭定时器 */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
/* 如果此时定时器在中断中,表明此时定时器已经执行了,需要将定时器从定时器列表中移除 */
if (timer->error == -RT_EINTR || timer->error == RT_EINTR)
{
_nowtimer = RT_NULL;
rt_list_remove(&timer->row);
_set_next_timeout_n_unlock(level);
}
else
{
rt_spin_unlock_irqrestore(&_spinlock, level);
}
return RT_EOK;
}其余接口
这些接口并没有直接暴露给应用,而是暴露到了ctime模块中的timer_create和timer_delete,具体调用实现如下:
#define TIMER_ID_MAX 50
static struct rt_spinlock _timer_id_lock = RT_SPINLOCK_INIT;
static struct timer_obj *_g_timerid[TIMER_ID_MAX];
static void *timer_id[TIMER_ID_MAX];
static resource_id_t id_timer = RESOURCE_ID_INIT(TIMER_ID_MAX, timer_id);
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
static int num = 0;
int _timerid = 0;
struct timer_obj *timer;
char timername[RT_NAME_MAX] = {0};
if (evp == RT_NULL || timerid == RT_NULL)
{
rt_set_errno(EINVAL);
return -1;
}
if (evp->sigev_notify == SIGEV_THREAD) // TODO need to implement
{
rt_set_errno(EINVAL);
return -1;
}
switch (clockid)
{
case CLOCK_REALTIME:
case CLOCK_REALTIME_ALARM:
case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME:
case CLOCK_BOOTTIME_ALARM:
case CLOCK_PROCESS_CPUTIME_ID:
case CLOCK_THREAD_CPUTIME_ID:
break; // Only these ids are supported
default:
rt_set_errno(EINVAL);
return -1;
}
// 申请并初始化timer资源,初始化信息来自evp
timer = rt_malloc(sizeof(struct timer_obj));
if(timer == RT_NULL)
{
rt_set_errno(ENOMEM);
return -1;
}
rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
num %= 100;
timer->sigev_signo = evp->sigev_signo;
#ifdef RT_USING_SMART // RT_SMART相关的代码,暂时不需要关注
struct rt_work *work;
struct rt_lwp *lwp = lwp_self();
struct lwp_timer_event_param *param;
param = rt_malloc(sizeof(struct lwp_timer_event_param));
work = ¶m->work;
if (!work)
{
rt_set_errno(ENOMEM);
return -1;
}
if (lwp)
{
timer->pid = lwp_self()->pid;
rt_list_insert_after(&lwp->timer, &timer->lwp_node);
}
else
{
timer->pid = 0; /* pid 0 is never used */
}
timer->work = work;
#endif /* RT_USING_SMART */
timer->sigev_notify_function = evp->sigev_notify_function;
timer->val = evp->sigev_value;
timer->interval.tv_sec = 0;
timer->interval.tv_nsec = 0;
timer->reload = 0U;
timer->status = NOT_ACTIVE;
timer->clockid = clockid;
// 初始化hrtimer
rt_ktime_hrtimer_init(&timer->hrtimer, timername, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
rtthread_timer_wrapper, timer);
// 获取资源ID号并将定时器挂载在此ID号上
_timerid = resource_id_get(&id_timer);
if (_timerid < 0)
{ // 如果ID号小于0,则说明timer已经注册满了,不能再注册新的timer了,此时需要销毁资源并返回错误信息
#ifdef RT_USING_SMART
rt_free(param);
#endif /* RT_USING_SMART */
rt_ktime_hrtimer_detach(&timer->hrtimer);
rt_free(timer);
rt_set_errno(ENOMEM);
return -1;
}
_g_timerid[_timerid] = timer;
timer->timer_id = (timer_t)(rt_ubase_t)_timerid;
*timerid = (timer_t)(rt_ubase_t)_timerid;
return 0;
}
RTM_EXPORT(timer_create);
int timer_delete(timer_t timerid)
{
struct timer_obj *timer;
rt_ubase_t ktimerid;
ktimerid = (rt_ubase_t)timerid;
if (ktimerid < 0 || ktimerid >= TIMER_ID_MAX)
{ // 如果定时器编号不再有效范围内,则报错返回
rt_set_errno(EINVAL);
return -1;
}
RT_DEBUG_NOT_IN_INTERRUPT; // 要求不能在中断中删除定时器
// 从定时器列表中取出timer,并将维护的_g_timerid和id_timer标记为未使用
rt_spin_lock(&_timer_id_lock);
timer = _g_timerid[ktimerid];
if (timer != NULL)
{
_g_timerid[ktimerid] = RT_NULL;
resource_id_put(&id_timer, ktimerid);
}
rt_spin_unlock(&_timer_id_lock);
if (timer == RT_NULL)
{
rt_set_errno(EINVAL);
LOG_D("can not find timer %ld", ktimerid);
return -1;
}
//如果拿出的定时器有效且处于激活状态,则置为非激活状态并停用该定时器
if (timer->status == ACTIVE)
{
timer->status = NOT_ACTIVE;
rt_ktime_hrtimer_stop(&timer->hrtimer);
}
// 解注册该定时器
rt_ktime_hrtimer_detach(&timer->hrtimer);
#ifdef RT_USING_SMART // RT_SMART的实现,需使用时针对看
if (timer->pid)
rt_list_remove(&timer->lwp_node);
rt_free(timer->work);
#endif
// 释放定时器资源
rt_free(timer);
return 0;
}
RTM_EXPORT(timer_delete);rt_ktime_hrtimer_stop
rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)
{
rt_base_t level;
RT_ASSERT(timer != RT_NULL);
level = rt_spin_lock_irqsave(&_spinlock);
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
{ // 如果定时器当前未启用,则不需要停止
rt_spin_unlock_irqrestore(&_spinlock, level);
return -RT_ERROR;
}
// 移除当前定时器并将定时器标记置为停用
_nowtimer = RT_NULL;
rt_list_remove(&timer->row);
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
// 启动下一个定时器并退出spin lock
_set_next_timeout_n_unlock(level);
return RT_EOK;
}rt_ktime_hrtimer_control
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)
{
*(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
}
else
{
*(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;
}总结
经过对这部分代码的分析,我们会得出以下结论:cputime本身的功能仅仅是提供更细颗粒度的计时信息,而他被boottime模块所使用。boottime模块,主要功能就是记录系统从cputime起来后到读取时间是系统所消耗的时间,其颗粒度与调用的接口有关。
hrtime模块,则是直接通过系统滴答时钟的方式实现了高于ms精度的延时,解决带RTOS时,只能使用比滴答时钟想等或者更长时间延时的问题。
我要赚赏金
