文章目录
- 一、Linux 内核设计与实现
- 1、进程管理
- (1)调度
- 2、内核数据结构
- (1)kfifo
- 3、中断
一、Linux 内核设计与实现
本章主要用来摘录《Linux 内核设计与实现》一书中学习知识点,其基于 Linux 2.6.34 。
1、进程管理
// include/linux/sched.h
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
int lock_depth; /* BKL lock depth */
// ...
}
进程描述符 task_struct 包含了一个具体进程的所有信息。其相对较大,在 32 位机器上,它大约有 1.7KB。
Linux 通过 slab 分配器分配 task_struct 结构。在 2.6 以前的内核中,各个进程的 task_struct 存放在它们内核栈的尾端。这样做是为了让那些像 x86 那样寄存器较少的硬件体系结构只要通过栈指针就能计算出它的位置,而避免使用额外的寄存器专门记录。由于现在用 slab 分配器动态生成 task_struct ,所以只需要在栈底创建一个新的结构 struct thread_info 。
// arch/x86/include/asm/thread_info.h
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
__u32 flags; /* low level flags */
__u32 status; /* thread synchronous flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable,
<0 => BUG */
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
#ifdef CONFIG_X86_32
unsigned long previous_esp; /* ESP of the previous stack in
case of nested (IRQ) stacks
*/
__u8 supervisor_stack[0];
#endif
int uaccess_err;
};
(1)调度
CFS 调度
2、内核数据结构
(1)kfifo
// kernel/kfifo.c
/**
* 使用 buffer 内存创建并初始化kfifo队列
*
* @param fifo kfifo队列
* @param buffer 指向内存地址
* @param size 内存大小,必须是 2 的幂
*/
void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size);
/**
* 动态创建并初始化kfifo队列
*
* @param fifo kfifo队列
* @param size 创建kfifo队列大小
* @param gfp_mask 标识
* @return
*/
int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask);
/**
* 把数据推入到队列。该函数把 from 指针所指的 len 字节数据拷贝到 fifo 所指的队列中,如果成功,
* 则返回推入数据的字节大小。如果队列中的空闲字节小于 len,则该函数值最多可拷贝队列可用空间那么多
* 的数据,这样的话,返回值可能小于 len。
*/
unsigned int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len);
/**
* 该函数从 fifo 所指向的队列中拷贝出长度为 len 字节的数据到 to 所指的缓冲中。如果成功,
* 该函数则返回拷贝的数据长度。如果队列中数据大小小于 len, 则该函数拷贝出的数据必然小于
* 需要的数据大小
*/
unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len);
/**
* 与 kfifo_out 类似,获取数据,但读后不删除数据。参数 offset 指向队列中的索引位置,如果
* 该参数为 0,则读队列头,这时候和 kfifo_out 一样。
*/
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, unsigned offset);