2018-07-25 13:49:01 baidu_34045013 阅读数 97

一、引言

练习编写调用内核的时间测量功能为应用程序测量和精确定时。

通过这个实验进一步了解Linux内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。

二、实验内容

问题A:使用ITIMER_REAL型定时器实现一个gettimeofday(),将它设置为每秒产生一个信号,并计算已经经过的秒数。

问题B:使用以上实现的gettimeofday()实现一个精确到微秒级的“壁钟”。

三、实验代码

/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_a main_a.c
*
* Execute: ./main_a
*
*****************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

static void sig_real(int);
static long real_secs = 0;
static struct itimerval realt;


int main(int argc, char *argv[])
{
    signal(SIGALRM, sig_real);
    realt.it_interval.tv_sec  = 0;
    realt.it_value.tv_sec     = 0;
    realt.it_interval.tv_usec = 999999;
    realt.it_value.tv_usec    = 999999;
    setitimer(ITIMER_REAL, &realt, NULL);

    for(;;);
    return 0;
}

static void sig_real(int non) {
    real_secs += 1;
    printf("%ld\r", real_secs);
    fflush(stdout);
}
/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_b main_b.c
*
* Execute: ./main_b
*
*****************************************/
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>

static void sighandle(int);
struct timeval now; 
int today;
int main(){
	struct itimerval v;
	signal(SIGALRM,sighandle);
	v.it_interval.tv_sec = 0;
	v.it_interval.tv_usec = 1;
	v.it_value.tv_sec = 0;
	v.it_value.tv_usec = 1;
	setitimer(ITIMER_REAL, &v, NULL);
	for(;;);
}
static void sighandle(int s){
	gettimeofday(&now, NULL);
	today = now.tv_sec%(3600*24);
    printf("%02d:%02d:%02d:%ld\r",today/3600+8,(today%3600)/60,(today%3600)%60,now.tv_usec);
	fflush(stdout);
}
/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_c main_c.c
*
* Execute: ./main_c
*
*****************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <wait.h>

// 父进程定时中断处理
static void psig_real(int);
static void psig_virtual(int);
static void psig_prof(int);

// 子进程1定时中断处理
static void c1sig_real(int);
static void c1sig_virtual(int);
static void c1sig_prof(int);

// 子进程2定时中断处理
static void c2sig_real(int);
static void c2sig_virtual(int);
static void c2sig_prof(int);

long unsigned int fibonnacci(unsigned int n);

static long p_real_secs     = 0, 
            c1_real_secs    = 0, 
            c2_real_secs    = 0,
            p_virtual_secs  = 0,
            c1_virtual_secs = 0,
            c2_virtual_secs = 0,
            p_prof_secs     = 0,
            c1_prof_secs    = 0,
            c2_prof_secs    = 0;

static struct itimerval p_realt, c1_realt, c2_realt;
static struct itimerval p_virtt, c1_virtt, c2_virtt;
static struct itimerval p_proft, c1_proft, c2_proft;

int main(int argc, char *argv[])
{
    long unsigned fib = 0;
    int pid1, pid2;
    unsigned int fibarg;
    int status;
    int i;
    
    if (argc < 3) {
        printf("Usage: testsig arg1 arg2 arg3\n");
        return 1;
    }


    pid1 = fork();
    if (pid1==0) {

        signal(SIGALRM, c1sig_real);
        signal(SIGVTALRM, c1sig_virtual);
        signal(SIGPROF, c1sig_prof);

        c1_realt.it_interval.tv_sec = 9;
        c1_realt.it_interval.tv_usec = 999999;
        c1_realt.it_value.tv_sec = 9;
        c1_realt.it_value.tv_usec = 999999;
        setitimer(ITIMER_REAL, &c1_realt, NULL);

        c1_virtt.it_interval.tv_sec = 9;
        c1_virtt.it_interval.tv_usec = 999999;
        c1_virtt.it_value.tv_sec = 9;
        c1_virtt.it_value.tv_usec = 999999;
        setitimer(ITIMER_VIRTUAL, &c1_virtt, NULL);

        c1_proft.it_interval.tv_sec = 9;
        c1_proft.it_interval.tv_usec = 999999;
        c1_proft.it_value.tv_sec = 9;
        c1_proft.it_value.tv_usec = 999999;
        setitimer(ITIMER_PROF, &c1_proft, NULL);

        fib = fibonnacci(atoi(argv[1]));

        getitimer(ITIMER_REAL, &c1_realt);
        printf("Child1 fib = %ld\nChild1 Real Time    = %2ldSec: %03ldMsec\n", 
                fib, c1_real_secs+9-c1_realt.it_value.tv_sec,
                (999999-c1_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL, &c1_virtt);
        printf("Child1 Virtual Time = %2ldSec: %03ldMsec\n", 
                c1_virtual_secs+9-c1_virtt.it_value.tv_sec,
                (999999-c1_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF, &c1_proft);
        printf("Child1 Prof Time    = %2ldSec: %03ldMsec\n\n", 
                c1_prof_secs+9-c1_proft.it_value.tv_sec,
                (999999-c1_proft.it_value.tv_usec)/1000);

    } else if ((pid2=fork())==0) {

        signal(SIGALRM, c2sig_real);
        signal(SIGVTALRM, c2sig_virtual);
        signal(SIGPROF, c2sig_prof);

        c2_realt.it_interval.tv_sec = 9;
        c2_realt.it_interval.tv_usec = 999999;
        c2_realt.it_value.tv_sec = 9;
        c2_realt.it_value.tv_usec = 999999;
        setitimer(ITIMER_REAL, &c2_realt, NULL);

        c2_virtt.it_interval.tv_sec = 9;
        c2_virtt.it_interval.tv_usec = 999999;
        c2_virtt.it_value.tv_sec = 9;
        c2_virtt.it_value.tv_usec = 999999;
        setitimer(ITIMER_VIRTUAL, &c2_virtt, NULL);

        c2_proft.it_interval.tv_sec = 9;
        c2_proft.it_interval.tv_usec = 999999;
        c2_proft.it_value.tv_sec = 9;
        c2_proft.it_value.tv_usec = 999999;
        setitimer(ITIMER_PROF, &c2_proft, NULL);

        fib = fibonnacci(atoi(argv[2]));

        getitimer(ITIMER_REAL, &c2_realt);
        printf("Child2 fib = %ld\nChild2 Real Time    = %2ldSec: %03ldMsec\n", 
                fib, c2_real_secs+9-c2_realt.it_value.tv_sec,
                (999999-c2_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL, &c2_virtt);
        printf("Child2 Virtual Time = %2ldSec: %03ldMsec\n", 
                c2_virtual_secs+9-c2_virtt.it_value.tv_sec,
                (999999-c2_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF, &c2_proft);
        printf("Child2 Prof Time    = %2ldSec: %03ldMsec\n\n", 
                c2_prof_secs+9-c2_proft.it_value.tv_sec,
                (999999-c2_proft.it_value.tv_usec)/1000);
    } else {

        // 父进程设置3种定时处理入口
        signal(SIGALRM, psig_real);
        signal(SIGVTALRM, psig_virtual);
        signal(SIGPROF, psig_prof);

        // 初始化父进程3种时间定时器
        p_realt.it_interval.tv_sec = 9;
        p_realt.it_interval.tv_usec = 999999;
        p_realt.it_value.tv_sec = 9;
        p_realt.it_value.tv_usec = 999999;
        setitimer(ITIMER_REAL, &p_realt, NULL);

        p_virtt.it_interval.tv_sec = 9;
        p_virtt.it_interval.tv_usec = 999999;
        p_virtt.it_value.tv_sec = 9;
        p_virtt.it_value.tv_usec = 999999;
        setitimer(ITIMER_VIRTUAL, &p_virtt, NULL);

        p_proft.it_interval.tv_sec = 9;
        p_proft.it_interval.tv_usec = 999999;
        p_proft.it_value.tv_sec = 9;
        p_proft.it_value.tv_usec = 999999;
        setitimer(ITIMER_PROF, &p_proft, NULL);

        fib = fibonnacci(atoi(argv[3]));

        getitimer(ITIMER_REAL, &p_realt);
        printf("Parent fib = %ld\nParent Real Time    = %2ldSec: %03ldMsec\n", 
                fib, p_real_secs+9-p_realt.it_value.tv_sec,
                (999999-p_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL, &p_virtt);
        printf("Parent Virtual Time = %2ldSec: %03ldMsec\n", 
                p_virtual_secs+9-p_virtt.it_value.tv_sec,
                (999999-p_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF, &p_proft);
        printf("Parent Prof Time    = %2ldSec: %03ldMsec\n\n", 
                p_prof_secs+9-p_proft.it_value.tv_sec,
                (999999-p_proft.it_value.tv_usec)/1000);
        waitpid(0, &status, 0);
        waitpid(0, &status, 0);
    }
    return 0;
}

static void psig_real(int non) {
    p_real_secs += 10;
}
static void psig_virtual(int non) {
    p_virtual_secs += 10;
}
static void psig_prof(int non) {
    p_prof_secs += 10;
}
static void c1sig_real(int non) {
    c1_real_secs += 10;
}
static void c1sig_virtual(int non) {
    c1_virtual_secs += 10;
}
static void c1sig_prof(int non) {
    c1_prof_secs += 10;
}
static void c2sig_real(int non) {
    c2_real_secs += 10;
}
static void c2sig_virtual(int non) {
    c2_virtual_secs += 10;
}
static void c2sig_prof(int non) {
    c2_prof_secs += 10;
}

long unsigned int fibonnacci(unsigned int n) {
    if (n < 3) return 1;
    return fibonnacci(n-1)+fibonnacci(n-2);
}

四、运行结果

如有错误请指正

2015-08-07 08:46:49 chunlovenan 阅读数 15917

第一类延时函数原型是:(忙等)

void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs); 

说明:内核函数 ndelay, udelay, 以及 mdelay 对于短延时好用, 分别延后执行指定的纳秒数, 微秒数或者毫秒数. 它们涉及到的延时常常是最多几个毫秒

第二类延时函数原型是:(使进程进入休眠)
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds) 
这类方法获得毫秒(和更长)延时而不用涉及到忙等待,前2 个函数使调用进程进入睡眠给定的毫秒数. 
一个对 msleep 的调用是不可中断的; 你能确保进程睡眠至少给定的毫秒数. 
如果你的驱动位于一个等待队列并且你想唤醒来打断睡眠, 使用 msleep_interruptible. 从 msleep_interruptible 的返回值正常地是 0; 如果这个进程被提早唤醒, 返回值是在初始请求睡眠周期中剩余的毫秒数. 对 ssleep 的调用使进程进入一个不可中断的睡眠给定的秒数.


区别:

mdelay是忙等待函数,在延迟过程中无法运行其他任务.这个延迟的时间是准确的.是需要等待多少时间就会真正等待多少时间.
msleep是休眠函数,它不涉及忙等待.你如果是msleep(10),那实际上延迟的时间,大部分时候是要多于10ms的,是个不定的时间值.

根据个人经验,10ms以下的延时对时序要求比较高的地方最好还是用mdelay,100ms以上的延时最好还是用msleep,100ms以上的延迟
对linux的多任务系统运行还是有一定影响的。至于10ms到100ms之间的延时看时序的要求情况和应用场景灵活决定了。



在Linux Driver开发中,经常要用到延迟函数:msleep,mdelay/udelay.

虽然msleep和mdelay都有延迟的作用,但他们是有区别的.

1.)对于模块本身

mdelay是忙等待函数,在延迟过程中无法运行其他任务.这个延迟的时间是准确的.是需要等待多少时间就会真正等待多少时间.

msleep是休眠函数,它不涉及忙等待.你如果是msleep(10),那实际上延迟的时间,大部分时候是要多于10ms的,是个不定的时间值.


2.)对于系统:

mdelay() 会占用cpu资源,导致其他功能此时也无法使用cpu资源。

msleep() 则不会占住cpu资源,其他模块此时也可以使用cpu资源。

delay函数是忙则等待,占用CPU时间;而sleep函数使调用的进程进行休眠。


3.)udelay() mdelay() ndelay() 区别:

udelay(); mdelay(); ndelay();实现的原理本质上都是忙等待,ndelay和mdelay都是通过udelay衍生出来的。

我们使用这些函数的实现往往会碰到编译器的警告implicit declaration of function 'udelay',这往往是由于头文件的使用不当造成的。

在include/asm-***/delay.h中定义了udelay(),而在include/linux/delay.h中定义了mdelay和ndelay.

udelay一般适用于一个比较小的delay,如果你填的数大于2000,系统会认为你这个是一个错误的delay函数,因此如果需要2ms以上的delay需要使用mdelay函数。


4.)msleep,ssleep区别:

休眠单位不同


5.)秒的单位

ms是毫秒=0.001秒

us是微秒=0.000001秒

ns是纳秒=0.000000001秒


参考文献:

http://blog.chinaunix.net/uid-26707720-id-3425774.html

http://www.52rd.com/Blog/Detail_RD.Blog_wangh6620_67531.html

http://blog.csdn.net/cbk861110/article/details/40747139


2019-05-15 09:11:14 Chasing_Chasing 阅读数 122

33.1 前言

对于Linux驱动开发来说,我们不可避免会使用到延时函数,其中最为常见的延时函数有msleep、usleep(sleep这些是睡眠不占用cpu的),还有mdelay、udelay(delay是CPU忙等待,定时精准但占用cpu),上述延时函数各有优缺点。对于普通情况的延时,也就是多一秒也没大关系的用sleep类延时函数完全没问题,对于有精准延时的用delay类函数一般也没啥问题。如果涉及到硬件时序操作的,我们必定要使用精准的延时函数,如果在对应的地方使用不精准的sleep类延时函数,则会出现下面时序巨大的时序偏差。

                              

然而,如果使用delay函数对于系统性能来说是一个硬伤害,CPU忙等待表示CPU干不了其它事情,只能瞎等。因此,为了解决这种资源浪费问题,必须用另外一个办法解决,那就是使用高精度定时器+条件等待,实现延时函数的功能。

33.2 hrtimer高精度定时器

内核从2.6.16开始加入了高精度定时器架构,高精度定时器架构具有稳定快速的查找、插入、删除定时能力及排序功能,红黑树(rbtree)来组织hrtimer,红黑树已经以库的形式存在于内核中,并被成功地使用在内存管理子系统和文件系统中,随着系统的运行,hrtimer不停地被创建和销毁,新的hrtimer按顺序被插入到红黑树中,树的最左边的节点就是最快到期的定时器,内核用一个hrtimer结构来表示一个高精度定时器。

hrtimer相关函数

void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode)

高精度定时器初始化;timer高精度定时器数据结构;clockid定时的时间类型(如实时时间、开机时间);mode定时器模式

hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)

高精度定时器启动;timer定时器结构;tim定时时间;mode定时器模式

ktime_t ktime_set(const long secs, const unsigned long nsecs)

定时器时间设定函数;secs秒;nsecs纳秒

hrtimer_forward_now(struct hrtimer *timer, ktime_t interval)

设置超时时间;interval下次超时时间

int hrtimer_cancel(struct hrtimer *timer)

关闭定时器

enum hrtimer_restart (*function)(struct hrtimer *)

定时器超时回调函数

33.3 Linux等待队列

在驱动开发中,有时不可避免需要进行阻塞,如当硬件数据未准备好,此时程序必须阻塞等待数据准备好才能读,否则读取到的数据内容将是无效数据。为了支持应用层这种阻塞与非阻塞的功能,驱动程序就需要提供阻塞(如等待队列,中断)和非阻塞方式(如轮询,异步通知)机制。

Linux内核中,等待队列是常用的阻塞条件出发机制,在数据或任务不能被读取或执行时,将要执行的任务放入等待队列中,当条件到达及唤醒等待队列时再执行即可。

等待队列阻塞分为ASK_UNINTERRUPTIBLE(不可打断)模式睡眠、TASK_INTERRUPTIBLE(可打断)模式睡眠,在不可打断睡眠中,就算发送kill信号程序也不会响应。

等待队列函数

wait_queue_head_t queue;

等待队列结构

init_waitqueue_head(wait_queue_head_t* queue)

初始化等待队列;

wait_event(*queue, int condition)

不可打断等待;condition等待条件

wait_event_interruptible(*queue, int condition)

可打断等待模式;

wait_event_timeout(queue, condition, timeout)

超时条件等待不可中断函数;

wait_event_interruptible_timeout(queue, condition, timeout)

超时条件等待可中断函数

wake_up(wait_queue_head_t *queue);

等待唤醒queue所有进程

wake_up_interruptible(wait_queue_head_t *queue)

等待唤醒queue所有进程

33.4 高精度定时器延时驱动实例

#include <linux/module.h>    
#include <linux/kernel.h>    
#include <linux/hrtimer.h>    
#include <linux/jiffies.h>    
  
struct _stIdelayMngr{  
    int nQueWaiting;                    /*等待队列条件*/  
    wait_queue_head_t iwaitQue;         /*等待队列*/  
    struct hrtimer ihrtimer;            /*高精度定时器*/  
};  
struct _stIdelayMngr stIdelayMngr;  
  
//示例程序  
int hrtimer_main()  
{  
    while(1)  
    {  
        /*启动高精度定时器,结合等待队列延时1ms*/      
        hrtimer_start(&stIdelayMngr.ihrtimer,ktime_set(0,1000*1000),HRTIMER_MODE_REL);  
        wait_event(stIdelayMngr.iwaitQue,stIdelayMngr.nQueWaiting);  
        stIdelayMngr.nQueWaiting = 0;  
  
        /*do something you want*/  
        //.....  
    }  
    return 0;  
}  
  
/* 定时器回调函数 */    
static enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)    
{  
    stIdelayMngr.nQueWaiting = 1;  
    wake_up(&stIdelayMngr.iwaitQue);  
    return HRTIMER_NORESTART;  
}  
  
static int __init hrtimer_demo_init(void)    
{  
    memset(&stIdelayMngr,0,sizoef(stIdelayMngr));  
    /*初始化等待队列*/  
    stIdelayMngr.nQueWaiting = 0;  
    init_waitqueue_head(&stIdelayMngr.iwaitQue);  
  
    /*初始化高精度定时器*/  
    hrtimer_init(&stIdelayMngr.ihrtimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);    
    stIdelayMngr.ihrtimer.function = hrtimer_hander;    /* 设置回调函数 */    
    hrtimer_start(&stIdelayMngr.ihrtimer,ktime_set(1,0),HRTIMER_MODE_REL);  /* hrtimer启动 */    
  
    return 0;    
}  
  
static void __exit hrtimer_demo_exit(void)    
{  
    /* hrtimer注销 */    
    hrtimer_cancel(&stIdelayMngr.ihrtimer);  
}  
  
module_init(hrtimer_demo_init);    
module_exit(hrtimer_demo_exit);    
MODULE_LICENSE("GPL");  

 

 

 

2019-11-06 10:25:18 qq153471503 阅读数 575

STM32CUBEMX系列教程之HAL库方式的微秒延时函数


标准库一般是使用系统嘀嗒定时器来进行微妙级别的延时,而HAL库官方使用SysTick的地方非常多,改代码容易引起错乱。网上的代码使用定时器进行微秒级别延时(不知道该方式的请自行搜索),总是卡在__HAL_TIM_GET_COUNTER,所以自己实现一个微秒级别延时函数尤为重要。


1、第一种方式

#define CPU_FREQUENCY_MHZ    72		// STM32时钟主频
void delay_us(__IO uint32_t delay)
{
    int last, curr, val;
    int temp;

    while (delay != 0)
    {
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0)
        {
            do
            {
                val = SysTick->VAL;
            }
            while ((val < last) && (val >= curr));
        }
        else
        {
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            {
                val = SysTick->VAL;
            }
            while ((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}

2、第二种方式

void delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while (delay--)
	{
		;
	}
}

在这里插入图片描述


2013-11-07 21:59:11 gnefniu 阅读数 548

一.实验目的

本实验是练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。通过这个实验我们可以进一步理解Linux内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。

二.实验问题

1、使用操作系统提供的定时机制实现一个精确到微秒级的闹钟

2、支持用户设置最多4个闹铃

三.实验代码

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/time.h>
int count=0;
struct timeval thetime;
//信号发生函数
void handle(int num)
{
count++;
printf("The %d time is over\n",num);
}
//求去当前时间和闹钟时间的时间差,精确到微妙
struct timeval nowtime(int b[4])
{
int a[3];
time_t   now;       
struct   tm     *timenow; 
char s[100];
time(&now);
timenow   =   localtime(&now);
strcpy(s,asctime(timenow));
a[0]=(s[11]-48)*10+s[12]-48;
a[1]=(s[14]-48)*10+s[15]-48;
a[2]=(s[17]-48)*10+s[18]-48;
thetime.tv_sec=(b[0]-a[0])*3600+(b[1]-a[1])*60+b[2]-a[2];
thetime.tv_usec=b[3];
return thetime;
}
//建立闹钟,并行处理
void deal()
{
struct itimerval tick;
tick.it_interval.tv_usec=0;
tick.it_interval.tv_sec=0;
int i;
tick.it_value.tv_sec=thetime.tv_sec;
tick.it_value.tv_usec=thetime.tv_usec;
if(fork())
{
signal(SIGALRM,handle);
setitimer(ITIMER_REAL,&tick,NULL);
while(1)
pause;
}
}
void main()
{
int num,i,j;
int a[4];
//输入闹钟个数
printf("Please input the space interval:\n");
scanf("%d",&num);
for(i=0;i<num;i++)
{
scanf("%d:%d:%d %d",&a[0],&a[1],&a[2],&a[3]);
handle(i+1);
thetime=nowtime(a);
deal();
}
}

       在Linux中,存在三种定时机制ITIMER_REAL,ITIMER_VIRTUAL和ITIMER_PROF,他们各自有不同的作用,每个定时都要设定一个值,然后随时间递减,当递减到0时,闹钟就会被触发。在代码中,利用time_t数据结构,可以得到毫秒级的时间,当前时间可以获得,再将闹钟时间转化为秒级和毫秒,相减,会获得一个毫秒级时间差。再把这个时间差作为setitimer函数的参数,依次递减,直到为0触发闹钟。

       在实验中,要求要最多设置4个闹钟,所以每个闹钟要并行处理,互不干涉。所以要为每个闹钟设置一个进程,在这个闹钟信号触发后,杀死进程,本次闹钟结束。


20110105


Linux 内核延时

阅读数 388

linux微秒时间

阅读数 111

没有更多推荐了,返回首页