整理一下《深入理解Linux内核(2.6)》里的相关数据结构

一、工作队列

写到一半,发现一个好贴,哈哈

https://www.cnblogs.com/zzb-Dream-90Time/p/6476018.html

与工作队列相关的主要数据结构是名为 workqueue_struct的描述符,它包含一个有NR_CPUS(CPU最大数量)个元素的数组。

每个元素都是cpu_workqueue_struct类型的描述符:

cpu_workqueue_struct结构
字段名 描述
lock 保护该数据结构的自旋锁
remove_sequence flush_workqueue()使用的序列号
insert_sequence flush_workqueue()使用的序列号
worklist 挂起链表(双向链表)的头结点
more_work 等待队列,其中的工作者线程因等待更多的工作而处于睡眠状态
work_done 等待队列,其中的进程由于等待工作队列被刷新而处于睡眠状态
wq 指向 workqueue_struct结构的指针,其中包含该描述符
thread 指向结构中工作者线程的进程描述符指针
run_depth run_workqueue()当前的执行深度(当工作队列链表中的函数阻塞时,这个字段的值会变得比1大)

worklist字段是双向链表的头,该链表集中了工作队列中的所有挂起函数,挂起函数用work_struct数据结构表示:

work_struct结构
字段名 描述
pending 如果函数已经在工作队列链表中,该字段值设为1,否则设为0
entry 指向挂起函数链表前一个或后一个元素的指针
func 挂起函数的地址
data 传递给挂起函数的参数,是一个指针
wq_data 通常是指向cpu_workqueue_struct描述符的父结点的指针
timer 用于延迟挂起函数执行的软定时器

create_workqueue("foo")函数接收一个字符串作为参数,返回新创建工作队列的workqueue_struct描述符的地址。该函数还创建n个工作者线程(n是当前系统中有效运行的CPU的个数),并根据传递给函数的字符串为工作者线程命名,如:foo/0,foo/1等等。 create_singlethread_workqueue()函数与之相似,但不管系统中有多少个cpu, create_singlethread_workqueue()函数都只创建一个工作者线程。内核调用 destroy_workqueue()函数撤消工作队列,它接收指向 workqueue_struct数组的指针作为参数。

二、内核信号量

struct semaphore

{

    count    //大于0:资源空闲;等于0:资源忙,没有等待进程;小于0:资源忙,至少有一个等待进程。

    wait     //存放等待队列(等待进程队列)链表的地址。

    sleepers //存放是否有一些进程在信号量上睡眠的标志:如果没有进程在信号量等待队列上睡眠,
             //则改值为0,否则置为1。

}

init_MUTEX()                  函数把count字段设置成1

init_MUTEX_LOCKED() 函数把count字段设置成0

获取/释放信号量

释放内核信号量:调用up()函数,增加count字段的值,如果count小于等于0,调用__up()函数换新一个睡眠进程。

获取内核信号量:调用down()函数,减少count字段的值,如果count大于等于0,当前进程获得信号量,否则,当前进程挂起。把一些寄存器内容保存在栈中,然后调用__down()函数。

down()函数的主要任务是挂起当前进程,直到信号量被释放。几种典型的情况:

MUTEX 信号量打开(count等于1,sleepers等于0)

MUTEX 信号量关闭,没有睡眠进程(count等于0,sleepers等于0)

MUTEX 信号量关闭,有其他睡眠进程(count等于-1,sleepers等于1)

 

down_trylock()函数在资源忙时会立即返回。

down_interruptible()函数广泛用于设备驱动中,睡眠进程在获得需要的资源之前被另一个信号唤醒,则该函数会增加count字段的值并返回-EINTR,而正常结束时返回0;因此,在返回值为-EINTR时,驱动程序可以放弃I/O操作。

三、读/写信号量

struct rw_semaphore

{
    count        // 两个16位计数器。高16位以二进制补码形式存放非等待写者进程的总数和等待的
                 // 写内核控制路径数。低16位存放非等待读者和写者进程的总数。
    wait_list    // 指向等待进程的链表
    wait_lock    // 一个用于保护等待队列链表喝rw_semaphore结构的自旋锁
}

inti_rwsem()函数初始化rw_semaphore结构,把count字段置为0,wait_lock自旋锁置为未锁,把wait_list置为空链表。

down_read() 获取读信号量;

down_write()获取写信号量;

up_read()释放读信号量;

up_write()释放写信号量;

down_read_trylock()非阻塞式获取读信号量;

down_write_trylock()非阻塞式获取写信号量;

downgrade_write()自动把写锁转换成读锁。

四、禁止本地中断

疑问:

“如果eflags寄存器的IF标志被清0,宏irqs_disabled()返回1;如果IF标志被设置,改宏也返回1。”

为什么都返回1呢?

 

定时器对象

timer_opts数据结构

字段名 说明
name 标识定时器源的一个字符串
mark_offset 记录上一个节拍的准确时间,由时钟中断处理程序调用
get_offset 返回自上一个节拍开始所经过的时间
monotonic_clock 返回自内核初始化开始所经过的纳秒数
delay 等待指定数目的“循环”

 

你可能感兴趣的:(Linux内核)