读薄《Linux 内核设计与实现》(5) - 定时器、时间管理和内存管理

举报
远航 | FIBOS 发表于 2020/12/02 23:13:33 2020/12/02
【摘要】 这篇文章是《读薄「Linux 内核设计与实现」》系列文章的第 V 篇,本文主要讲了以下问题:Linux 内核中的时间概念和时间表示,硬件时钟和定时器以及时间中断和内存管理的相关知识。 0x00 内核中的时间概念 内核需要管理相对时间和绝对时间硬件为内核提供了一个系统定时器用以计算流逝的时间,它以某种频率自行触发时间中断,该频率可以通过编程预定,称作节拍率时间...

这篇文章是《读薄「Linux 内核设计与实现」》系列文章的第 V 篇,本文主要讲了以下问题:Linux 内核中的时间概念和时间表示,硬件时钟和定时器以及时间中断和内存管理的相关知识。

0x00 内核中的时间概念

  • 内核需要管理相对时间和绝对时间
  • 硬件为内核提供了一个系统定时器用以计算流逝的时间,它以某种频率自行触发时间中断,该频率可以通过编程预定,称作节拍率
  • 时间的作用:
    • 更新系统时间
    • 更新实际时间
    • 定期均衡运行队列(SMP)
    • 时间片
    • 定期统计处理器时间

0x01 Linux 中的时间表示

I 节拍率(Hz)

II jiffies

全局变量 jiffies 用来记录自系统启动以来产生的节拍的总数,定义于

unsigned long timeout = jiffies + HZ / 2; /*0.5秒后超时*/

if(time_before(jiffies, timeout)){
  /*没有超时,很好*/
}else{
  /*超时,发生错误*/
}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

0x02 硬件时钟和定时器

体系结构中提供了两种设备进行计时:

  • 系统定时器:提供了一种周期性触发中断机制
  • 实时时钟:用来持久存放系统时间的设备

0x03 Linux 下的时钟中断

I 时钟中断处理程序做的工作

  • 获得 xtime_lock 锁,对 jiffies_64 和 xtime 进行保护

  • 应答或重新设置系统时钟

  • 周期性使用墙上时间更新实时时钟

  • 调用体系结构无关的时钟例程:do_timer()

II do_timer()

  • jiffies + 1
  • 更新资源消耗的统计值
  • 执行到期的动态定时器
  • 执行 scheduler_tick()
  • 更新墙上时间并存到 xtime 变量中
  • 计算平均负载值

III 从用户空间获取时间

gettimeofday(): 对应系统调用 sys_gettimeofday()

0x04 Linux 内存页

I 内核分配内存特点

  • 内核使用的内存空间有限
  • 内核不支持便捷的内存分配方式
  • 处理内存分配错误难度大
  • 内核分配机制不能太复杂

II 页

  • 内核以物理页为单位分配内存
  • 物理页的大小取决于体系结构
  • page 结构体(定义于
struct page{
  unsigned long flags; //存放页的状态
  atomic_t _count; //存放页的引用计数
  atomic_t _mapcount;
  unsigned long private;
  struct address_space *mapping;
  pgoff_t index;
  struct list_head lru;
  void *virtual; //页的虚拟地址
}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

0x05 Linux 内存区

由于硬件的限制,内核并不能对所有的页一样看待,内核需要对页进行分类,分不同区域

  • Linux 必需处理 2 种由于硬件存在缺陷而引起的内存寻址问题:
    • 一些硬件只能用某些特定的内存地址来执行DMA(Direct Memory Access)
    • 一些体系结构的内存的物理寻址范围比虚拟内存大得多,导致一些内存不能总是映射到内核空间
  • Linux 主要使用了 4 种区:
    • ZONE_DMA: 该区页面用来执行 DMA
    • ZONE_DMA32: 用于 32 位设备执行 DMA
    • ZONE_NORMAL:该区页面都能正常映射
    • ZONE_HIGHEM:该区包含“高端内存”,这里的页不能永久映射到内核空间

0x06 内存管理提供的服务

I 获得页

  • alloc_pages()
  • page_address(struct page* page)
  • __get_free_pages()
  • alloc_page()
  • __get_free_page()

II 获得填充为 0 的页

  • get_zeroed_page()

III 释放页

  • __free_pages()
  • free_pages()
  • free_page()

IV kmalloc()

用于获得以字节为单位的一块连续内存空间:

void *kmalloc (size_t size, gfp_t flags)
  
 
  • 1

V kfree()

该函数用于释放 kmalloc() 分配出的内存块:

void kfree(const void *ptr)
  
 
  • 1

VI vmalloc()

类似 kmalloc(), 但分配的内存空间不连续,释放使用 vfree()

VII slab 层

即 slab 分配器,它扮演了通用数据结构缓存层的角色,是一种缓存机制


本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!

文章来源: blog.csdn.net,作者:冰水比水冰,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/luoyhang003/article/details/52901447

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。