linux定时器

linux定时器
linux定时器

Linux下的定时器:alarm()与setitimer()

2008年04月29日星期二 10:17

Linux下的定时器有两种,以下分别介绍:

1、alarm

如果不要求很精确的话,用alarm()和signal()就够了

unsigned int alarm(unsigned int seconds)

函数说明: alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

返回值: 返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。

alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。

2、setitimer()

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));

setitimer()比alarm功能强大,支持3种类型的定时器:

ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。

ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。

ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。

setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。

setitimer()调用成功返回0,否则返回-1。

下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:

(1) struct itimerval

itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后再将it_value设置为it_interval值.

(2) setitimer()

setitimer()为其所在进程设置一个定时器,如果itimerval.it_interval 不为0(it_interval的两个域都不为0),则该定时器将持续有效(每隔一段时间就会发送一个信号)

注意:Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统

中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。

linux定时器详解

Linux内核定时器详解 80X86体系结构上,常用的定时器电路 实时时钟(RTC) RTC内核通过IRQ8上发出周期性的中断,频率在2-8192HZ之间,掉电后依然工作,内核通过访问0x70和0x71 I/O端口访问RTC。 时间戳计时器(TSC) 利用CLK输入引线,接收外部振荡器的时钟信号,该计算器是利用64位的时间戳计时器寄存器来实现额,与可编程间隔定时器传递来的时间测量相比,更为精确。 可编程间隔定时器(PIT) PIT的作用类似于微波炉的闹钟,PIT永远以内核确定的固定频率发出中断,但频率不算高。 CPU本地定时器 利用PIC或者APIC总线的时钟计算。 高精度时间定时器(HPET) 功能比较强大,家机很少用,也不去记了。 ACPI电源管理定时器 它的时钟信号拥有大约为3.58MHZ的固定频率,该设备实际上是一个简单的计数器,为了读取计算器的值,内核需要访问某个I/O端口,需要初始化 定时器的数据结构 利用timer_opts描述定时器 Timer_opts的数据结构 Name :标志定时器员的一个字符串 Mark_offset :记录上一个节拍开始所经过的时间,由时钟中断处理程序调用 Get_offset 返回自上一个节拍开始所经过的时间

Monotonic_clock :返回自内核初始化开始所经过的纳秒数 Delay:等待制定数目的“循环” 定时插补 就好像我们要为1小时35分34秒进行定时,我们不可能用秒表去统计,肯定先使用计算时的表,再用计算分的,最后才用秒表,在80x86架构的定时器也会使用各种定时器去进行定时插补,我们可以通过cur_timer指针来实现。 单处理器系统上的计时体系结构 所有与定时有关的活动都是由IRQ线0上的可编程间隔定时器的中断触发。 初始化阶段 1. 初始化间,time_init()函数被调用来建立计时体系结构 2. 初始化xtime变量(xtime变量存放当前时间和日期,它是一个timespec 类型的数据结构) 3. 初始化wall_to_monotonic变量,它跟xtime是同一类型的,但它存放将加在xtime上的描述和纳秒数,这样即使突发改变xtime也不会受到影响。 4. 看是否支持高精度计时器HPET 5. 调用select_timer()挑选系统中可利用的最好的定时资源,并让 cur_timer变量指向该定时器 6. 调用setup_irq(0,&irq0)来创建与IRQ相应的中断门。 时钟中断处理程序 1. 在xtime_lock顺序锁产生一个write_seqlock()来保护与定时相关的内核变量,这样防止中断让该进程被阻止。 2. 执行cur_timer定时器对象的mark_offset方法(记录上一个节拍开始所经过的时间,由时钟中断处理程序调用) 3. 调用do_timer_interrupt函数,步骤为 a) 使jiffies_64值增1 b) 调用updata_times()函数来更新系统日期和时间。

Linux复习(成熟期版)

前面的可能考选择题,填空题,全部题型如下: 一、选择题(10个题,每题2分,共20分) 二、填空题(10个空,每空2分,共20分) 三、程序阅读题(2道题,共20分) 四、程序注释(1道题,共20分)可能考I/O 五、编程题(1道题,共20分) P 154 文件I/O操作open()、read()、write()、lseek()和close() 仔细阅读程序,能写注释或填空。 /* copy_file.c */ #include #include #include #include #include #include #define BUFFER_SIZE 1024/* 每次读写缓存大小1KB,关于《linux读写文件运行效率》的传送门*/ #define SRC_FILE_NAME "src_file" /* 源文件名,之后用SRC_FILE_NAME代替src_file */ #define DEST_FILE_NAME "dest_file" /* 目标文件名文件名,之后用DEST_FILE_NAME代替dest_file */ #define OFFSET 10240/* 复制的数据大小 1MB,也是lseek函数的偏移量*/ int main() { int src_file, dest_file; //定义了2个变量 unsigned char buff[BUFFER_SIZE]; //设定缓存的大小,定义为数组,存放读写缓存 int real_read_len; /* 以只读方式打开源文件 */ src_file = open(SRC_FILE_NAME, O_RDONLY); //前面的src_file是变量名,成功时为3,失败时为-1 //也可以写成src_file = open("src_file", O_RDONLY); /* 以只写方式打开目标文件,若此文件不存在则创建该文件, 访问权限值为644 */ dest_file = open(DEST_FILE_NAME, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); //前面的dest_file是变量名,成功时为4,失败时为-1 //也可以写成 d est_file = open("dest_file",O_WRONLY|O_CREAT,644); if (src_file < 0 || dest_file < 0) //打开文件失败时 { printf("Open file error\n"); //输出这句话 exit(1); // exit()中,1是返回给操作系统的,0是正常退出 } /* 将源文件的读写指针移到最后10KB的起始位置*/ lseek(src_file, -OFFSET, SEEK_END); //从文件的结尾处向前移动10KB // OFFSET 是偏移量,正值向前移,负值向后移。这里在 OFFSET 前加了负号。 // SEEK_END 表示从文件的结尾开始。 //也可以写成lseek("src_file", -10240, SEEK_END); /* 读取源文件的最后10KB数据并写到目标文件中,每次读写1KB */ while ((real_read_len = read(src_file, buff, sizeof(buff))) > 0)//读取成功时返回读到的字节数//红字部分也可以写成 read("src_file", buff, 1024) { write(dest_file, buff, real_read_len); // real_read_len 在上一步被赋值为 1KB,即real_read_len = 1024; //也可以写成write("src_file", buff, 1024)

linux定时器和Jiffies

1.linux HZ Linux核心几个重要跟时间有关的名词或变数,以下将介绍HZ、tick与jiffies。 HZ Linux核心每隔固定周期会发出timer interrupt (IRQ 0),HZ是用来定义每一秒有几次timer interrupts。举例来说,HZ为1000,代表每秒有1000次timer interrupts。 HZ可在编译核心时设定,如下所示(以核心版本 adrian@adrian-desktop:~$ cd /usr/src/linux adrian@adrian-desktop:/usr/src/linux$ make menuconfig Processor type and features ---> Timer frequency (250 HZ) ---> 其中HZ可设定100、250、300或1000。 小实验 观察/proc/interrupt的timer中断次数,并于一秒后再次观察其值。理论上,两者应该相差250左右。 adrian@adrian-desktop:~$ cat /proc/interrupts | grep timer && sleep 1 && cat /proc/interrupts | grep timer 0: 9309306 IO-APIC-edge timer 0: 9309562 IO-APIC-edge timer 上面四个栏位分别为中断号码、CPU中断次数、PIC与装置名称。

要检查系统上HZ的值是什么,就执行命令 cat kernel/.config | grep '^CONFIG_HZ=' 2.Tick Tick是HZ的倒数,意即timer interrupt每发生一次中断的时间。如HZ为250时,tick为4毫秒(millisecond)。 3.Jiffies Jiffies为Linux核心变数(unsigned long),它被用来记录系统自开机以来,已经过了多少tick。每发生一次timer interrupt,Jiffies变数会被加一。值得注意的是,Jiffies于系统开机时,并非初始化成零,而是被设为-300*HZ (arch/i386/kernel/time.c),即代表系统于开机五分钟后,jiffies 便会溢位。那溢位怎么办?事实上,Linux核心定义几个macro(timer_after、time_after_eq、time_before与time_before_eq),即便是溢位,也能借由这几个macro正确地取得jiffies的内容。 另外,80x86架构定义一个与jiffies相关的变数jiffies_64 ,此变数64位元,要等到此变数溢位可能要好几百万年。因此要等到溢位这刻发生应该很难吧。

linux定时器详解

查看文章 Linux 定时器设置(一)2010-04-12 17:07定时器设置函数alarm设置的定时器只能精确到秒,而以下函数理论上可以精确到微妙: #include #include int getitimer(int which, struct itimerval *value); int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); 函数setitimer可以提供三种定时器,它们相互独立,任意一个定时完成都将发送定时信号到进程,并且自动重新计时。参数which确定了定时器的类型,如表10-6所示:表10-6 参数which与定时器类型取值含义信号发送ITIMER_REAL 定时真实时间,与alarm类型相同。SIGALRM ITIMER_VIRT 定时进程在用户态下的实际执行时间。 SIGVTALRM ITIMER_PROF 定时进程在用户态和核心态下的实际执行时间。SIGPROF 这三种定时器定时完成时给进程发送的信号各不相同,其中ITIMER_REAL类定时器发送SIGALRM信号,ITIMER_VIRT类定时器发送SIGVTALRM信号,ITIMER_REAL类定时器发送SIGPROF信号。函数alarm本质上设置的是低精确、非重载的ITIMER_REAL类定时器,它只能精确到秒,并且每次设置只能产生一次定时。函数setitimer设置的定时器则不同,它们不但可以计时到微妙(理论上),还能自动循环定时。 在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器。结构itimerval描述了定时器的组成:struct itimerval { struct tim. it_interval; /* 下次定时取值*/ struct tim. it_value; /* 本次定时设置值*/} 结构tim.描述了一个精确到微妙的时间:struct tim. { long tv_sec; /* 秒(1000000微秒)*/ long tv_usec; /* 微妙*/}函数setitimer设置一个定时器,参数value指向一个itimerval结构,该结构决定了设置的定时器信息,结构成员it_value指定首次定时的时间,结构成员it_interval指定下次定时的时间。定时器工作时,先将it_value的时间值减到0,发送一个信号,再将it_value赋值为it_interval的值,重新开始定时,如此反复。如果it_value 值被设置为0,则定时器停止定时;如果it_value值不为0但it_interval值为0,则定时器在一次定时后终止。函数setitimer调用成功时返回0,否则返回-1,参数ovalue如果不为空,返回上次的定时器状态。函数getitimer获取当前的定时器状态,整型参数which指定了读取的定时器类型,参数value返回定时器状态。函数调用成功返回0,否则返回-1。 例1. 设置一个定时器,每2.5秒产生一个SIGALRM信号。答:将itimerval结构的成员it_interval和成员it_value均赋值为 2.5秒即可:struct itimerval value;value.it_https://www.360docs.net/doc/9810622978.html,_sec=2;value.it_https://www.360docs.net/doc/9810622978.html,_usec=500000;value.it_https://www.360docs.net/doc/9810622978.html,_sec=2;value.it_i https://www.360docs.net/doc/9810622978.html,_usec=500000;setitimer(ITIMER_REAL, &value, NULL);函数setitimer设置的定时器可以重复定时,无需多次调用。例2. 设置一个定时器,进程在用户态下执行1秒钟后发出首次信号,以后进程每在用户态下执行3秒钟,发送一个信号。答:将itimerval结构的成员it_value均赋值为1秒,成员it_interval赋值为3秒即可:struct itimerval value;value.it_https://www.360docs.net/doc/9810622978.html,_sec=1;value.it_https://www.360docs.net/doc/9810622978.html,_usec=0;value.it_https://www.360docs.net/doc/9810622978.html,_sec=3;value.it_interva https://www.360docs.net/doc/9810622978.html,_usec=0;setitimer(ITIMER_VIRT, &value, NULL);例3. 取消一个ITIMER_PROF类定时器。答:将itimerval结构的成员it_value均赋值为0秒即可:struct itimerval value;value.it_https://www.360docs.net/doc/9810622978.html,_sec=1;value.it_https://www.360docs.net/doc/9810622978.html,_usec=0;setitimer(ITIMER_PROF, &value, NULL);例4. 设置一个定时1.5秒的真实时间定时器,它仅发送一次信号就自动取消。答:将itimerval结构的成员it_value均赋值为1.5秒,成员it_interval赋值为0秒即可:struct

LINUX内核时钟中断机制

Linux内核的时钟中断机制 opyright © 2003 by 詹荣开 E-mail:zhanrk@https://www.360docs.net/doc/9810622978.html, Linux-2.4.0 Version 1.0.0,2003-2-14 摘要:本文主要从内核实现的角度分析了Linux 2.4.0内核的时钟中断、内核对时间的表示等。本文是为那些想要了解Linux I/O子系统的读者和Linux驱动程序开发人员而写的。 关键词:Linux、时钟、定时器 申明:这份文档是按照自由软件开放源代码的精神发布的,任何人可以免费获得、使用和重新发布,但是你没有限制别人重新发布你发布内容的权利。发布本文的目的是希望它能对读者有用,但没有任何担保,甚至没有适合特定目的的隐含的担保。更详细的情况请参阅GNU 通用公共许可证(GPL),以及GNU自由文档协议(GFDL)。 你应该已经和文档一起收到一份GNU通用公共许可证(GPL)的副本。如果还没有,写信给:The Free Software Foundation, Inc., 675 Mass Ave, Cambridge,MA02139, USA 欢迎各位指出文档中的错误与疑问。 前言 时间在一个操作系统内核中占据着重要的地位,它是驱动一个OS内核运行的“起博器”。一般说来,内核主要需要两种类型的时间: (1)、在内核运行期间持续记录当前的时间与日期,以便内核对某些对象和事件作时间标记(timestamp,也称为“时间戳”),或供用户通过时间syscall进行检索。 (2)、维持一个固定周期的定时器,以提醒内核或用户一段时间已经过去了。 PC机中的时间是有三种时钟硬件提供的,而这些时钟硬件又都基于固定频率的晶体振荡

内核2.6.X中的时钟与定时器

内核2.6.X中的时钟与定时器 2007年07月11日星期三 15:47 时钟和定时器对Linux内核来说十分重要。首先内核要管理系统的运行时间(uptime)和当前墙上时间(wall time),即当前实际时间。其次,内核中大量的活动由时间驱动(time driven)。其中一些活动是周期性的,比如调度调度器(scheduler)中的运行队列(runqueue)或者刷新屏幕这样的活动,它们以固有的频率定时发生;同时,内核要非周期性地调度某些函数在未来某个时间发生,比如推迟执行的磁盘I/O操作等。 实时时钟 --------------------------------------------------------- 内核必须借助硬件来实现时间管理。实时时钟(real time clock)是用来持久存放系统时间的设备,它与CMOS集成在一起,并通过主板电池供电,所以即便在关闭计算机系统之后,实时时钟仍然能继续工作。 系统启动时,内核读取实时时钟,将所读的时间存放在变量xtime 中作为墙上时间(wall time),xtime保存着从1970年1月1日0:00 到当前时刻所经历的秒数。虽然在Intel x86机器上,内核会周期性地将当前时间存回实时时钟中,但应该明确,实时时钟的主要作用就是在启动时初始化墙上时间xtime。

系统定时器与动态定时器 --------------------------------------------------------- 周期性发生的事件都是由系统定时器(system timer)驱动。在X86体系结构上,系统定时器通常是一种可编程硬件芯片(如8254 CMOS芯片),又称可编程间隔定时器(PIT, Programmable Interval Timer),其产生的中断就是时钟中断(timer interrupt)。时钟中断对应的处理程序负责更新系统时间和执行周期性运行的任务。系统定时器的频率称为节拍率(tick rate),在内核中表示为HZ。 以X86为例,在2.4之前的内核中其大小为100;从内核2.6开始,HZ = 1000,也就是说每秒时钟中断发生1000次。这一变化使得系统定时器的精度(resolution)由10ms提高到1ms,这大大提高了系统对于时间驱动事件调度的精确性。过于频繁的时钟中断不可避免地增加了系统开销(overhead),但是总的来说,在现在计算机系统上,HZ = 1000不会导致难以接受的系统开销。 与系统定时器相对的是动态定时器(dynamic timer),它是调度事件(执行调度程序)在未来某个时刻发生的时机。内核可以动态地创建或销毁动态定时器。 系统定时器及其中断处理程序是内核管理机制的中枢,下面是一些利用系统定时器周期执行的工作(中断处理程序所做的工作): (1) 更新系统运行时间(uptime) (2) 更新当前墙上时间(wall time)

linux 内核定时器 timer_list

linux 内核定时器timer_list linux 内核使用timer_list 结构体当作定时器。#include “linux/timer.h” #include “linux/module.h”MODULE_LICENSE(“GPL”);//不加这句话,虽然不影响功能,但有时候程序执行时会打印错误,类似Disabling lock debugging //due to kernel taint 之类的话struct timer_list tm;static int num;static void func(){ num++; mod_timer(&tm,jiffies+1*HZ); //timer 一旦超时,就 会执行fuc 函数,然后永远的休眠,//所以如果没有这mod_timer,hello world 只会执行一次,也就是timer 第一次超时时执行的那次。//mod_timer 可以激活timer。如果你没有add_timer(),激活也没用printk(“hello,world\n ,%d”,num);}static int timer_init(void){ init_timer(&tm); //初始化定时 器,必须在所有下面复制操作前进行定时器初始化tm.expires = jiffies +1*HZ; //超时1 秒,执行function tm.function = func; //超时后执行的函数add_timer(&tm); //将定时器加入定时器等待队列中return 0;}static void timer_destory(void){ del_timer(&tm); printk(“remove timer\n”);}tips:感谢大家 的阅读,本文由我司收集整编。仅供参阅!

linux定时器

Linux下的定时器:alarm()与setitimer() 2008年04月29日星期二 10:17 Linux下的定时器有两种,以下分别介绍: 1、alarm 如果不要求很精确的话,用alarm()和signal()就够了 unsigned int alarm(unsigned int seconds) 函数说明: alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。 返回值: 返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。 alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。

2、setitimer() int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)); setitimer()比alarm功能强大,支持3种类型的定时器: ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。 ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。 ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。 setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。 setitimer()调用成功返回0,否则返回-1。 下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:

Linux实现时钟中断的全过程

Linux实现时钟中断的全过程 1.可编程定时/计数器的初始化 IBM PC中使用的是8253或8254芯片。有关该芯片的详细知识我们不再详述,只大体介绍以下它的组成和作用,如下表5.1所示: 表5.1 8253/8254的组成及作用 计数器0的输出就是图5.3中的Out0,它的频率由操作系统的设计者确定,Linux对8253的初始化程序段如下(在/arch/i386/kernel/i8259.c的init_IRQ ()函数中): set_intr_gate(ox20, interrupt[0]); /*在IDT的第0x20个表项中插入一个中断门。这个门中的段选择符设置成内核代码段的选择符,偏移域设置成0号中断处理程序的入口地址。*/ outb_p(0x34,0x43); /* 写计数器0的控制字:工作方式2*/ outb_p(LATCH & 0xff , 0x40); /* 写计数初值LSB 计数初值低位字 节*/ outb(LATCH >> 8 , 0x40); /* 写计数初值MSB 计数初值高位字节*/ LATCH(英文意思为:锁存器,即其中锁存了计数器0的初值)为计数器0的计数初值,在/include/linux/timex.h中定义如下:

#define CLOCK_TICK_RATE 1193180 /* 图5.3中的输入脉冲 */ #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* 计数器0的计数初值 */ CLOCK_TICK_RATE是整个8253的输入脉冲,如图5.3中所示为1.193180MHz,是近似为1MHz的方波信号,8253内部的三个计数器都对这个时钟进行计数,进而产生不同的输出信号,用于不同的用途。 HZ表示计数器0的频率,也就是时钟中断或系统时钟的频率,在 /include/asm/param.h中定义如下: #define HZ 100 2.与时钟中断相关的函数 下面我们看时钟中断触发的服务程序,该程序代码比较复杂,分布在不同的源文件中,主要包括如下函数: 时钟中断程序:timer_interrupt( ); 中断服务通用例程do_timer_interrupt(); 时钟函数:do_timer( ); 中断安装程序:setup_irq( ); 中断返回函数:ret_from_intr( ); 前三个函数的调用关系如下: timer_interrupt( ) do_timer_interrupt()

linux ipsec 实现

1. 前言 在Linux2.6内核中自带了IPSEC的实现,这样就不用象2.4那样打补丁来实现了。该实现包括以下几个部分: PF_KEY类型套接口, 用来提供和用户层空间进行 PF_KEY通信,代码在net/key目录下,前面已经介绍过;安全联盟SA和安全策略SP管理,是使用xfrm库来实现的,代码在net/xfrm/目录下定义;ESP,AH等协议实现,在net/ipv4(6)下定义;加密认证算法库,在crypto目录下定义,这些算法都是标准代码了。本系列文章主要描述XFRM库的实现以及在IPV4下相关协议的处理部分, IPV6的忽略。 本文Linux内核代码版本为2.6.19.2。xfrm是内核中变化比较大的部分,每个版本中都有不小的差异, 同时也说明了该模块的不成熟性。 在net/xfrm目录下的各文件大致功能说明如下: xfrm_state.c: xfrm状态管理 xfrm_policy.c: xfrm策略管理 xfrm_algo.c: 算法管理 xfrm_hash.c: HASH计算函数 xfrm_input.c: 安全路径(sec_path)处理,用于进入的ipsec包 xfrm_user.c: netlink接口的SA和SP管理 在net/ipv4目录下的和ipsec相关各文件大致功能说明如下: ah4.c: IPV4的AH协议处理 esp4.c: IPV4的ESP协议处理 ipcomp.c: IP压缩协议处理 xfrm4_input: 接收的IPV4的IPSEC包处理 xfrm4_output: 发出的IPV4的IPSEC包处理 xfrm4_state: IPV4的SA处理 xfrm4_policy: IPV4的策略处理 xfrm4_tunnel: IPV4的通道处理 xfrm4_mode_transport: 传输模式 xfrm4_mode_tunnel: 通道模式 xfrm4_mode_beet: BEET模式 2. 数据结构 内核SA的定义用xfrm_state结构定义,SP用xfrm_policy结构定义,在 include/net/xfrm.h中定义。 2.1 状态(SA) xfrm_state状态结构用来描述SA在内核中的具体实现:

Linux 下定时器的实现方式分析

概论 定时器属于基本的基础组件,不管是用户空间的程序开发,还是内核空间的程序开发,很多时候都需要有定时器作为基础组件的支持,但使用场景的不同,对定时器的实现考虑也不尽相同,本文讨论了在 Linux 环境下,应用层和内核层的定时器的各种实现方法,并分析了各种实现方法的利弊以及适宜的使用环境。 首先,给出一个基本模型,定时器的实现,需要具备以下几个行为,这也是在后面评判各种定时器实现的一个基本模型 [1]: StartTimer(Interval, TimerId, ExpiryAction) 注册一个时间间隔为 Interval 后执行 ExpiryAction 的定时器实例,其中,返回TimerId 以区分在定时器系统中的其他定时器实例。 StopTimer(TimerId) 根据 TimerId 找到注册的定时器实例并执行 Stop 。 PerTickBookkeeping() 在一个 Tick 内,定时器系统需要执行的动作,它最主要的行为,就是检查定时器系统中,是否有定时器实例已经到期。注意,这里的 Tick 实际上已经隐含了一个时间粒度(granularity) 的概念。 ExpiryProcessing() 在定时器实例到期之后,执行预先注册好的 ExpiryAction 行为。 上面说了基本的定时器模型,但是针对实际的使用情况,又有以下 2 种基本行为的定时器: Single-Shot Timer 这种定时器,从注册到终止,仅仅只执行一次。 Repeating Timer 这种定时器,在每次终止之后,会自动重新开始。本质上,可以认为 Repeating Timer 是在 Single-Shot Timer 终止之后,再次注册到定时器系统里的 Single-Shot Timer,因此,在支持 Single-Shot Timer 的基础上支持 Repeating Timer 并不算特别的复杂。 回页首

linux下时间和定时器

一、问题的提出 我们开发程序时,经常会遇到时间和定时器的问题,为了更好的使用时间和定时器,现在列举一个一些时间结构体、函数和定时器。 二、解决思路 1.时间类型 1) time_t是一个长整型,一般用来表示用1970年以来的秒数。 2)struct timeval有两个成员,一个是秒,一个是微妙。 struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; 3) struct timespec有两个成员,一个是秒,一个是纳秒。 struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; 4) struct tm是直观意义上的时间表示方法 struct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */ int tm_hour; /* hours */ int tm_mday; /* day of the month */ int tm_mon; /* month */ int tm_year; /* year */ int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ }; 5) struct timeb

{ time_t time; //从1970来经过的秒数 unsigned short millitm; //毫秒 short timezone; //时区 short dstflag;//为日光节约时间的修正值,如果为非0代表启用日光节约修正}; 6) struct timezone { int tz_minuteswest;//和格林尼治时间相差多少分 int tz_dsttime;//日光节约时间的状态 }; 日光节约时间:夏时制。 2.时间函数 1) char *asctime(const struct tm *timeptr) 将时间和日期以字符串格式显示。 2)clock_t clock(void) 取得进程占用cpu的大约时间。 3)char *ctime(const time_t *timep) 将时间和日期以字符串格式显示。 4) double difftime(time_t time1, time_t time0) 计算时间time1和time0间的差距。 5) int ftime(struct timeb *tp) 取得目前的时间和日期。 6) int gettimeofday(struct timeval *tv, struct timezone *tz) 取得目前的时间。 7)strcut tm *gmtime(const time_t *timep) time_t结构时间转tm结构时间,tm为UTC时区。 8) struct tm *localtime(const time_t *timep) 将time_t结构时间转tm结构时间,tm是当地时区。 9)time_t mktime(struct tm *timeptr) 将tm结构时间转换为time_t。 10) int settimeofday(const struct timeval *tv, const struct timezone *tz) 设置时间为tv,设置时区为tz。

Linux下的定时器

简介 这篇文章主要记录我在试图解决如何尽可能精确地在某个特定的时间间隔执行某项具体任务时的思路历程,并在后期对相关的API进行的归纳和总结,以备参考。 问题引出 很多时候,我们会有类似“每隔多长时间执行某项任务”的需求,乍看这个问题并不难解决,实则并不容易,有很多隐含条件需要考虑,诸如:时间精度是多少?时间是否允许出现偏差,允许的偏差是多少,偏差之后如何处理?系统的负载如何?这个程序允许占用的系统资源是否有限制?这个程序运行的硬件平台如何? 为了便于分析,我们锁定题目为“每隔2妙打印当前的系统时间(距离UNIX纪元的秒数)”。 基于sleep的朴素解法 看到这个题目,我想大家的想法和我一样,都是首先想到类似这样的解法: 如果对时间精度要求不高,以上代码确实能工作的很好。因为sleep的时间精度只能到1s:

所以对于更高的时间精度(比如说毫秒)来说,sleep就不能奏效了。如果沿着这个思路走下去,还分别有精确到微妙和纳秒的函数usleep和nanosleep可用: 既然有了能精确到纳秒的nanosleep可用,上面的较低精度的函数也就可以休息了。实际上在Linux系统下,sleep和usleep就是通过一个系统调用nanosleep实现的。 用带有超时功能的API变相实现睡眠 如果开发者不知道有usleep和nanosleep,这个时候他可能会联想到select 类的系统调用:

从函数原型和相关手册来看,poll和epoll_wait能提供的时间精度为毫秒,select比他们两个略胜一筹,为微秒,和前述的usleep相当。但是,果真如此么?这需要我们深入到Linux的具体实现,在内核里,这几个系统调用的超时功能都是通过内核中的动态定时器实现的,而动态定时器的时间精度是由当前内核的HZ数决定的。如果内核的HZ是100,那么动态定时器的时间精度就是1/HZ=1/100=10毫秒。目前,X86系统的HZ最大可以定义为1000,也就是说

Linux定时器实验

Linux第六次实验及分析报告 姓名:徐豪 学号:SA11225049 实验要求: 1)在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限); 2)分析你的程序的实际执行借助了内核的哪些机制; 3)提交实验与分析报告; 一:在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限); 程序源代码如下:

G++进行编译 运行结果如下:

可见调用间隔定时器定时10秒成功! 二:分析你的程序的实际执行借助了内核的哪些机制; realtimer_set()函数分析: void realtimer_set() { struct itimerval itv,oldtv; itv.it_https://www.360docs.net/doc/9810622978.html,_sec=1; itv.it_https://www.360docs.net/doc/9810622978.html,_usec=0;//定义事件为 1s itv.it_https://www.360docs.net/doc/9810622978.html,_sec=1; itv.it_https://www.360docs.net/doc/9810622978.html,_usec=0;//interval=1s setitimer(ITIMER_REAL,&itv,&oldtv);//调用realtimer } 这里声明两个为itimerval类型的结构体itv,oldtv,itimerval 在time.h中的定义。其中,it_interval和it_value分别表示时间间隔和当前值,它们又是timeval类型的结构体,继续追踪: Timeval有两个变量,分别表示秒和微秒, 通过对itv赋值,可以看到,它表示当前时间为1s,间隔为1s。 分析函数setitimer, 执行系统调用do_setitimer,(Itimer.c)

Linux进程状态与调度

Linux进程状态与调度 目录 一.进程的状态 1.schedule_timeout 2.wake_up 3.task_struct current 二.内核与用户空间信号传递fasync 一.进程的状态 1.Schedule_timeout 当我们调用schedule_timeout时,有两种情况能打断该定时器,一种为超时,一种为有信号打断。 在该函数的申明中提到 * %TASK_INTERRUPTIBLE - the routine may return early if a signal is * delivered to the current task. In this case the remaining time * in jiffies will be returned, or 0 if the timer expired in time * * The current task state is guaranteed to be TASK_RUNNING when this * routine returns. 配合schedule_timeout,使用__set_currnet_state.对于支持信号打断的schedule_timeout,调用__set_currnet_state设置task state 为 TASK_INTERRUPIBLE,如下, __set_current_state(TASK_INTERRUPTIBLE); Timeout=schedule_timeout(timeout); __set_current_state(TASK_RUNNING); 调用schedule_timeout如果超时之后会自动设置task_state为 TASK_RUNNING,在调用schedule_timeout之后,进程会进入休眠状态,退出进程调度,只有在有关于此进程的事件到来时会被唤醒(各种信号),重新加入进程调度中。 用过msleep都知道所在的task会sleep 相应ms,而实际上其原理就与schedule_timeout和进程状态有关。 当设置current_state为TASK_UNINTERRUPTIBLE时,只能等待超时,signal 无法打断

linux驱动之内核定时器驱动设计

linux驱动之内核定时器驱动设计 我的环境: Fedora 14 内核版本为2.6.38.1 开发板:ARM9 TQ2440 移植内核版本:linux-2.6.30.4 定时器在linux内核中主要是采用一个结构体实现的。但是需要注意定时器是一个只运行一次的对象,也就是 当一个定时器结束以后,还需要重现添加定时器。但是 可以采用mod_timer()函数动态的改变定时器到达时间。这个驱动主要实现内核定时器的基本操作。内核定时器 主要是是通过下面的结构体struct timer_list实现。需要的头文件包括#include;,但是在实际开发过程中不需要包含该头文件,因为在sched.h中包含了该头文件。 struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long);

unsigned long data; struct tvec_base *base; #ifdef CONFIG_TIMER_STATS void *start_site; char start_comm[16]; int start_pid; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }; 定时器的实现主要是该结构体的填充和部分函数的配合即可完成。其中红色的部分是最主要的几个元素,1、expires主要是用来定义定时器到期的时间,通常采用jiffies这个全局变量和HZ这个全局变量配合设置该元素的值。比如expires = jiffies + n*HZ,其中jiffies 是自启动以来的滴答数,HZ是一秒种的滴答数。 2、function可以知道是一个函数指针,该函数就是定

Linux定时器的使用

Linux定时器的使用 内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于 和kernel/timer.c 文件中。 被调度的函数肯定是异步执行的,它类似于一种“软件中断”,而且是处于非进程的上下文中,所以调度函数必须遵守以下规则: 1) 没有current 指针、不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。 2) 不能执行休眠(或可能引起休眠的函数)和调度。 3) 任何被访问的数据结构都应该针对并发访问进行保护,以防止竞争条件。 内核定时器的调度函数运行过一次后就不会再被运行了(相当于自动注销),但可以通过在被调度的函数中重新调度自己来周期运行。 在SMP系统中,调度函数总是在注册它的同一CPU上运行,以尽可能获得缓存的局域性。 内核定时器的数据结构 struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_base *base; /* ... */ }; 其中expires 字段表示期望定时器执行的jiffies 值,到达该jiffies 值时,将调用function 函数,并传递data 作为参数。当一个定时器被注册到内核之后,entry 字段用来连接该定时器到一个内核链表中。base 字段是内核内部实现所用的。 需要注意的是expires 的值是32位的,因为内核定时器并不适用于长的未来时间点。 初始化 在使用struct timer_list 之前,需要初始化该数据结构,确保所有的字段都被正确地设置。初始化有两种方法。 方法一: DEFINE_TIMER(timer_name, function_name, expires_value, data); 该宏会定义一个名叫timer_name 内核定时器,并初始化其function, expires, name 和base 字段。 方法二: struct timer_list mytimer; setup_timer(&mytimer, (*function)(unsigned long), unsigned long data); mytimer.expires = jiffies + 5*HZ; 注意,无论用哪种方法初始化,其本质都只是给字段赋值,所以只要在运行add_timer() 之

相关主题
相关文档
最新文档