sleep系统调用

我是一个线程,生活在Linux帝国。一直以来辛勤工作,日子过得平平淡淡,可今天早上发生了一件事让我回想起来都后怕。

早上,我还是如往常一样执行着人类编写的代码指令,不多时走到了一个冷门的分支,一个sleep()函数调用摆在了我的面前。

终于可以去休息了!听老一辈的线程们说,执行了这个函数就可以休息休息了。我瞄了一眼参数,足足有5秒钟的休息时间,我简直乐坏了,没有犹豫,赶紧执行了这个调用。

进入sleep()函数后,又来到了nano_sleep()函数,接着看到了一个syscall系统调用指令,我继续执行,来到了内核空间。

进入内核空间后,我接连穿过了

  • –> nano_sleep()
  • –> hrtimer_nanosleep()
  • –> do_nanosleep()
  • –> freezable_schedule()

把我累得够呛,说好让我休息,没想到休息之前还有这么多事要做。

终于,我来到了一个叫schedule()的函数面前。

线程调度

进入schedule()后,迎面走来一位发须皆已花白的长者。

“小伙子,这是要来休息了,我是负责线程调度的使者,让我看下你占用的CPU号码”,一边说一边查找着什么。

“哦,是2号CPU,来,跟我到这边来”,在他的指引下,我又来到了一个函数面前。

“你先去pick_next_task()找到一个接盘侠,哦不,找到下一个需要执行的线程,这是2号CPU的就绪队列,你可拿好了,等你办完回来我再带你去办理交接手续”,说完给我手里塞了一个参数rq,随即便离开了,留下我不知所措。

我只好按他说的照办,迈进了pick_next_task()函数的大门,一位美女接待映入眼帘。

“先生您好,您来此想必是要寻找接班线程吧”,见我到来,美女起身招呼。

“你猜的不错,要麻烦你帮我处理一下,多谢了”

“您别客气,把就绪队列给我看看吧”

我先是愣了一下,反应过来后将手里的rq参数给了她。

struct rq {raw_spinlock_t lock;...unsigned int nr_running;...struct cfs_rq cfs;struct rt_rq rt;struct dl_rq dl;...struct task_struct *curr, *idle, *stop;...struct mm_struct *prev_mm;...struct list_head cfs_tasks;
};

美女拿着rq一阵端详,说到:“您运气不错哦,rq->nr_running和rq->cfs.h_nr_running相等,看来没有实时线程,全是普通线程,您直接去那边的公平调度CFS窗口fair_sched_class那里去办理吧。”

我顺着美女指向的方向看去,那边一共有5个窗口:

  • stop_sched_class
  • dl_sched_class
  • rt_sched_class
  • fair_sched_class
  • idle_sched_class

“唉,美女,那要是不相等该去哪个窗口办理呢?你告诉我一下,下次来我就知道了”

“不相等的话那就说明就绪队列里除了普通线程还有其他优先级更高的线程,就得按照优先级从stop_sched_class窗口挨个向后询问,直到找到一个线程。不过我在这干了这么久,就实时线程所在的rt_sched_class窗口和普通线程所在的fair_sched_class最常用”,美女耐心的给我解释到。

听了她的解释,我想到了一个问题:“那要是都找不到线程需要执行怎么办,比如他们都在等待IO事件之类的?那我怎么交差啊”

“放心吧,最后那个idle_sched_class窗口绝对不会让你空手而归的”,美女笑着说。

原来如此,我点了点头。

来到fair_sched_class窗口的旁边,递交了我的rq参数,只见工作人员取出了其中的cfs_rq

struct cfs_rq {struct load_weight load;unsigned int nr_running, h_nr_running;...struct rb_root tasks_timeline;struct rb_node *rb_leftmost;...struct sched_entity *curr, *next, *last, *skip;...struct rq *rq;
};

我这才注意到,原来这个cfs_rq中指向了一棵红黑树,再仔细一看,这树上的每个节点都是一个线程task_struct

工作人员很快就取出了一个task_struct交给我,一个年纪轻轻的线程小T,我带着小T告别了美女接待,回到了schedule()

context_switch

看到我回来,长者起身言道:“小伙子,回来啦,走,带你们去context_switch()

进入这个context_switch()之后,长者又带着我又做了一些准备工作,比如把当前的进程地址空间换成了小T的,最终我们来到了一个叫switch_to的地方。

“小伙子,再往前走几步就是换班的地方了,就可以休息了,我就不送你了,感谢你这段时间的辛苦工作”,长者一边说一边拍拍我的肩膀。

告别了长者,我和小T踏上了这神秘的switch_to,跟随着一步一步的指令,我把自己线程上下文的寄存器都保存到了我的内核栈上面,然后将栈指针指向了小T的内核栈,最后把小T保存在他内核栈的指令地址加载进指令寄存器,终于完成了交接工作。

“小T,接下来就该你工作了,我要去休息了”,我和小T握手告别,来到旁边准备眯一会儿。

神秘的唤醒

“醒醒,醒醒”,睡梦中听到有人唤我。

我揉揉睡眼,看了下时间,这才睡了2s,时间还没到,难道现在是在做梦?

“总算把你叫醒了,快起来,换班时间到了,该你上了”,我抬起头才发现另外一个线程小H站在面前。

“我休息时间还没够啊,怎么选中了我啊,让我再睡会儿”,说罢我就要躺下。

小H一把拉住了我,“别磨叽了,就是你,快走”。

在小H的带领下,我们又来到了那个叫switch_to地方,只不过这一次我的角色变了。

小H一顿和我之前一样的操作,把执行流程交给了我。

我再次获得了执行代码的能力,随后回到了context_switch(),又回到了schedule(),看到了熟悉的长者。

我和长者再次告了别,继续返回,最后通过sysret虫洞,回到了用户态空间。

不过我马上意识到事情不对劲,这里并不是我最开始调用sleep()的地方,而是一片完全陌生的区域,难道哪里出了问题,我这是到了哪里?

这一定是在做梦,我还在sleep()呢,时间还没够,我只好这样安慰自己。

我小心翼翼的执行了这里的代码,只是简单输出了一行日志,然后来到了一个叫__restore_rt()的函数,又一条syscall指令摆在了我的面前,我没有犹豫再一次一头扎进了内核空间。

经过一番折腾,又来到了sysret虫洞面前,不知道这一次又将带我去到哪里。我闭上了眼睛跳了进去···

等我睁开眼睛,竟然奇迹般的回到了最开始调用sleep()的地方,这场梦终于醒了,庆幸我回到了这里。

我看了一眼sleep()的返回值,竟然是3。我又看了一眼日志文件,竟看到了梦里输出的那一行日志。

难道那不是梦?这究竟是怎么一回事?

未完待续······

彩蛋

“奇怪,这个TCP数据包的ACK和SEQ怎么和刚才那个一样,估计是重传了吧”,帝国网络部的小Q丢掉了这个重复的数据包。

不过,同样的事情接二连三的出现,经历了上次那件事的小Q不敢大意,赶紧向安全部长汇报了情况。

预知后事如何,请关系后续精彩······


本文关联前作

内核地址空间大冒险1:系统调用

内核地址空间大冒险2:中断与异常

内核地址空间大冒险3:权限管理


往期热门回顾

震撼!全网第一张源码分析全景图揭秘Nginx

一个整数+1引发的灾难

一网打尽!每个程序猿都该了解的黑客技术大汇总

看过无数Java GC文章,这5个问题你也未必知道!

一个Java对象的回忆录:垃圾回收

谁动了你的HTTPS流量?

路由器里的广告秘密

DDoS攻击:无限战争

一条SQL注入引出的惊天大案

一个HTTP数据包的奇幻之旅

一个DNS数据包的惊险之旅

我是一个流氓软件线程

调用sleep后,我做了一个噩梦相关推荐

  1. 做了一个噩梦,梦见你离开,我从哭泣中醒来

    做了一个噩梦,梦见你离开,我从哭泣中醒来. 还好,只是梦. 可是突然想起, 现实中你也早已离去.

  2. 设置支付后跳转到一个指定的网页,自动成交出售虚拟产品

    我们讲了,通过八图片平台,可以生成一个带有二维码的图片链接,扫码支付后就会跳转到一个指定的网页.有人可能会问,这个支付后跳转网页的功能有什么用呢?用处可大了,比如,我可以在网页上放置软件,视频,或者一 ...

  3. 接手一个网站后应做什么

    摘自:http://lusongsong.com/reed/441.html 北京有个卖家具公司,有位经理对网络营销很感兴趣,于是开始招聘网络推广专员.一哥们,搞技术的,因爱好推广,面试了这家实体公司 ...

  4. 混合模式程序matlab,VS2013 C# 调用 cognex 的QuickBuild做程序时发生一个错误

    今天在用 VS2013 C# 调用 cognex 的QuickBuild做程序时发生一个错误,如下所示 混合模式程序集是针对"v2.0.50727"版的运行时生成的,在没有配置其他 ...

  5. 多个联盟广告调用代码,这样做可以做到打开页面,随机显示一个联盟广告代码

    多个联盟广告调用代码,这样做可以做到打开页面,随机显示一个联盟广告代码: 现在很多站长所经营的网站都挂有很多联盟广告,但是同一个广告位不好同时挂好几个联盟广告,下面我来给大家写一点简单JS广告随机显示 ...

  6. python opencv 实现从一个文件夹中读取图片做切割处理后放入另一个文件夹

    python opencv 实现从一个文件夹中读取图片切割处理后放入另一个文件夹. 实现的功能是把一个文件夹里的图片作处理,即把原图片中心为起点切割成1536*1536的图片,原图片必须大于这个的大小 ...

  7. 基于阿里云用C/C++做了一个http协议与TCP协议的web聊天室的服务器——《干饭聊天室》

    基于阿里云用C/C++做了一个http协议与TCP协议的web聊天室的服务器--<干饭聊天室> 在这里首先感谢前端小伙伴飞鸟 前端技术请看一款基于React.C++,使用TCP/HTTP协 ...

  8. C#做的一个加密/解密的类

    C#做的一个加密/解密的类 大家要有兴趣,可以一起来讨论一下 WebService数据交互安全问题,以下的这个代码,可以用于Dotnet环境下的任何托管方式的应用程序,在实际应用中有两个实例.其中,有 ...

  9. request payload怎么发_做了一个个人博客,但不知道怎么介绍

    三月即将过去了,这意味着很多,比如,上市公司要开始准备第一季度的财报了:比如,2019年不知不觉已经过去1/4:比如,金三银四的跳槽季,你拿到满意的offer了吗?... 整个三月份,我大概做了一些事 ...

最新文章

  1. 重磅!2019年诺贝尔生理学或医学奖揭晓,“细胞感知氧气通路”摘得桂冠
  2. Codeforces Round #501 (Div. 3)【未完结】
  3. 为Mac安装homebrew
  4. mysql 5.7 root password 过期
  5. 红橙Darren视频笔记 自定义RatingBar touch事件学习 dp转px listener监听
  6. Android开发笔记(一百六十八)为应用绑定通知渠道并展示消息角标
  7. 做了一款股票复盘工具
  8. Java编程——subString,截取当前字符串的部分内容
  9. 占内存少的java开发工具_Java所占内存中神奇的64MB
  10. 2022年西藏最新建筑八大员(市政)模拟考试题库及答案
  11. python研发岗简历_【干货】不谈具体面经,说说研发岗简历编写、面试技巧
  12. 2021年数维杯数学建模A题外卖骑手的送餐危机求解全过程文档及程序
  13. 微信公众号怎么发PDF文件
  14. Dockerflie概述
  15. 使用H5中的video标签时,页面中间显示“暂停”图标;点击播放,图标消失;点击暂停,图标出现(play、pause、ended)
  16. 越野赛车 v1.0 怎么用
  17. FPGA开发基础——基于multisim以及Quartus实现的交通灯电路
  18. 珠海先达MES系统在电镀车间的应用
  19. 《随遇而安》读书摘记
  20. 联想服务器万全T260G3系统,联想万全T260G3服务器企业高性价比之选

热门文章

  1. 物联网网关神器 Kong ( 四 )- 利用 Konga 来配置生产环境安全连接 Kong
  2. 电脑桌面壁纸更换后不一会就变成黑屏
  3. prf###.tmp临时文件导致磁盘资源不足
  4. python 列表作业
  5. 台式计算机把光驱改成硬盘,如何在台式机光驱中安装硬盘?
  6. 字符串统计不同类型字符的个数
  7. python架构的抉择
  8. sd卡突然所有文件都无法删除,在手机中会提示‘无法删除’,并且无法格式化,并且无法写入文件,
  9. What’s difference between 1’s Complement and 2’s Complement?
  10. iOS开发 ☞ Commen Sense