(1)内核基础层提供的服务

操作系统通常提供的服务是内存管理、进程管理、设备管理、文件系统

一. 内核中使用内存

内核提供了两个层次的内存分配接口:从伙伴系统分配、从slab系统分配。
伙伴系统是最底层的内存管理机制,提供页式的内存管理。
slab是伙伴系统之上的内存管理,提供基于对象的内存管理。

从伙伴系统分配内存调用的是alloc_pages,此时得到的是页面地址,要获得能使用的内存地址,需要调用page_address来获得内存地址。(直接获取内存地址可以使用__get_free_pages)。

alloc_pages申请的内存是以页为单位的,最少要一个页。如果只是申请一小块内存,一个页就浪费了,而且内核中很多应用也希望一种对象化的内存管理,希望内存管理能自动地构造和析构对象,这就是slab内存管理。

要从slab申请内存,需要创建一个slab对象,使用kmem_cache_create创建slab对象。kmem_cache_create可以提供对象的名字和大小、构造函数和析构函数等,然后通过kmem_cache_alloc和kmem_cache_free来申请和释放内存。

内核中常用的kmalloc其实也是slab提供的对象管理,只不多内核已经构建了一些固定大小的对象,用户通过kmalloc申请时,就使用了这些对象。

内核中还有一个内存分配调用:vmalloc。vmalloc的作用是把物理地址不连续的内存页面拼凑为逻辑地址连续的内存区间。

二. 内核中的任务调度

内核中经常需要进行进程的调度,使用wait_event实现。内核中还实现了一系列函数:
wait_event_timerout:和wait_event的区别是有时间限制,如果条件满足,进程恢复运行,或者时间到达,进程同样恢复进行。
wait_event_interruptible:和wait_event类似,不同之处是进程处于可中断的睡眠。而wait_event设置进程处于不可中断的睡眠。
wait_event_interruptible_timeout:和wait_event_interruptible相比,多个时间限制。在规定的时间到达后,进程恢复运行。
wait_event_interruptible_exclusive:和wait_event_interruptible区别是排他性的等待。

三. 软中断和tasklet

Linux内核把对应中断的软件执行代码分拆成两部分。
一部分代码和硬件关系紧密,这部分代码必须关闭中断来执行,以免被后面触发的中断打断,影响代码的正确执行,这部分代码放在中断上下文中执行。
另一部分代码和硬件关系不紧密,可以打开中断执行,这部分代码放在软中断上下文执行。

Linux内核定义了几个默认的软中断,网络设备有自己的发送和接收软中断,块设备也有自己的软中断。为了方便使用,内核还定义了一个tasklet软中断。tasklet是一种特殊的软中断同一时刻一个tasklet只能有一个CPU执行,不同的tasklet可以在不同的CPU上执行。这和软中断不同,软中断同一时刻可以在不同的CPU并行执行,因此软中断必须考虑重入的问题。

四. 工作队列

工作队列和tasklet相似,都是一种延缓执行的机制。
不同之处是工作队列有自己的进程上下文,所以工作队列可以睡眠,也可以被调度,而tasklet不可睡眠。

使用工作队列很简单,schedule_work把用户定义的work_struct加入系统的队列中,并唤醒系统线程去执行。那么是哪个系统线程执行用户的work_struct呢?实际上,内核初始化的时候,就要创建一个工作队列keventd_wq,同事为这个工作队列创建内核线程(默认是为每个CPU创建一个内核线程)。

内核同时还提供了create_workqueue和create_singlethread_workqueue函数,这样用户可以创建自己的工作队列和执行线程,而不用内核提供的工作队列。

create_workqueue和create_singlethread_workqueue类似,不同的是,create_singlethread_workqueue只创建一个内核线程,而不是为每个CPU创建一个内核线程。

五. 自旋锁

自旋锁用来在多处理器的环境下保护数据。
自旋锁可以用在中断等禁止睡眠的场景。

六. 内核信号量

内核信号量和自旋锁类似,作用也是保护数据。不同的是,进程获取内核信号量的时候,如果不能获取,则进程进入睡眠状态。

内核信号量和自旋锁的不同之处:

  • 内核信号量不能用在中断处理函数和tasklet等不可睡眠的场景。
  • 深层次的原因是Linux内核以进程为单位调度,如果在中断上下文睡眠,中断将不能被正确处理
  • 可睡眠的场景即可使用内核信号量,也可使用自旋锁。自旋锁通常用在轻量级的锁场景。即锁的时间很多,马上就释放锁的场景。

七. 原子变量

原子变量提供了一种原子的、不可中断的操作。
内核提供了一系列的原子变量操作函数:
atomic_add:加一个整数到原子变量。
atomic_sub:从原子变量减一个整数。
atomic_set:设置原子变量的数值。
atomic_read:读原子变量的数组。

发布了19 篇原创文章 · 获赞 20 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章