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…

golang mysql断线_MySQL的连接池、异步、断线重连-Go语言中文社区

MySQL长连接MySQL短连接每次请求操作数据库都需要建立与MySQL服务器建立TCP连接&#xff0c;这是需要时间开销的。TCP连接需要3次网络通信。这样就增加了一定的延时和额外的IO消耗。请求结束后会关闭MySQL连接&#xff0c;还会发生3/4次网络通信。close操作不会增加响应延时&am…

如何解决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;打球的时候经常在天上飞来飞去不觉得累&#…

linux下mysql主从同步是主从i/o线程显示为no_mysql主从同步IO线程NO

主从同步错误一例mysql> show slavestatus\G;***************************1. row ***************************Slave_IO_State:Master_Host: 10.0.10.114Master_User: repMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000024Read_Master_Log_Pos: 264Rela…

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;每天上班的时候&…

Bootstrap全局CSS样式之表单

.form-control——将单独的表单控件赋予一些全局样式&#xff0c;如默认宽度width:100%。 .form-group——包裹表单控件&#xff0c;获得最好的排列&#xff1b; .form-inline——将表单设置为内联表单&#xff0c;仅仅适用于视口&#xff08;viewport&#xff09;至少在 768px…

mysql索引使增删变慢_mysql优化(四)–索引

http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.html一、 四种索引类型&#xff1a;主键索引&#xff0c;唯一索引&#xff0c;全文索引&#xff0c;普通索引二、 为什么建立索引比较快一般的数据表是按照行来存储的&#xff0c;字段多、有长字段的表的记录就会长…

Linux 下的推迟执行

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

ASP.NET系统退出(移除Session 、清除浏览器缓存)

一、在退出时移除Session&#xff0c;首先在登录时要记录登录信息 Session["id"] user.id.ToString();Session["name"] user.name.ToString();Session["pwd"] user.password.ToString();Session["time"] user.LoginTime.ToString(…

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…