• <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • ?

    Linux时间子系统之(五):POSIX Clock

    作者:linuxer 发布于:2015-1-5 19:03 分类:时间子系统

    一、前言

    clock是timer的基础,任何一个timer都需要运作在一个指定的clock上?#30784;?#20869;核中维护了若干的clock,本文第二章描述了clock的基本概念和一些静态定义的posix clock。根据计时的特点,clock分成两种:一种是真实世界的时间概念,另外一个是仅仅计算CPU执行时间 ,这两种clock分别在第三和第四章描述。从clock的生命周期来看,可以分成静态和动态的posix clock,静态是一直存在于内核中的,而动态clock有创建和销毁的概念,本文第五章描述了dynamic posix clock。

     

    二、基本概念

    1、核心数据结构

    所谓clock,实际上就是一种计时工具,可能是?#24067;?#20063;可能是软件,当然对于POSIX clock而言,当然是指软件抽象了。clock能够记录一段时间的流逝,这段时间可能是真实的墙上时间,也可能是虚拟的时间,例如基于某个进程或者线程的CPU执行时间。在linux kernel中,用struct k_clock来抽象,具体定义如下:

    struct k_clock {
        int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
        int (*clock_set) (const clockid_t which_clock, const struct timespec *tp);
        int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
        int (*clock_adj) (const clockid_t which_clock, struct timex *tx);
        int (*timer_create) (struct k_itimer *timer);
        int (*nsleep) (const clockid_t which_clock, int flags, struct timespec *, struct timespec __user *);
        long (*nsleep_restart) (struct restart_block *restart_block);
        int (*timer_set) (struct k_itimer * timr, int flags, struct itimerspec * new_setting,
                                struct itimerspec * old_setting);
        int (*timer_del) (struct k_itimer * timr);
        void (*timer_get) (struct k_itimer * timr, struct itimerspec * cur_setting);
    };

    clock作为一个计时工具当然有计时精度,通过clock_getres函数可以获取该clock的时间精度,需要说明的是这个精度是和timer相关的,用于将用户设定的timer超时时间规整到clock精度允许的数值上。clock_get和clock_set函数可以分别获取和设定当前的时间,这个时间值是一个绝对时间值(对于时间轴而言,这个绝对时间也是相对的,是相对于该timeline的epoch而言),标记了当前时间点。clock计时有可能是不准确的,例如基于系统晶振的clock。一方面本身晶振的精度有限,时间累积长了会出现较大误差。另外,晶振也会随着使用时间的推移、温度的变化等等因素而导致误差。clock_adj函数允许系统根据外部的精确时间信息对本clock进行调整。nsleep和nsleep_restart这两个成员函数可以让进程sleep一段时间。timer_xxx系列函数是和POSIX interval timer相关,具体会在POSIX timer文档中描述。

    2、静态定义的clock

    static struct k_clock posix_clocks[MAX_CLOCKS];

    posix_clocks数组定义了系统支持的所有的clock,相关的定义如下:

    #define CLOCK_REALTIME            0
    #define CLOCK_MONOTONIC            1
    #define CLOCK_PROCESS_CPUTIME_ID    2
    #define CLOCK_THREAD_CPUTIME_ID        3
    #define CLOCK_MONOTONIC_RAW        4
    #define CLOCK_REALTIME_COARSE        5
    #define CLOCK_MONOTONIC_COARSE        6
    #define CLOCK_BOOTTIME            7
    #define CLOCK_REALTIME_ALARM        8
    #define CLOCK_BOOTTIME_ALARM        9
    #define CLOCK_SGI_CYCLE            10    /* Hardware specific */
    #define CLOCK_TAI            11

    #define MAX_CLOCKS            16

    POSIX标准定义了4种类型的clock,CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIME_ID和CLOCK_THREAD_CPUTIME_ID,其他是linux specific。如果一个clock的timeline是基于CPU运行时间的,那么我们称之CPU-time clock。CPU-time clock主要是用来为某个进程或者线程的执行时间进行计时的,一旦线程(进程)被切换,那么该clock就停掉了,直到下次调度器切换回该线程(进程)执行。

    各个具体的操作系统实现可以定义自己特有的clock,对于Linux kernel,我?#23884;?#20041;了若干种clock。CLOCK_MONOTONIC_RAW启动时间点被设成0,此后一直不断累加,而且能设定,不会随NTP调整。CLOCK_REALTIME_COARSE、CLOCK_MONOTONIC_COARSE的概念和CLOCK_REALTIME、CLOCK_MONOTONIC的概念是类似的,只不过是精度是比较粗的版本。有时候,timer没有必要要求那么高的精度,那么我们可以使用这种clock,从而可以获取更好的性能。CLOCK_BOOTTIME和CLOCK_MONOTONIC类似,也是单调上述,在系统初始化的时候设定的基准数值是0,不过CLOCK_BOOTTIME计算系统suspend的时间,也就是说,不论是running还是suspend(这些都算是启动时间),CLOCK_BOOTTIME都会累积计时,直到系统reset或者shutdown。

    CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM主要用于Alarmtimer,这种timer是基于RTC的,更详细的内容请参考本站Alarmtimer的文档。CLOCK_TAI是原子钟的时间,和基于UTC的CLOCK_REALTIME类似,不过没有leap second。

    用户空间的clock_xxx函数会传递clock id的参数,在内核态,根据id作为index在posix_clocks数组中可?#36816;?#24341;到对应的clock,然后调用clock对应的callback函数就OK了。当然基本意思就是这样,具体实现如下:

    static struct k_clock *clockid_to_kclock(const clockid_t id)
    {
        if (id < 0)
            return (id & CLOCKFD_MASK) == CLOCKFD ?
                &clock_posix_dynamic : &clock_posix_cpu;

        if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
            return NULL;
        return &posix_clocks[id];
    }

    clockid_to_kclock这个函数用来将clock id和具体的posix clock的k_clock 数据结构对应起?#30784;?#22312;linux平台上,clockid是int类型的数据,共32个bit,高29个bit用来保存一个pid(用于CPU-time clock)或者fd(动态分配的clock),bit 2用来说明该CPU-time clock是一个进程clock还是线程clock。bit 1和bit 0用来说明该clock id的类型:PROF=0, VIRT=1, SCHED=2, or FD=3。

    当clock id小于0的时候,要么是CPU-time clock,要么?#23884;?#24577;分配的clock,可以根据clock id的类型来判断。CPU-time clock和动态分配的clock后面会具体介绍。

     

    三、各种real timeclock的定义

    系统初始化的时候会调用init_posix_timers函数对各种静态定义的real time clock进行注册。注:monotonic clock也是real time clock的一种,全称是monotonic real time clock。

    1、real time clock的定义如下(timer相关内容不在本文描述):

    struct k_clock clock_realtime = {
        .clock_getres    = hrtimer_get_res,
        .clock_get    = posix_clock_realtime_get,
        .clock_set    = posix_clock_realtime_set,
        .clock_adj    = posix_clock_realtime_adj,
        .nsleep        = common_nsleep,
        .nsleep_restart    = hrtimer_nanosleep_restart,
    };

    real time clock需要调用timekeeping模块的接口来获取和设定当前时间值。对于获取当前时间值的函数posix_clock_realtime_get而言,是调用ktime_get_real_ts函数,该函数是timekeeping模块的接口函数,以timespec的格式回了real time clock的当前值。posix_clock_realtime_set函数主要是调用do_settimeofday这个timekeeping模块的接口函数。posix_clock_realtime_adj是调用do_adjtimex接口函数来实现具体的功能。

    纳秒级别的sleep是通过高精度timer实现的,real time clock的精度和hrtimer相关,具体可以参考hrtimer相关文档。

    2、monotonic clock的定义如下:

    struct k_clock clock_monotonic = {
        .clock_getres    = hrtimer_get_res,
        .clock_get    = posix_ktime_get_ts,
        .nsleep        = common_nsleep,
        .nsleep_restart    = hrtimer_nanosleep_restart,
    };

    monotonic clock没有clock_set函数,不能被设定。通过ktime_get_ts这个timekeeping模块的接口可以获得monotonic clock的当前值。纳秒级别的sleep以及精度的获取函数和real time clock一样。

    3、monotonic raw clock的定义如下:

    struct k_clock clock_monotonic_raw = {
        .clock_getres    = hrtimer_get_res,
        .clock_get    = posix_get_monotonic_raw,
    };

    posix_get_monotonic_raw函数是调用timekeeping模块getrawmonotonic接口函数实现获取monotonic raw clock当前时间数值的。和monotonic clock一样,不能设定。和monotonic clock不同的是该clock没有timer相关的callback函数。

    4、coarse clock

    struct k_clock clock_realtime_coarse = {
        .clock_getres    = posix_get_coarse_res,
        .clock_get    = posix_get_realtime_coarse,
    };
    struct k_clock clock_monotonic_coarse = {
        .clock_getres    = posix_get_coarse_res,
        .clock_get    = posix_get_monotonic_coarse,
    };

    这两个clock的精度都是和tick相关的,KTIME_LOW_RES定义就是tick的纳秒数值。clock_get函数分别调用current_kernel_time和get_monotonic_coarse获取当前时间点的值。

    CLOCK_BOOTTIME和CLOCK_TAI的clock实现非常简单,大家自行阅读代码就OK了。

     

    四、CPU-time clock

    1、概述

    从用户空间的?#23884;?#30475;,有两种CPU-time clock的应用场景:

    (1)调用clock_xxx函数并传递CLOCK_PROCESS_CPUTIME_ID或者CLOCK_THREAD_CPUTIME_ID给该函数

    (2)调用clock_getcpuclockid或者pthread_getcpuclockid函数来获取指定进程或者线程的clock id,之后调用clock_xxx函数并传递该clock id参数

    应对第一种场景,系统初始化的时候会调用init_posix_cpu_timers函数对静态定义的CPU-time clock进行注册。对于第二种场景,内核静态定义了一个clock_posix_cpu的clock来应对这种需求。

    2、指定进程或者线程的CPU-time clock

    内核静态定义了一个clock如下(去掉了timer的callback函数):

    struct k_clock clock_posix_cpu = {
        .clock_getres    = posix_cpu_clock_getres,
        .clock_set    = posix_cpu_clock_set,
        .clock_get    = posix_cpu_clock_get,
        .nsleep        = posix_cpu_nsleep,
        .nsleep_restart    = posix_cpu_nsleep_restart,
    };

    (1)获取精度信息

    static int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
    {
        int error = check_clock(which_clock);--------参数校验
        if (!error) {
            tp->tv_sec = 0;
            tp->tv_nsec = ((NSEC_PER_SEC + HZ - 1) / HZ);
            if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
                tp->tv_nsec = 1;
            }
        }
        return error;
    }

    该函数的执行逻辑分成两个部分,一部分是参数校验,一部分是返回精度。参数校验需要检查的包括:

    (a)clock id中的高29个bit包含了pid,获取pid的代码如下:

    #define CPUCLOCK_PID(clock)        ((pid_t) ~((clock) >> 3))

    从代码可知,实际上并不是将pid放到高29个bit,而是将反码保存到了高29个bit。为何保存反码?这样做为了确保clock id是一个负数(MSB是1),还记得clockid_to_kclock的实现吗?要获取该clock id的精度,要确保该pid的task存在

    (b)如果该clock id是一个进程相关的(调用clock_getcpuclockid获得),那么这个进程id应该是一个实实在在的进程id。在linux kernel中,pid实际上是线程ID,POSIX标准的进程ID,也就是PID在内核中被成为线程组ID。因此,所谓一个“实实在在的进程id?#26412;?#26159;说该线程的id(pid)和tgid一样,该pid标识的线程是线程组leader。当然,就是获取精度而已,实际上要求并不要那么?#32454;瘢?#20063;许该pid标识的线程leader会退出,因此实际上要求该pid标识的task有thread group leader就OK了。(这里有可能理解有误,TODO)

    (c)如果该clock id是一个线程相关的(调用pthread_getcpuclockid获得),那么调用者必须和该线程(clock id中指明的那个线程)属于一个进程(线程组)。

    返回精度部分的代码逻辑很简单,对于PROF和VIRT类型的CPU-time clock,其精度是tick,对于SCHED类型,精度是1ns。

    (2)获取当前时间值

    同样的,首先需要从clock id中获取pid的值,然后根据pid的值获取对应的task sturct,如果pid等于0,那么不需要费劲去寻找。得到task struct之后,可以调用posix_cpu_clock_get_task函数获取时间值:

    static int posix_cpu_clock_get_task(struct task_struct *tsk,   const clockid_t which_clock,
                        struct timespec *tp)
    {
        int err = -EINVAL;
        unsigned long long rtn;

        if (CPUCLOCK_PERTHREAD(which_clock)) {---per 线程的cpu clock
            if (same_thread_group(tsk, current))---必须和调用者是同一个线程组,也就是同一个进程
                err = cpu_clock_sample(which_clock, tsk, &rtn);
        } else {

            if (tsk == current || thread_group_leader(tsk))---进程的cpu clock
                err = cpu_clock_sample_group(which_clock, tsk, &rtn); 
        }

        if (!err)
            sample_to_timespec(which_clock, rtn, tp); ---给返回值?#25345;?

        return err;
    }

    这里仍然存在校验问题,也就是说是否允许调用者获取该task的CPU-time clock。对于进程,只允许调用者进程获取自己的CPU-time clock,在多线程环境下,主线程(线程组leader)可以获取整个进程的CPU-time clock信息。对于per线程的操作,必须和调用者是同一个线程组,也就是同一个进程。

    (a)获取线程的clock信息

    static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
                    unsigned long long *sample)
    {
        switch (CPUCLOCK_WHICH(which_clock)) {
        default:
            return -EINVAL;
        case CPUCLOCK_PROF:
            *sample = prof_ticks(p);----获取该task在用户空间加上在kernel space的执行时间
            break;
        case CPUCLOCK_VIRT:
            *sample = virt_ticks(p);----获取该task在用户空间的执行时间
            break;
        case CPUCLOCK_SCHED:
            *sample = task_sched_runtime(p);----和调度器相关的cpu clock
            break;
        }
        return 0;
    }

    计算进程或者线程在cpu?#31995;?#25191;行时间是一个挺烦人的事,一方面想要精度高,另外一方面又不想计算?#30475;蟆?#22240;此,实际上CPU-time clock有三种,CPUCLOCK_PROF和CPUCLOCK_VIRT这两种都是比较?#33268;?#20272;计CPU执行时间的clock,它的工作原理就是在周期性tick中进行进程cpu time的统计,如果该tick是用户态(timer中断了用户态程序的执行),那么整个tick的时间都是该进程的用户态执行时间。如果该tick是内核态,并且是用户程序进行系统调用而陷入内核,那么整个tick的时间都是该进程的系统态执行时间。

    CPUCLOCK_SCHED clock和上面的方法不一样,它的精度是纳秒级别的,是在调度器上进行计算进程时间。具体的计算方法还是留到调度器文章中再描述吧。

    (b)cpu_clock_sample_group函数概念类似,不过是统计一个进程上所有线程的时间而已。

    3、CLOCK_PROCESS_CPUTIME_ID 类型的clock

    struct k_clock process = {
        .clock_getres    = process_cpu_clock_getres,
        .clock_get    = process_cpu_clock_get,
        .nsleep        = process_cpu_nsleep,
        .nsleep_restart    = process_cpu_nsleep_restart,
    };

    process_cpu_clock_getres用来获取时间精度,该函数实际是调用posix_cpu_clock_getres(PROCESS_CLOCK, tp)来完成的。process_cpu_clock_get用来获取当前时间值,实际上是通过调用posix_cpu_clock_get完成。posix_cpu_clock_xxx函数在上一节中已经描述。

    4、CLOCK_THREAD_CPUTIME_ID类型的clock

    很简单,大家自行学习吧。

     

    五、动态分配clock

    1、?#20174;?

    某些?#24067;?#25552;供了计时的能力,可以实现成一个posix clock,同时,这些?#24067;?#21448;类似USB设备那样可以热拔插,这也就意味着该posix clock不能静态定义。此外,除了标准的timer和clock相关的操作,这些提供计时能力的?#24067;?#36824;需要一些其他的类似字符设备界面的控?#24179;?#21475;,在这样的需求推动下,内核提供了dynamic posix clock。

    2、dynamic posix clock

    系统中的每一个dynamic posix clock用struct posix_clock来抽象,如下:

    struct posix_clock {
        struct posix_clock_operations ops;--------------(1)
        struct cdev cdev;----------------------(2)
        struct kref kref;
        struct rw_semaphore rwsem;
        bool zombie;------------------------(3)
        void (*release)(struct posix_clock *clk);-------------(4)
    };

    (1)ops是该dynamic posix clock的操作函数集,分成两个group,一个是timer(例如:timer_create、timer_delete等)以及clock操作相关(例如clock_gettime、clock_settime等),另外一个是普通字符设备的操作函数(例如:open、read、write等)。

    (2)该dynamic posix clock对应的cdev数据结构。在struct posix_clock_operations中有一个owner,其实在cdev中也有一个指向moudle的owner成员,看起来似乎是重复定义了。同样的疑问也存在与kref成员,因为在cdev中有kobject成员,kobject抽象了内核最基础的对象类别,包括名字、引用计数等,因此,我觉得只要struct posix_clock包括了cdev成员,struct posix_clock_operations中的owner以及struct posix_clock中的kref应该没有存在的必要了。

    (3)zombie记录了底层?#24067;?#30340;状态,对于hotplug的外设,有可能?#24067;?#34987;拔除。rwsem用来保护该状态信息

    (4)当reference count等于0的时候会调用release函数释放dynamic posix clock占用的资?#30784;?

    3、注册和注销

    底层的有计时能力的?#24067;river可以调用posix_clock_register和posix_clock_unregister来注册或者注销一个posix clock,注册代码如下:

    int posix_clock_register(struct posix_clock *clk, dev_t devid)
    {
        int err;

        kref_init(&clk->kref);
        init_rwsem(&clk->rwsem);

        cdev_init(&clk->cdev, &posix_clock_file_operations);-----VFS接口的操作函数集合
        clk->cdev.owner = clk->ops.owner;
        err = cdev_add(&clk->cdev, devid, 1);

        return err;
    }

    VFS接口的操作函数集合都非常简单,基本上都是struct posix_clock_operations?#31995;?#23383;符设备操作函数集合上。这样,用户空间的程序可以通过标准的文件描述符进行设备操作。

    4、clock和timer接口

    通过clock_xxx或者timer_xxx函数可以指定clock id,对于dynamic posix clock可以通过下面的操作来生成一个dynamic posix clock ID:

    #define FD_TO_CLOCKID(fd)    ((~(clockid_t) (fd) << 3) | CLOCKFD)

    其中fd是通过设备节点打开的那个有计时能力的?#24067;?#22312;内核态会通过clockid_to_kclock操作将clock id转换成

    static struct k_clock *clockid_to_kclock(const clockid_t id)
    {
        if (id < 0)
            return (id & CLOCKFD_MASK) == CLOCKFD ?
                &clock_posix_dynamic : &clock_posix_cpu;

    ……
    }

    clock_posix_dynamic可以将dynamic posix clock ID转换成对应的posix_clock,然后调用struct posix_clock_operations?#31995;膖ime和clock相关的函数即可。


    原创文章,转发请注明出处。蜗窝科技

    http://www.71402172.com/timer_subsystem/posix-clock.html

    标签: posix-clock

    评论:

    okmine
    2019-04-17 19:16
    是不是ptp 的timer 不支持 timer_create()?
    运行了一下tools/testing/selftests/ptp/testptp.c, 不支持这个定时,其它都正常。
    okmine
    2019-04-18 10:28
    @okmine?#20309;?#30340;kernel4.14里面没有timer_create:
    164 static const struct file_operations posix_clock_file_operations = {
    165         .owner          = THIS_MODULE,
    166         .llseek         = no_llseek,
    167         .read           = posix_clock_read,
    168         .poll           = posix_clock_poll,
    169         .unlocked_ioctl = posix_clock_ioctl,
    170         .open           = posix_clock_open,
    171         .release        = posix_clock_release,
    172 #ifdef CONFIG_COMPAT
    173         .compat_ioctl   = posix_clock_compat_ioctl,
    174 #endif
    175 };

    (1)ops是该dynamic posix clock的操作函数集,分成两个group,一个是timer(例如:timer_create、timer_delete等)以及clock操作相关(例如clock_gettime、clock_settime等),另外一个是普通字符设备的操作函数(例如:open、read、write等)。
    Murick
    2017-10-26 16:30
    CLOCK_MONOTONIC_RAW启动时间点被设成0,此后一直不断累加,而且能设定,不会随NTP调整。
    CLOCK_MONOTONIC_RAW 用户无法设定,?#21019;?#20102;吧?
    江南书生
    2017-05-19 11:42
    ?#20064;澹?#20320;好!

    请问clock和timer有什么不同么?看了这么多文章一直在思考,都?#23884;?#33033;冲计数的啊?请问能不能用个例子说明一下不同呀?
    linuxer
    2017-05-19 15:18
    @江南书生:clock就是钟表啊,从上面可以读取当前时间的一种工具。timer总是基于某个clock而言的,当clock推进到某个时间点的时候会触发调用timer的callback函数。
    andreaji
    2016-10-07 14:14
    只要struct posix_clock包括了cdev成员,struct posix_clock_operations中的owner以及struct posix_clock中的kref应该没有存在的必要了。
    =====================================================================================

    您好 linuxer,请教一个问题:

    我在读 linux-3.19.y 版本的 driver/ptp/ptp_clock.c  时看到使用 ptp clock 模块使用 posix_clock_register 注册 posix clock 时 posix_clock_operations 结构体 ptp_clock_ops 的 owner 设置为 THIS_MODULE(我理解这个 THIS_MODULE 为 ptp clock 模块)

    static struct posix_clock_operations ptp_clock_ops = {
        .owner        = THIS_MODULE,
            ... ...
    };

    进入 posix_clock_register 函数时将 posix_clock -> cdev.owner 也设置为 ptp_clock_ops.owner

    int posix_clock_register(struct posix_clock *clk, dev_t devid)
    {
            ... ...

        cdev_init(&clk->cdev, &posix_clock_file_operations);
        clk->cdev.owner = clk->ops.owner;
        
            ... ...
    }

    可是在 posix-clock.c 中 file_operations 结构体 posix_clock_file_operations(也就是上面 cdev_init 函数中传入的 file_operations 结构体)的 owner 被设置为 THIS_MODULE,这个 THIS_MODULE 指的是什么?如果指的是 posix-clock 的话,会不会又矛盾?

    请教一下 linuxer 对于这样的设计,您是怎么看?
    linuxer
    2016-10-08 11:30
    @andreaji:这里的回复不能画图,所以我在http://www.71402172.com/forum/viewtopic.php?pid=448#p448回复了你,请参考。
    andreaji
    2016-10-10 11:05
    @linuxer:您好 Linuxer,?#34892;?#24744;的及时回复,不过?#19968;?#26377;一事不明:

    posix-clock.c 中并没有使用 module_init 宏,所以我不理解 posix clock 如何能够成为独立的内核模块。

    这也是我无法判断 posix_clock_file_operations.owner 到底是是指向 ptp_clock 模块还是指向 posix clock 的根本原因。

    还请 Linuxer 指点一下。多谢!
    linuxer
    2016-10-10 21:40
    @andreaji:posix_clock_file_operations.owner 不会指向ptp_clock 模块的struct module数据结构的,因为它不属于ptp_clock 模块而是属于posix-clock.c这个模块。当posix-clock.c不是编译成模块而是build in kernel,那么posix_clock_file_operations.owner 等于NULL。
    andreaji
    2016-10-11 14:43
    @linuxer:?#34892;?Linuxer !
    tigger
    2015-03-02 11:22
    为什么我的kernel3.10的版本里面,clock_monotonic里面有timer set 跟get 呢?    
    struct k_clock clock_monotonic = {
            .clock_getres    = hrtimer_get_res,
            .clock_get    = posix_ktime_get_ts,
            .nsleep        = common_nsleep,
            .nsleep_restart    = hrtimer_nanosleep_restart,
            .timer_create    = common_timer_create,
            .timer_set    = common_timer_set,
            .timer_get    = common_timer_get,
            .timer_del    = common_timer_del,
        };
    linuxer
    2015-03-02 12:20
    @tigger:clock_monotonic的确有timer set 跟get函数,我是说没有clock set函数。

    发表评论:

    Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog
    连码三全中是什么
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>