Linux 内核宏 time_after解析

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

同学们留言回复答案看看


可能很多老鸟对这样的Linux 内核宏已经见惯不怪了,但是作为新手的Linux内核开发者,我觉得非常有必要了解其中的原理和作用。

jiffies 这个想必大家已经非常熟悉,jiffies表示的是当前的系统时钟节拍总数,它统计的是从开机到现在的系统时间节拍。

既然说到时钟节拍,那就不能不说HZ,这个是系统的节拍,每个体系结构系统的节拍都不一样,内核中通常的节拍数都不同,是 100,200,1000等,根据不同的体系结构来设定,节拍数可以理解为心跳,jiffies 可以理解为从出生到现在你系统产生了多少次心跳。

/*

* These inlines deal with timer wrapping correctly. You are

* strongly encouraged to use them

* 1. Because people otherwise forget

* 2. Because if the timer wrap changes in future you won't have to

*   alter your driver code.

*

*  time_after(a,b) returns true if the time a is after time b.

*

* Do this with "<0" and ">=0" to only test the sign of the result. A

* good compiler would generate better code (and a really good compiler

* wouldn't care). Gcc is currently neither.

*/

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(b) - (long)(a) < 0))

看注释,就是如果 a 的时间在 b 的时间之后,就返回true,也可以理解为产生b的时间段超时后,就返回true。

然后我们看看在内核代码里面是如何使用这个宏的?

timeout =2;

timeout += jiffies;

do {

if (time_after(jiffies, timeout)) {

/* drive timed-out */

return 1;

}

/* give drive a breather */

msleep(50);

} while ((hwif->INB(hd_status)) & BUSY_STAT);

我随便拿了一个代码来举例,这个是在驱动里面的一个代码,如果这个驱动代码产生了超时,就返回true,函数就返回,可以理解为注册驱动产生了超时时间后,while里面的判断还是真。

我们看这个宏实现的原理

如果

b = 100; (超时时间)

a = 55;     (当前时间)

正常的时候

(long)b - (long)a > 0 表示没有产生超时

如果

a = 101时

(long)b - (long)a = 100 - 101 = -1 < 0 表示时间超时

但是我们正常不会这样使用,我们会利用HZ参数来一起使用

比如,我要设置2秒后超时,那么timeout可以这样设置

timeout = 2*HZ;

timeout += jiffies;

if(time_after(jiffies,timeout)){

//do somethings

}

但是前面有一个typecheck(unsigned long) 后面比较的时候又强制转变为long,这个有什么玄机呢?

这个主要是解决jiffies回绕的问题

我们知道unsigned long 的最大值是 2^64 -1 = 18446744073709551615 (64位系统

           640?wx_fmt=png            

假设time_after的宏定义如下

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((unsigned long)(b) - (unsigned long)(a) < 0))

//jiffies = 18446744073709550615

timeout = 2*HZ;

timeout += jiffies;

//do something

if(time_after(jiffies,timeout)){ 

//这时候,jiffies 已经回绕为 0,timeout还是一个很大的值,这时候就会出现问题了,jiffies需要重新计数很久很久才可能再回到和timeout比较的一个量级。

   //do something

}

但是如果上面的宏,被强制转换成long 有符号数呢?

signed long 的范围是 [-9223372036854775808, 9223372036854775807]

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(b) - (long)(a) < 0))

       jiffies = 18446744073709550615;

timeout =2*HZ;

timeout += jiffies;

      //do something

      if(time_after(jiffies,timeout)){ 

//这时候,jiffies 已经回绕为 0,timeout 还是一个很大       的值,转成有符号的long是 -801,这时候timeout - jiffies = -801 < 0是成立的。

          //do something

      }

我们看注释里面也写着,这个宏是非常强壮的,但是这个也有一个弊端的时候,就是timeout的时间超出了unsigned long /2 的范围,就会出现问题 ,但是unsigned long/2 表示多长的时间呢?我们计算一下

18446744073709551615 /HZ(200)/60/60/24 = 533759955836/2 = 266879977918(天)

没有谁把超时时间设置到这么久吧,所以说这个宏是足够你使用的了。

可能很多人不明白为什么timeout设置太长会出现问题,我们可以列举一下

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(b) - (long)(a) < 0))

jiffies = 18446744073709551615/2;

printf("%lld\n",(long)(jiffies));

timeout = 18446744073709551615/2;

timeout += jiffies;

       jiffies += 202;

printf("jiffies=%ld,timeout=%ld, time_after(a,a+b)=%d\n",(long)jiffies, (long)timeout, time_after(jiffies,timeout));

      //输出结果如下

      9223372036854775807

      jiffies=-9223372036854775607,timeout=-2, time_after(a,a+b)=0

请读者自行验证 jiffies =0 timeout = 18446744073709551615/2 的情况

看到最后返回的是  0 ,不是 1 

原因很简单,因为timeout回绕变成了在 0附近的值(可以回去看那个图片加深理解),然后jiffies是一个负数很大的值,相减就出现问题了。

***************************

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript mysql php_HTML、CSS、JavaScript、PHP、 MySQL 的学习顺序是什么?

下面是前端学习路线以及学习资源推荐&#xff1a;目录1. HTMLDOCTYPEHTML, XHTML, XML 差异性HTML5 新特性 及 语义化标签meta, img, script 等标签及其标签属性有兴趣可以了解 W3C 和 WHATWG HTML5 差异文章视频2. CSSCSS 基础CSS 布局CSS 动画CSS 预处理器(sass, less, stylu…

一个看似是系统问题的应用问题的解决过程

作者&#xff1a;王小二C 2019/09/04前言今天遇到一个问题&#xff0c;应用工程师分析是系统层的问题&#xff0c;然后就把这个锅给了我。最后我又把锅甩回给了应用工程师。异常log如下:I [2019-08-18 10:11:08 GMT8] binder: 1433:1561 transaction failed 29201/-28, size 8…

如何解决Binder泄漏问题

作者&#xff1a;王小二C 2019/09/06前言[011]一个看似是系统问题的应用问题的解决过程[1]中我们解决了一个注册过多的BroadcastReceiver导致的某一次发送广播失败的问题。我这边遇到了一个类似的问题&#xff0c;但是我用了一个可能网络上从来没有提出过的方法&#xff0c;解…

Docker-compose实战——Django+PostgreSQL

今天我们来用docker-compose 快速安装一个DjangoPostgreSQL的开发环境。 Compose简介 Compose 定位是“defining and running complex applications with Docker”&#xff0c;前身是 Fig&#xff0c;兼容 Fig 的模板文件。 Dockerfile 可以让用户管理一个单独的应用容器&#…

终于赢球了

感谢老将易建联我们要承认一个事实&#xff0c;阿联是这届男篮里面的老将&#xff0c;是唯一一个80后球员&#xff0c;很多人不了解老将意味着什么&#xff0c;很多打篮球的人都有一个感觉&#xff0c;在高中时代的时候&#xff0c;打球的时候经常在天上飞来飞去不觉得累&#…

Zookeeper原理和实战开发经典视频教程 百度云网盘下载

Zookeeper原理和实战开发 经典视频教程 百度云网盘下载 资源下载地址&#xff1a;http://pan.baidu.com/s/1o7ZjPeM 密码&#xff1a;r5yf 转载于:https://www.cnblogs.com/heitaok/p/6979781.html

C语言大神进来看看这个题目

之前一个读者给我发的一个题目&#xff0c;我大概看了下&#xff0c;题目的难度还是比较大的&#xff0c;而且考察的内容也比较多&#xff0c;可能在实际项目上使用比较少&#xff0c;估计十几年的老码农都没有用过&#xff0c;但是在看大神的代码的时候&#xff0c;就特别考验…

qq浏览器主页_安卓浏览器哪家强?这些小众好用的手机浏览器你知道吗

前言无论手机还是电脑&#xff0c;浏览器都可以说是最重要的软件之一了。最流行的 Chrome 和 Firefox&#xff0c;国内常见的还有 UC、QQ、360 浏览器等。手机上可供选择的优秀浏览器还有很多&#xff0c;这次就推荐些其他的小众但是也很好用的安卓手机浏览器。安卓手机浏览器推…

ms access to mysql_Access转MySQL工具

Bullzip MS Access To MySQL是一个Access转MySQL工具&#xff0c;可以帮助用户把MS Access数据库中的内容转到MySQL数据库中&#xff0c;支持全部转换以及有选择的转换&#xff0c;支持命令行&#xff0c;非常适合有Access转MySQL需求的数据库维护人员使用。Bullzip MS Access …

_一文让你透彻理解Linux的SOCKET编程(含实例解析)

1. 网络中进程之间如何通信进 程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行&#xff0c;为保证两个相互通信的进程之间既互不干扰又协调一致工作&#xff0c;操作系统为进程通信提供了相应设施&#xff0c;如UNIX BSD有&#xff1a;管道&#xff08;…

老师好

今天是教师节&#xff0c;今年楠哥也上幼儿园了&#xff0c;以后估计会经常跟老师有接触&#xff0c;我楼上的一个邻居&#xff0c;叫老莫&#xff0c;跟我的关系很好&#xff0c;有钱&#xff0c;又有儿有女&#xff0c;大女儿现在已经上小学了&#xff0c;每天上班的时候&…

Linux 下的推迟执行

准备中秋节说个活动&#xff0c;评论文章点赞排名&#xff0c;用心评论哦&#xff0c;前5名获得每人 19 心意红包。感谢大家的支持我最近在用freertos&#xff0c;想让一个任务在某个时间后再执行&#xff0c;找了一圈&#xff0c;竟然没有这样才处理机制&#xff0c;因为也是新…

js 获得明天0点时间戳_js实现一个简单钟表动画(javascript+html5 canvas)

自己学生时代的代码&#xff0c;发现还保存着&#xff0c;今天拿出来分享下。用js和html5 canvas对象实现一个简单钟表程序主要用到的就是h5的canvas对象canvas对象本人也不是很熟&#xff0c;大致看了几个常用的方法&#xff0c;难免有不足之处&#xff0c;仅是练习所用。实现…

mysql 根据当前时间戳_mysql timestamp类型 根据当前时间戳更新

注意到这个是因为一次事故。一个简单的操作记录表&#xff0c;只记录了一个操作人&#xff0c;操作时间&#xff0c;操作结果。当时为了演示效果&#xff0c;在生产环境中去修改&#xff0c;创建数据。一顿操作猛如虎之后发现&#xff0c;所有改过的数据的创建时间都变成了当前…

设置拖拽事件,获取拖拽内容

设置dragEnter 设置DragDrop using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using…

笔记本电脑锁_2020年双11有哪些值得选购的笔记本电脑?(全能本/便携高性能笔记本电脑/设计本)...

&#xff08;本文于2020年10月22日更新&#xff09;本文章会不定期更新&#xff0c;保证文章的时效性和准确性&#xff0c;可点赞或收藏本文章&#xff0c;这样在需要的时候可以找到啦。文章推荐产品较多&#xff0c;按价位排序&#xff0c;篇幅较长&#xff0c;可按键盘CtrlF快…

300来行代码实现最小Linux文件系统

Linux作为一个类UNIX系统&#xff0c;其文件系统保留了原始UNIX文件系统的表象形式&#xff0c;它看起来是这个样子&#xff1a;rootname-VirtualBox:/# lsbin boot cdrom dev etc home lib lib64 lostfound media mnt opt proc root run sbin snap srv sys …

淘宝怎么多个订单一起付款_淘宝未付款订单如何催付?

淘宝未付款订单如何催付&#xff1f;很多人只认为运营就是技巧&#xff0c;其实客服也是需要技巧的&#xff0c;客服也是关键的数据支撑。一个好的客服团队&#xff0c;能够很好地提高转化率、客单价、复购率&#xff0c;有效的降低退款率、纠纷等售后问题。今天和大家分享一下…

爱大姚,恨男篮

先祝姚明生日快乐2019年9月12日。是中国篮协主席、CBA董事长姚明39岁的生日&#xff0c;时间已经过去几天了&#xff0c;当时铺天盖地的都是其他的热点新闻&#xff0c;很多人&#xff0c;包括我也忘记了这个大个子已经39岁了&#xff0c;看着中国男篮的惨败&#xff0c;很想冲…

Linux 内核系统架构

描述Linux内核的文章已经有上亿字了但是对于初学者&#xff0c;还是应该多学习多看&#xff0c;毕竟上亿字不能一下子就明白的。即使看了所有的Linux 内核文章&#xff0c;估计也还不是很明白&#xff0c;这时候&#xff0c;还是需要fucking the code.28年前(1991年8月26日)Lin…