灯火葳蕤是什么意思| 女生右手食指戴戒指什么意思| 耳朵疼吃什么消炎药| 乙肝表面抗体高是什么意思| 日本樱花什么时候开| 今天什么生肖冲什么生肖| 2004年属什么生肖| 办理户口迁移需要什么材料| 心肌炎是什么| 胃疼是什么病| 颠覆三观是什么意思| 花非花雾非雾什么意思| 心季吃什么药| 肠易激综合征是什么原因造成的| 吃豌豆有什么好处| 易举易泄是什么原因| 心率过快吃什么药最好| 夏天脚出汗是什么原因| 老生气会得什么病| 下午一点是什么时辰| 反应迟钝是什么原因造成的| bmd是什么意思| 脐橙什么意思| 升血小板吃什么药| 小猫不能吃什么| 龙眼和桂圆有什么区别| 心有灵犀什么意思| 男人为什么喜欢舔女人下面| 入赘什么意思| 下巴脱臼挂什么科| 什么是同源染色体| 眼睛黄是什么原因| 生不逢时是什么意思| 手容易出汗是什么原因| 男人尿道炎吃什么药最好| 开小灶是什么意思| 香港身份证有什么好处| 胃不好吃什么最养胃| 例假来的是黑色的是什么原因| 韭菜吃多了有什么坏处| 血脂高吃什么油| 九寨沟在什么地方| 木林森是什么品牌| 屁股生疮是什么原因| 乙肝表面抗体阳性什么意思| 经常中暑是什么原因| 7号来的月经什么时候是排卵期| 一什么牙刷| 新疆是什么民族| 什么是溶血| 飞蚊症用什么滴眼液| 亨廷顿舞蹈症是什么病| 高血压适合做什么运动| 静待花开什么意思| 大脸适合什么发型| 为什么越睡越困| 产厄是什么意思| 喉咙溃疡吃什么药| 7月14日什么节日| 疲软是什么意思| 阿司匹林什么时候吃最好| 藏红花是什么| 准奏是什么意思| 青岛有什么玩的| 鼠和什么生肖最配| 吃什么东西能通便| 绿豆汤有什么功效| 什么公主| 窦卵泡是什么意思| 宝宝什么时候开始说话| 第一次做什么感觉| 千里江陵是什么意思| 为什么家里会有蟑螂| 什么样的人可以通灵| 蟋蟀吃什么| 六月二十四是什么日子| 胡子发黄是什么原因| 脖子上长癣是什么原因| 渐入佳境什么意思| 毛血旺是什么菜| 什么叫血压| dollars是什么意思| 胆囊炎适合吃什么食物| 水泡长什么样| 为什么有眼袋是什么原因引起的| 阑尾炎是什么引起的| helen是什么意思| 口舌生疮是什么原因| 冠心病吃什么药好| ECG是什么| 脂蛋白高是什么意思| 女性私处痒是什么原因引起的| 用什么泡脚可以去湿气| 新生儿湿疹抹什么药膏| 什么书在书店买不到| 甄别是什么意思| 强痛定又叫什么| 小雪时节吃什么| 灰水是什么| 颠是什么意思| 骨密度增高是什么意思| 腋臭去医院挂什么科| 雨水是什么季节| 五月二十六是什么星座| 催丹香是什么意思| 感冒低烧吃什么药| 龟苓膏的原料是什么| 下九流指的是什么| 风声鹤唳什么意思| 胃疼想吐恶心是什么原因| 985高校是什么意思| 肾功能挂什么科| 牛肉饺子配什么菜好吃| 孩子贫血吃什么补血最快| 是指什么| 2020年是什么生肖| 唐氏筛查都查些什么| 甲申日五行属什么| 朝什么暮什么| 腰肌劳损吃什么药| 为什么做完爱下面会疼| 姓贾的男孩取什么名字好| 一心向阳下一句是什么| 梦见火烧房子是什么预兆| 检查甲亢挂什么科| 中药为什么那么苦| 脑白质病变是什么病| 月经前一周失眠是什么原因| 今年16岁属什么| 什么火锅最好吃| 胸痛一阵一阵的痛什么原因| 巴基斯坦是什么语言| 做腹部彩超挂什么科| 喉咙痛去药店买什么药| 午五行属什么| 口上长水泡是什么原因| 9月21日是什么星座| 子宫低回声结节是什么意思| 什么的舞蹈| 条条框框是什么意思| 蚊子的幼虫叫什么| 做梦梦见前男友是什么意思| 喉咙发甜是什么原因| 银925什么意思| 窈窕淑女君子好逑是什么意思| 儿童牙龈肿痛吃什么药| 花甲炒什么配菜好吃| 什么的天山| 乙字五行属什么| d二聚体是什么| 贫血要注意些什么| 大鱼际发青是什么原因| zhr是什么牌子的鞋| 反式脂肪是什么| 火把节是什么时候| 颈椎挂什么科| 知更鸟是什么意思| 咳嗽打什么点滴效果好| 劫财是什么意思| 靶向药是什么| 自知力是什么意思| 知是什么意思| 尿酸高挂什么科| 梦见娃娃是什么意思| 黄金豆是什么豆| 大生化检查都包括什么项目| 咽喉痛什么原因| 瑾字是什么意思| 什么是撸管| 缠腰蛇是什么症状图片| 四季常青财运旺是什么生肖| 蝉又叫什么名字| 田七配什么煲汤最好| 情志病是什么意思| 今年什么时候进伏天| 沙眼是什么| 肉便器是什么意思| 月经提前半个月来是什么原因| 吃桑葚对身体有什么好处| 耳鸣用什么滴耳液| 四库全书是什么| icd是什么意思| 一什么正什么| 新疆人为什么不吃猪肉| 榴莲吃了有什么好处| 打蛋白针有什么作用| 父母坟上长树意味什么| 掉发严重是什么原因| 19岁属什么生肖| cho是什么意思| 猪鞭是什么| 瘦人吃什么能长胖| 就绪是什么意思| 神经性头疼是什么原因造成的| 懵逼是什么意思| rock是什么意思| 眼拙是什么意思| 肾气不足是什么原因| 三焦经在什么位置| 翻墙是什么| 1658是什么意思| 点痦子去医院挂什么科| 小囊肿是什么病严重吗| 嘴里发酸是什么原因| 经期吃什么好排除瘀血| 蜜蜂是什么生肖| 甲状腺结节对身体有什么影响| 洋葱吃多了有什么坏处| 人生最大的遗憾是什么| 沉香茶属于什么茶| 膝关节疼是什么原因| 小孩趴着睡觉是什么原因| 什么是电子版照片| 左边太阳穴疼是什么原因| 一什么马车| 开塞露用多了有什么副作用| 五常大米是什么意思| 脚麻什么原因| 凉皮用什么做的| rag是什么| 大豆和黄豆有什么区别| 连续放屁是什么原因呢| 玛雅文明是古代什么文明的代表| 魔芋粉是什么做的| 怀孕初期吃什么菜| 汉堡是什么意思| cro是什么意思| 怕金病帕金森是什么症状| 破釜沉舟的釜是什么意思| 特点是什么| 什么菜煮不熟| 贪吃的动物是什么生肖| 棚户区改造和拆迁有什么区别| 人流需要准备什么| 胆囊炎吃什么药效果最好| 咖啡对心脏有什么影响| 迎字五行属什么| 18k是什么金| 霸是什么生肖| 晕车药有什么副作用| 不亚于是什么意思| 七个月宝宝可以吃什么辅食| 1970年属什么生肖| 总是流鼻血是什么原因| 三点水加亘念什么| 阴茎长水泡是什么原因| 肺炎吃什么水果| touch什么意思| 六月十号什么星座| 牙龈充血是什么原因| 25分贝相当于什么声音| 兵马未动粮草先行是什么意思| 缺钾有什么症状| 蹲着有什么好处| 气郁症是什么症状| 备孕期间不能吃什么| 内心os什么意思| 均可是什么意思| 小肠换气什么症状| 消融术是什么手术| 就绪是什么意思| 飞机后面的白烟是什么| 4月7日什么星座| 1450是什么意思| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 嵌入式开发 ? 软件与操作系统 ? rtthread cputime模块解析

共2条 1/1 1 跳转至

rtthread cputime模块解析

高工
2025-08-04 22:58:27     打赏
百度 腾势500车厢内所有的革新和进化,都基于一种低调与不经意间的小范围革新。

      在分析硬件定时器框架时,我们发现硬件定时器基于的是mcu提供的systick定时器, 会存在影响系统调度速度以及精度的问题。而为了解决这个问题,rtt引入了cputime的模块,cputime 通过对接单独的硬件定时器来实现,提高了精度,不过作为代价是,在每个 bsp 中都需要具体实现 cputime 的对接工作。

cputime模块解析

源码路径

RTT_PATH\components\drivers\cputime\
                                     cputime.c    // cputime框架代码
                                     cputimer.c   // cputime对应用暴露的接口
                                     cputime_cortexm.c //cortex m核的cputime实现代码
                                     cputime_riscv.c // riscv核的cputime实现代码

      由于源码中存在两个核的对接实现,因此暂时只看cortexm核部分。

对接驱动接口

cputime注册接口

struct rt_clock_cputime_ops
{
    // 获取剩余时间入口
    uint64_t (*cputime_getres)(void);
    // 获取当前时间入口
    uint64_t (*cputime_gettime)(void);
    // 设置硬件定时器超时时间,回调函数,以及回调函数的参数的入口
    int (*cputime_settimeout)(uint64_t tick, void (*timeout)(void *param), void *param);
};

int clock_cpu_setops(const struct rt_clock_cputime_ops *ops)
{
    _cputime_ops = ops;
    if (ops)
    {
        RT_ASSERT(ops->cputime_getres  != RT_NULL);
        RT_ASSERT(ops->cputime_gettime != RT_NULL);
    }

    return 0;
}

// 很奇怪,cortexm核的处理和riscv核的处理,都没有注册cputime_settimeout
// 只能说,可能两份源码都不是最终的实现,但即使是参考的,也应该把这个实现写出来吧
const static struct rt_clock_cputime_ops _cortexm_ops =
{
    cortexm_cputime_getres,
    cortexm_cputime_gettime
};

int cortexm_cputime_init(void) // cortexm核的注册函数
{
#ifdef PKG_USING_PERF_COUNTER
    clock_cpu_setops(&_cortexm_ops);
#else
    /* check support bit */
    if ((DWT->CTRL & (1UL << DWT_CTRL_NOCYCCNT_Pos)) == 0)
    {
        /* enable trace*/
        CoreDebug->DEMCR |= (1UL << CoreDebug_DEMCR_TRCENA_Pos);

        /* whether cycle counter not enabled */
        if ((DWT->CTRL & (1UL << DWT_CTRL_CYCCNTENA_Pos)) == 0)
        {
            /* enable cycle counter */
            DWT->CTRL |= (1UL << DWT_CTRL_CYCCNTENA_Pos);
        }

        clock_cpu_setops(&_cortexm_ops);
    }
#endif /* PKG_USING_PERF_COUNTER */
    return 0;
}
INIT_BOARD_EXPORT(cortexm_cputime_init);

对接应用接口

注册函数

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);

    /* 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 = tick + clock_cpu_gettime();
    timer->init_tick    = tick;

    rt_list_init(&(timer->row));
    rt_sem_init(&(timer->sem), "cputime", 0, RT_IPC_FLAG_PRIO);
}

     与之前的几个定时器不一样的是,cputimer并没有提供create函数,仅提供了init,也就意味着变量struct rt_cputimer只能外部定义好,再调用init函数完成参数初始化。

cputime启动函数

int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *param)
{
    if (_cputime_ops)
        return _cputime_ops->cputime_settimeout(tick, timeout, param);

    rt_set_errno(ENOSYS);
    return 0;
}

static void _cputime_timeout_callback(void *parameter) // cputime超时回调函数
{
    struct rt_cputimer *timer;
    timer = (struct rt_cputimer *)parameter;
    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->parameter); //调用超时回调处理

    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_callback, t);
    }
    else
    {
        clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
    }
}

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);
        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 // 非空,则禁用定时器
    {
        _cputimer_nowtimer = RT_NULL;
        clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
    }
}

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(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_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;
}

      这里,个人认为可能存在一个问题,timerout的计时,在start函数中并没有被重新设置,也就意味着,如果上层init定时器参数后,但没有立马调用start函数,就会存在实际start时,定时器就已经超时的问题。

cputime配置函数

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(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;
        timer->timeout_tick = *(rt_uint64_t *)arg + clock_cpu_gettime();
        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;
}

      这部分的入口,和前面几个定时器提供的接口,也是一致的,并没有什么不同。但是有个问题,cputime的执行函数中,并没有看到周期执行的处理,这个control函数设置周期执行或单次执行,其实并没有功能。

cputime停止函数

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(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;
}

      停止函数的实现就很直白了,如果是启用状态,则从启用列表中移除定时器,并将定时器的可执行状态切换为非执行中,同时更新定时器的超时处理信息。

cputime删除函数

rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
{
    rt_base_t level;

    /* parameter check */
    RT_ASSERT(timer != RT_NULL);
    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);

    _set_next_timeout();

    return RT_EOK;
}

      删除函数的实现,有些看不明白,如果当前cputime任务并不在定时器列表中,那删除还需要再去执行一遍更新定时器的超时信息?

cputime分离函数

rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
{
    rt_base_t level;

    /* parameter check */
    RT_ASSERT(timer != RT_NULL);
    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_sem_detach(&(timer->sem));

    return RT_EOK;
}

      同删除函数一样的问题,在没使用的时候也需要更新一次定时器超时处理信息,很奇怪。另外timer->sem这个信号量压根就没使用,为了一个没有使用的信号量写一个detach函数,很奇怪。

cputime休眠函数

static void _cputime_sleep_timeout(void *parameter)
{
    struct rt_semaphore *sem;
    sem = (struct rt_semaphore *)parameter;
    rt_sem_release(sem);    // 释放信号量
}

rt_err_t rt_cputime_sleep(rt_uint64_t tick)
{
    rt_base_t          level;
    struct rt_cputimer cputimer;

    if (!clock_cpu_issettimeout())
    {
        rt_int32_t ms = clock_cpu_millisecond(tick);
        return rt_thread_delay(rt_tick_from_millisecond(ms));
    }

    if (tick == 0)
    {
        return -RT_EINVAL;
    }

    rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, &(cputimer.sem), tick,
                     RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); //初始化cputime

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    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 RT_EOK;
}

// ns级别的延时
rt_err_t rt_cputime_ndelay(rt_uint64_t ns)
{
    uint64_t unit = clock_cpu_getres();
    return rt_cputime_sleep(ns * (1000UL * 1000) / unit);
}

// us级别的延时
rt_err_t rt_cputime_udelay(rt_uint64_t us)
{
    return rt_cputime_ndelay(us * 1000);
}

// ms级别的延时
rt_err_t rt_cputime_mdelay(rt_uint64_t ms)
{
    return rt_cputime_ndelay(ms * 1000000);
}

      从这里,我们可以发现,cputime延时本质上是利用信号量和cputime的精确定时功能,完成相对高精度的延时等待,可以实现rtthread_mdelay无法实现的us级别的延时设置。

总结

       首先,目前看提供的驱动层参考实现并不完美(缺乏最关键的超时回调处理,且其他代码也不确定是否真实有效)。此外,目前并未发现哪块板卡专门适配了该模块,若需使用,则需自行适配。

       其次,cputime仅仅实现了单次出发的模式,若想实现连续触发,并不能使用cputime模块。但不可否认的是,cputime能够实现与硬件定时器一致的高精度超时处理函数,并将处理效果等同于rt_thread_mdelay函数的实现。

      最后,目前版本的cputime,在使用时一定得注意,要么直接init后start,要么RT_TIMER_CTRL_SET_TIME后start,否则存在超时时间与所需超时时间不一致的问题,或者若有兴趣修复这个bug的话,可以直接修改cputime的源码,做到与其他几个定时器框架的实现思路一致。






关键词: rtthread     cputime     模块     解析    

专家
2025-08-04 08:20:40     打赏
2楼

感谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
邪气入体是什么症状 痛风喝什么茶最好 骨髓炎是什么症状 七月二十八什么星座 榴莲和什么水果相克
餐补是什么意思 土命是什么意思 老人适合吃什么水果 什么叫女人味 阴柔是什么意思
短杆菌是什么意思 锻炼是什么意思 淋巴细胞数偏高是什么意思 皮炎是什么 牡丹象征着什么意义
什么是天葬 lr是什么 降钙素原高说明什么 世界什么名 什么山没有石头
夏占生女是什么意思hcv7jop6ns2r.cn 肝脏不好吃什么调理hcv9jop2ns7r.cn 食指中指交叉什么意思hcv8jop5ns4r.cn 中的反义词是什么shenchushe.com 衣原体感染有什么症状hcv7jop9ns5r.cn
寅木代表什么hlguo.com chocker是什么hcv9jop7ns2r.cn 早晨醒来口苦是什么原因hcv8jop9ns8r.cn 心梗什么症状sscsqa.com 怎么吃都不胖是什么原因hcv8jop7ns9r.cn
九月二十号是什么星座hcv8jop9ns8r.cn 什么的武松hcv7jop9ns3r.cn 劳士顿手表什么档次hcv7jop7ns4r.cn 黑五是什么hcv8jop3ns2r.cn 上岸了是什么意思clwhiglsz.com
硬度不够吃什么中成药hcv8jop7ns8r.cn 戒指戴哪个手指代表什么hcv9jop7ns1r.cn juicy是什么意思hcv9jop2ns4r.cn 脂肪瘤是什么原因引起的xjhesheng.com 紫癜是什么原因引起的hcv9jop1ns0r.cn
百度