中断屏蔽码上半部屏蔽中断屏蔽码 jiffies还会增加吗

linux内核时间管理
Linux中如何对时间进行管理?时钟节拍的概念及延时函数的用法很多同学都用不好,下面我给大家总结一下。
一,linux时钟运作机制
1,linux时钟运作机制
o 大部分PC机中有两个时钟源,分别是实时时钟(RTC)和 操作系统(OS)时钟
o 实时时钟也叫CMOS时钟,它靠电池供电,即使系统断电,也可以维持日期和时间。
o RTC和OS时钟之间的关系通常也被称作操作系统的时钟运作机制
o 不同的操作系统,其时钟运作机制也不同
linux中的时钟机制大致如下图所示
linux中时钟机制
由上图可知:
RTC是硬件时钟,它为整个计算机提供一个计时标准,是最原始最底层的时钟数据,由纽扣电池供电,系统断电后仍然在工作
OS时钟产生于PC主板上的定时/计数芯片,由操作系统控制这个芯片的工作,OS时钟的基本单位就是该芯片的计数周期,开机时操作系统取得RTC中的时间数据来初始化OS时钟,所以它只是在开机有效,由操作系统控制,已被称为软时钟或系统时钟。操作系统通过OS时钟提供给应用程序和时间有关的服务。
扩展:OS时钟其本质是一个计数器,计数器从计数初值开始,每收到一次脉冲信号,计数器减1,当减至0时,就会输出高电平或低电平,然后获取重载值重新从初值开始计数,不断循环,这样就得到一个输出脉冲,这个脉冲作用中断控制器上,产生中断信号,触发时钟中断。
2,OS时钟中断
o OS时钟是由可编程定时/计数器产生的输出脉冲触发中断而产生的,而输出脉冲的周期叫做一个“时钟节拍”(Tick,又称滴答),(中断触发时会进入中断处理函数,使jiffies+1)
o 操作系统的“时间基准” 由设计者决定,Linux的时间基准是日凌晨0点
o OS时钟记录的时间就是系统时间。系统时间以“时钟节拍”为单位
o时钟中断触发的频率,由内核HZ来确定,系统启动时会按照定义的HZ值对硬件进行设置
比如对HZ的定义如下:
#define Hz100
内核时间频率:表示每秒钟触发100次时钟中断,即每10ms触发一次,
每次中断jiffies+1,,则每秒jiffies增加了100,
o Linux中用全局变量 jiffies表示系统自启动以来的时钟节拍数目(时钟中断触发的次数)
因此系统运行的时间以s为单位计数, 就等于 jiffies/HZ
内核启动时将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值,每秒钟触发中断的次数为Hz,
3、实际时间
实际时间就是现实中钟表上显示的时间,其实内核中并不常用这个时间,主要是用户空间的程序有时需要获取当前时间,所以内核中也管理着这个时间。
实际时间的获取是在开机后,内核初始化时从RTC读取的。
内核读取这个时间后就将其放入内核中的 xtime 变量中,并且在系统的运行中不断更新这个值。
当前实际时间(墙上时间): xtime.tv_sec以秒为单位,存放着自日(UTC)以来经过的时间,日被称为纪元。多数Unix系统的墙上时间都是基于该纪元而言的。xtime.tv_nsec记录自上一秒开始经过的纳秒数。
在&Time.h(incluce/linux)&中
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
struct timespec { /*高精度*/
time_t tv_ /* seconds */
long tv_ /* nanoseconds 纳秒*/
从用户空间取得墙上时间的主要接口是gettimeofday(),在内核中对应的系统调用为sys_gettimeofday():
虽然内核也实现了time()系统调用,但是gettimeofday()几乎完全取代了它。C库函数也提供了墙上时间相关的库调用,比如ftime(),ctime()。
除了更新xtime时间外,内核不会想用户空间程序那样频繁的使用xtime。但是,在文件系统的实现代码中存放访问时间戳(创建,存取,修改等)需要使用xtime。
4,时钟中断处理程序----操作系统的脉搏
每一次时钟中断的产生都触发下列几个主要的操作:
– 给jiffies变量加 1
– 更新时间和日期,既更新xtime墙上时间
– 确定当前进程在CPU 上已运行了多长时间,如果已经超过了分配给它的时间,则抢占它
– 更新资源使用统计数
– 检查定时器时间间隔是否已到,如果是,则执行它注册的函数(运行于底半部软中断中)
以上工作每秒要发生 Hz次,也就是说PC上的时钟中断处理程序执行的频率为Hz
5、时间系统总结
1、节拍-----&jiffies
又称时钟滴答,是一个全局变量,它的值在系统引导的时候初始化为0,在时钟中断初始化完成后,每次时钟中断发生,在时钟中断处理例程中都会将jiffies的值 +1。
jiffies_64:为了解决jiffies溢出问题,更重要的是通过jiffies_64可以知道自开机以来的时间间隔。
2、节拍率----&HZ
HZ表示时钟中断发生的频率。可以在.config的配置文件中改写。1/HZ是每个jiffies+1的时间间隔。
3、通过jiffies可以进行时间的比较和时间转换
4、时间比较
time_after(a,b) time_after64(a,b)
time_before(a,b) time_before64(a,b)
time_after_eq(a,b) time_after_eq64(a,b)
time_before_eq(a,b) time_before_eq64
time_in_range(a,b,c) time_in_range(a,b,c)
5、时间转换
a、jiffies和msecs以及usecs的转换:
unsigned int jiffies_to_msecs(const unsigned long);
unsigned int jiffies_to_usecs(const unsigned long);
unsigned long msecs_to_jiffies(const unsigned int m);
unsigned long usecs_to_jiffies(const unsigned int u);
b、jiffies和timespec以及timeval的转换
在用户空间,应用程序更多的使用秒以及毫秒等时间形式,而在内核中多使用jiffes。
内核定义了struct timeval 和 struct timespec 两种数据结构
struct timespec {
__kernel_time_t tv_
struct timeval {
__kernel_time_t tv_
__kernel_suseconds_t tv_
相互转换函数:
unsigned long timespec_to_jiffies(const struct timespec *value);
void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);
unsigned long timeval_to_jiffies(const struct timeval *value);
void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value);
6、要注意的是jiffies的精度问题。
如果HZ = 1000,则jiffies增加1代表1ms。如果要用到更高精度的始终,要用其他的硬件机制。
二、内核短延时
Linux内核中提供了下列3个函数以分别进行纳秒、微秒和毫秒延迟:
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
上述延迟的实现原理本质上是忙等待,它根据CPU频率进行一定次数的循环。如果没有特殊的理由(比如在中断上下文中获取自旋锁的情况),不推荐使用这些函数延迟较长的时间,浪费CPU。
注:ndelay 和 mdelay都是基于udelay,将udelay的次数除1000就是ndelay,因此ndelay的次数为1000的整数倍才准确。
有时候,人们在软件中进行下面的延迟:
void delay(unsigned int time)
while(time--);
ndelay()、udelay()和mdelay()函数的实现方式原理与此类似。
内核在启动时,会运行一个延迟循环校准(Delay Loop Calibration),计算出lpj(Loops Per Jiffy)即处理器在一个jiffy时间内运行一个内部的延迟循环的次数,内核启动时会打印如下类似信息:
Calibrating delay loop... 530.84 BogoMIPS (lpj=1327104)
如果我们直接在bootloader传递给内核的bootargs中设置lpj=1327104,则可以省掉这个校准的过程节省约百毫秒级的开机时间。
毫秒时延(以及更大的秒时延)已经比较大了,在内核中,最好不要直接使用mdelay()函数,这将耗费CPU资源,对于毫秒级以上的时延,内核提供了下述函数:
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds);
上述函数将使得调用它的进程睡眠参数指定的时间为millisecs,msleep()、ssleep()不能被打断,而msleep_interruptible()则可以被打断。
受系统Hz以及进程调度的影响,msleep()类似函数的精度是有限的。
三、内核长延时
在内核中,一个直观的延时的方法是将所要延迟的时间设置的当前的jiffies加上要延迟的时间,这样就可以简单的通过比较当前的jiffies和设置的时间来判断延时的时间时候到来。针对此方法,内核中提供了简单的宏用于判断延时是否完成。
time_after(a,b); /*如果时间a在b之后 (a>b),则返回真,否则返回0*/
time_before(a,b); /*如果时间a在b之前 (a<b),则返回真,否则返回0*/
长延时实现举例:
/* 延迟 100 个 jiffies */
unsigned long delay = jiffies + 100;
while(time_before(jiffies, delay));
/* 再延迟 2s */
unsigned long delay = jiffies + 2*Hz;
while(time_before(jiffies, delay));
与time_before()对应的还有一个time_after(),它们在内核中定义为(实际上只是将传入的未来时间jiffies和被调用时的jiffies进行一个简单的比较):
#define time_after(a,b)
(typecheck(unsigned long, a) &&
typecheck(unsigned long, b) &&
((long)(b) - (long)(a) & 0))
#define time_before(a,b) time_after(b,a)
为了防止在time_before()和time_after()的比较过程中编译器对jiffies的优化,内核将其定义为
volatile变量,这将保证每次都会重新读取这个变量。因此volatile更多的作用还是避免这种读合并。
四、让进程睡固定的时间
下面两个函数可以将当前进程添加到等待队列中,从而在等待队列上睡眠,当超时发生时,进程将被唤醒:
sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);
interrupt_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);
关注微信公众号:华清远见成都中心(cdfarsight),回复“爱小黄车更爱华清”,领取小黄车90天免费骑行
11月28日,嵌入式星创客精英训练营
11月28日,高校师资班
11月28日,企业内训班
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
今日搜狐热点禁用时钟中断,jiffies就不准了吗_百度知道
禁用时钟中断,jiffies就不准了吗
我有更好的答案
唱歌应该是用定时器来控制的,你的定时中断肯定会影响IO口输出到蜂鸣器的频率 所以声音会变不准,你可以软件做一下调整,避免与定时中断冲突
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。比特客户端
您的位置:
详解大数据
详解大数据
详解大数据
详解大数据
Linux之定时器与时间管理
 企业软件热点文章
  定时器与时间管理:
  1、节拍率――HZ:在alpha体系结构上1024,而在其它平台上,都为10数量级倍。在嵌入式上为100(2.6内核)。这个值的意义是什么呢,也就是在arm平台上时钟中断100次,为一秒。一般的情况下编程者不要改变这个值,因为内核编很多代码都是有时间要求的,而且内核编写都在很多地方都做了相应的优化与折衷处理,改变HZ的值会对系统的性能有很大的影响。
  2、jiffies:这个值是用来记录系统自系统启动以来产生的节拍的总数,启动时,内核将这个变量初始化为0;在每次的时钟中断处理程序都会增加该变量的值,jiffies一秒内增加的值就是HZ,系统运行时间以秒为单位计算,则为系统运行了jiffies/HZ秒。
  在如下定义(2.6内核):
  extern u64 __jiffy_data jiffies_64;
  extern unsigned long volatile __jiffy_
  在2.6的内核中它的变量类型从无符号长整型变为了u64,也就是说,即使是32位的机器,也使用无符号的64位整型表示jiffies。大多数的代码只涉及jiffies的低32位,访问jiffies的代码中会读到jiffies_64的低32位,可以通过get_ jiffies_64()函数读取整个64位。在64位的体系结构中jiffies_64和jiffies指的同一个变量,代码可以既可以通过jiffies也可以通过get_ jiffies_64()读取。
  3、为了避免jiffies值的回绕(溢出),内核中提供了几个API函数来比较节拍计数。定义在中。
  /* time_is_before_jiffies(a) return true if a is before jiffies */
  #define time_is_before_jiffies(a) time_after(jiffies, a)
  /* time_is_after_jiffies(a) return true if a is after jiffies */
  #define time_is_after_jiffies(a) time_before(jiffies, a)
  /* time_is_before_eq_jiffies(a) return true if a is before or equal to jiffies*/
  #define time_is_before_eq_jiffies(a) time_after_eq(jiffies, a)
  /* time_is_after_eq_jiffies(a) return true if a is after or equal to jiffies*/
  #define time_is_after_eq_jiffies(a) time_before_eq(jiffies, a)
  可以利用jiffies设置超时等,譬如:
  unsigned long timeout = jiffies + HZ * 2; // 2秒钟后超时
  if(time_before(jiffies, timeout){
  // 还没有超时
  // 已经超时
  4、时间类型
  下常用的时间类型有4个:time_t,struct timeval,struct timespec,struct tm。一般用于实际时间(墙上时间),定义在文件中。
  (1)time_t是一个长整型,一般用来表示用1970年以来的秒数,格林威治时间。
  (2)Struct timeval有两个成员,一个是秒,一个是微妙。
  struct timeval{
  long tv_ /**//* seconds */
  long tv_ /**//* microseconds */
  (3)struct timespec有两个成员,一个是秒,一个是纳秒。
  struct timespec{
  time_t tv_ /**//* seconds */格林威治时间
  long tv_ /**//* nanoseconds */
  (4)struct tm是直观意义上的时间表示方法:
  struct tm {
  int tm_ /**//* seconds */
  int tm_ /**//* minutes */
  int tm_ /**//* hours */
  int tm_ /**//* day of the month */
  int tm_ /**//* month */
  int tm_ /**//* year */
  int tm_ /**//* day in the year */
  int tm_ /**//* day of the week */
  int tm_ /**//* daylight saving time */
  :一般使用int gettimeofday(struct timeval *tv, struct timezone *tz);得到墙上时间,墙上时间一般会在用户空间里使用,而在内核空间里,大多数情况下只要获取相对时间就OK了,也就是说用jiffies搞定。
  5、内核定时器
  内核定时器可以理解为一个软件定时器,它可以被动态的创建、更改和销毁等,而且运行次数没有限制。
  定时器同结构time_表示,此结构体定义在中。
  struct timer_list {
  struct list_ //包含定时器的链表
  u //以jiffies为单位的定时值
  void (*function)(unsigned long); //定时时间到的处理函数
   //传给片处理函数的参数,可以用在共用一个处理函数的情况。
  struct tvec_base * //内部值,用户呼略是安全的
  #ifdef CONFIG_TIMER_STATS
  void *start_;
  char start_comm[16];
  int start_
  #endif
  #ifdef CONFIG_LOCKDEP
  struct lockdep_map lockdep_
  #endif
  在使用定时器时,没有必要去深入了解这个数据结构体的成员。可以使用在中的API来操作。
  增加定时器
  void add_timer(struct timer_list * timer);
  删除定时器
  int del_timer(struct timer_list * timer);
  修改定时器的expire
  int mod_timer(struct timer_list *timer, unsigned long expires);
  使用定时器的一般流程为:
  (1)定义timer、编写
  (2)为timer的expires、data、function赋值;
  (3)调用add_timer将timer加入列表;
  (4)在定时器到期时,function被执行;
  (5)在程序中涉及timer控制的地方适当地调用del_timer、mod_timer删除timer或修改timer的expires。
  补充:一般应该使用del_timer_sync()来代替del_timer(),在俺的板子上就同没有必要了,因为俺的板子是单的,在SMP中一定要代替使用。
  6、短延迟
  前面所讲到的时间都是很长的了啦,在内核中提供了二个更短延迟的函数来供开发人员使用
  udelay(unsigned long usecs); //微秒
  mdelay(unsigned long msecs); //毫秒
  前者用软件循环指定的微妙数,后者调用前者达到延迟毫秒级。udelay 函数只能用于获取较短的时间延迟,因为loops_per_second值的精度只有8位,所以,当计算更长的延迟时会积累出相当大的误差。尽管最大能允 许的延迟将近1秒(因为更长的延迟就要溢出),推荐的 udelay 函数的参数的最大值是取1000微秒(1毫秒)。延迟大于 11 毫秒时可以使用函数 mdelay。
  :要特别注意的是 udelay 是个忙等待函数(所以 mdelay 也是),在延迟的时间段内无法运行其他的任务,因此要十分小心,尤其是 mdelay,除非别无他法,要尽量避免使用。
[ 责任编辑:之极 ]
去年,手机江湖里的竞争格局还是…
甲骨文的云战略已经完成第一阶段…
软件信息化周刊
比特软件信息化周刊提供以数据库、操作系统和管理软件为重点的全面软件信息化产业热点、应用方案推荐、实用技巧分享等。以最新的软件资讯,最新的软件技巧,最新的软件与服务业内动态来为IT用户找到软捷径。
商务办公周刊
比特商务周刊是一个及行业资讯、深度分析、企业导购等为一体的综合性周刊。其中,与中国计量科学研究院合力打造的比特实验室可以为商业用户提供最权威的采购指南。是企业用户不可缺少的智选周刊!
比特网络周刊向企业网管员以及网络技术和产品使用者提供关于网络产业动态、技术热点、组网、建网、网络管理、网络运维等最新技术和实用技巧,帮助网管答疑解惑,成为网管好帮手。
服务器周刊
比特服务器周刊作为比特网的重点频道之一,主要关注x86服务器,RISC架构服务器以及高性能计算机行业的产品及发展动态。通过最独到的编辑观点和业界动态分析,让您第一时间了解服务器行业的趋势。
比特存储周刊长期以来,为读者提供企业存储领域高质量的原创内容,及时、全面的资讯、技术、方案以及案例文章,力求成为业界领先的存储媒体。比特存储周刊始终致力于用户的企业信息化建设、存储业务、数据保护与容灾构建以及数据管理部署等方面服务。
比特安全周刊通过专业的信息安全内容建设,为企业级用户打造最具商业价值的信息沟通平台,并为安全厂商提供多层面、多维度的媒体宣传手段。与其他同类网站信息安全内容相比,比特安全周刊运作模式更加独立,对信息安全界的动态新闻更新更快。
新闻中心热点推荐
新闻中心以独特视角精选一周内最具影响力的行业重大事件或圈内精彩故事,为企业级用户打造重点突出,可读性强,商业价值高的信息共享平台;同时为互联网、IT业界及通信厂商提供一条精准快捷,渗透力强,覆盖面广的媒体传播途径。
云计算周刊
比特云计算周刊关注云计算产业热点技术应用与趋势发展,全方位报道云计算领域最新动态。为用户与企业架设起沟通交流平台。包括IaaS、PaaS、SaaS各种不同的服务类型以及相关的安全与管理内容介绍。
CIO俱乐部周刊
比特CIO俱乐部周刊以大量高端CIO沙龙或专题研讨会以及对明星CIO的深入采访为依托,汇聚中国500强CIO的集体智慧。旨为中国杰出的CIO提供一个良好的互融互通 、促进交流的平台,并持续提供丰富的资讯和服务,探讨信息化建设,推动中国信息化发展引领CIO未来职业发展。
IT专家新闻邮件长期以来,以定向、分众、整合的商业模式,为企业IT专业人士以及IT系统采购决策者提供高质量的原创内容,包括IT新闻、评论、专家答疑、技巧和白皮书。此外,IT专家网还为读者提供包括咨询、社区、论坛、线下会议、读者沙龙等多种服务。
X周刊是一份IT人的技术娱乐周刊,给用户实时传递I最新T资讯、IT段子、技术技巧、畅销书籍,同时用户还能参与我们推荐的互动游戏,给广大的IT技术人士忙碌工作之余带来轻松休闲一刻。
微信扫一扫
关注ChinabyteLinux内核驱动中断处理机制之按键中断-定时器消抖Linux内核驱动中断处理机制之按键中断-定时器消抖芯范儿百家号在前面的两篇文章《Linux内核驱动中断处理机制之外部中断》和《Linux内核驱动中断处理机制之软中断和定时器》中,分别描述了在Linux内核驱动中,外部中断的使用、软中断和定时器。因为在这之前所实现的按键驱动并没有实现消抖操作,所以经常性的只按下了一次按键,但是却产生了几个按键信息(抖动导致的)。效果如下:本文将通过Linux内核定时器解决按键的消抖问题。一、理论基础1、机械按键的结构如上图所示,当按键被按下时,按键中连接两个引脚的金属片相互接触导通,使得按键的两个引脚导通,从而表示按键按下。2、机械按键按下和抬起的过程如上图所示A区域,按键按下的过程中,不可避免的会使得按键内部的金属片进行短暂的接触,然后又断开,这使得CPU会将按键误识别为按键已经按下了,但是实际上按键并未按下,从而产生误识别。而我们用户需要的是在B区域时,按键完全的按下了。这就是抖动造成的误识别。那么解决抖动的方案是:“当第一次检测到按键按下时,将其状态记录下来,等待一段时间后(注意:这里的等待并不一定或者说并不是延时,而是CPU可以先去处理别的事件;这段时间通常是毫秒级别的,通常10ms~40ms),再回来再次检测按键状态,如果此时按键还是按下的状态,则说明按键确实按下了;否则说明按键并没有按下”。二、程序的实现1、程序实现思路(1)使用函数接口init_timer和add_timer初始化和注册一个内核定时器。如上图,Key_Dithering_timer为定时器处理函数。(2)在按键中断的下半部处理函数修改并启用定时器思路是:当按键按下之后,会产生按键中断,进入中断下半部之后,启用一个定时器,并且定时从当前时间开始之后的20ms。此时CPU可以去处理其他事件任务,当内核定时器时间到达之后,定时器处理函数Key_Dithering_timer将得到执行。如上图所示Demo即为中断下半部程序。使用mod_timer函数接口来修改定时器的expire。其中buttons_timer为装载驱动是注册的内核定时器,jiffies表示设备从开机到当前时间的定时器中断次数计数;HZ用来定义1s有多少次定时器中断(timer interrupt),在笔者当前使用的Linux内核中HZ的值被定义为200。所以定时20ms的定时器中断计数为HZ/50(关于jiffies和HZ的详细说明,在后续文章中)。(3)在定时器处理函数Key_Dithering_timer中实现键值的判断如上图定时器处理函数中,判断是哪一个按键被按下,如果需要详细处理,那么可以在其中添加各个按键代表的键值。在这里主要是验证驱动程序,并不实现应用程序功能。2、驱动程序的装载3、驱动程序的卸载卸载驱动是,需要使用接口del_timer将申请注册的定时器从内核中删除。四、程序运行效果编译内核得到驱动文件buttons_timer_driver.ko,将其拷贝到板卡根文件系统,通过命令:insmod buttons_timer_driver.ko将驱动装载到Linux内核中。按下按键后,从内核中将按键按下的状态打印出来。如下图:本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。芯范儿百家号最近更新:简介:芯范儿专注于电子行业干货。作者最新文章相关文章}

我要回帖

更多关于 不可屏蔽中断 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信