第一百八十八章:设计模式
大乘期涉及内核源码:
一
钟楼之后,林小源来到一座宏伟的讲道堂。讲道堂内坐满了修士,上方的高台上站着一位须发皆白的老者,手中握着一柄玉如意。
"内核之道,不仅在于算法和数据结构,更在于设计模式。"老者的声音洪亮而清晰,"设计模式是前人智慧的结晶,是解决常见问题的通用方案。"
他用玉如意在空中一划,虚空中浮现出六个光团,每个光团中都蕴含着不同的符文。
"第一个,链表。"老者指向第一个光团,"内核中最常用的数据结构。但内核的链表不是你想的那样——list_head不是独立的链表,而是嵌入到结构体中的。任何结构体,只要包含list_head成员,就能被链表管理。"
林小源恍然大悟。他之前一直以为链表是独立的数据结构,没想到内核的做法如此巧妙——通过嵌入,一个结构体可以同时属于多个链表。
二
"第二个,通知链。"老者指向第二个光团,"事件发生时,通知所有注册的回调函数。比如网络接口状态变化时,通知所有关心这个事件的模块。"
"第三个,工作队列。延迟执行,把工作推到进程上下文中处理。中断处理程序不能做太多事,就把剩下的工作交给工作队列。"
"第四个,状态机。网络协议的状态转换、文件系统的挂载状态……内核中到处都是状态机。"
老者顿了顿,目光扫过全场。"第五个,引用计数kref。当引用计数降为零时,自动释放资源。防止内存泄漏的利器。"
三
"第六个,也是最重要的——回调函数。"老者的语气变得庄重,"file_operations就是回调函数的典范。每个文件系统、每个设备驱动,都通过file_operations注册自己的open、read、write、close函数。VFS不需要知道具体的实现,只需要通过函数指针调用。"
"这就是策略模式?"林小源脱口而出。
老者赞许地点头。"没错。VFS是上下文,file_operations是策略接口,ext4、procfs、sysfs是具体策略。这就是接口与实现分离——内核可扩展性的根基。"
他收起玉如意,环顾讲道堂。"记住这些模式。它们不是教科书上的理论,而是内核中每天都在使用的实战技巧。"
/*
* 内核设计模式:
*
* 1. 链表 (list_head)
* 内核最常用的数据结构
* 嵌入到结构体中
* 宏操作
*
* 2. 通知链 (notifier_chain)
* 事件通知机制
* 注册回调函数
*
* 3. 工作队列 (workqueue)
* 延迟执行
* 进程上下文
*
* 4. 状态机
* 网络协议
* 文件系统状态
*
* 5. 引用计数
* kref
* 防止内存泄漏
*
* 6. 回调函数
* file_operations
* 策略模式
*/
/* 1. 链表模式 */
struct list_head {
struct list_head *next, *prev;
};
struct task_struct {
int pid;
char comm[16];
struct list_head list;
};
/* 2. 通知链模式 */
typedef void (*notifier_fn_t)(void *data);
struct notifier_block {
notifier_fn_t notifier_call;
struct notifier_block *next;
};
/* 3. 引用计数模式 */
struct kref {
int refcount;
};
void kref_init(struct kref *kref) {
kref->refcount = 1;
}
void kref_get(struct kref *kref) {
kref->refcount++;
}
int kref_put(struct kref *kref, void (*release)(struct kref *)) {
kref->refcount--;
if (kref->refcount == 0) {
release(kref);
return 1;
}
return 0;
}
/* 4. 回调函数模式 */
struct file_operations {
int (*open)(void);
int (*read)(void);
int (*write)(void);
int (*close)(void);
};
int my_open(void) { printf(" open\n"); return 0; }
int my_read(void) { printf(" read\n"); return 0; }
int my_write(void) { printf(" write\n"); return 0; }
int my_close(void) { printf(" close\n"); return 0; }
struct file_operations my_fops = {
.open = my_open,
.read = my_read,
.write = my_write,
.close = my_close,
};
printf("=== 设计模式 — 内核的智慧 ===\n\n");
printf("--- 1. 链表模式 ---\n");
printf("list_head:\n");
printf(" 嵌入到结构体中\n");
printf(" list_add, list_del\n");
printf(" list_for_each_entry\n\n");
printf("--- 2. 通知链模式 ---\n");
printf("notifier_chain:\n");
printf(" 注册回调函数\n");
printf(" 事件发生时通知\n\n");
printf("--- 3. 引用计数模式 ---\n");
struct kref kref;
kref_init(&kref);
printf("kref_init: refcount = %d\n", kref.refcount);
kref_get(&kref);
printf("kref_get: refcount = %d\n", kref.refcount);
kref_put(&kref, NULL);
printf("kref_put: refcount = %d\n", kref.refcount);
printf("\n--- 4. 回调函数模式 ---\n");
printf("file_operations:\n");
my_fops.open();
my_fops.read();
my_fops.write();
my_fops.close();
printf("\n--- 5. 工作队列模式 ---\n");
printf("workqueue:\n");
printf(" 延迟执行\n");
printf(" 进程上下文\n");
printf(" schedule_work()\n\n");
printf("--- 6. 状态机模式 ---\n");
printf("状态机:\n");
printf(" 网络协议状态\n");
printf(" TCP: ESTABLISHED, TIME_WAIT\n");
printf(" 文件系统状态\n\n");
printf("--- 设计原则 ---\n");
printf("1. 分离关注点\n");
printf("2. 接口与实现分离\n");
printf("3. 组合优于继承\n");
printf("4. 依赖倒置\n");#include <stdio.h>
/*
* 内核设计模式:
*
* 1. 链表 (list_head)
* 内核最常用的数据结构
* 嵌入到结构体中
* 宏操作
*
* 2. 通知链 (notifier_chain)
* 事件通知机制
* 注册回调函数
*
* 3. 工作队列 (workqueue)
* 延迟执行
* 进程上下文
*
* 4. 状态机
* 网络协议
* 文件系统状态
*
* 5. 引用计数
* kref
* 防止内存泄漏
*
* 6. 回调函数
* file_operations
* 策略模式
*/
/* 1. 链表模式 */
struct list_head {
struct list_head *next, *prev;
};
struct task_struct {
int pid;
char comm[16];
struct list_head list;
};
/* 2. 通知链模式 */
typedef void (*notifier_fn_t)(void *data);
struct notifier_block {
notifier_fn_t notifier_call;
struct notifier_block *next;
};
/* 3. 引用计数模式 */
struct kref {
int refcount;
};
void kref_init(struct kref *kref) {
kref->refcount = 1;
}
void kref_get(struct kref *kref) {
kref->refcount++;
}
int kref_put(struct kref *kref, void (*release)(struct kref *)) {
kref->refcount--;
if (kref->refcount == 0) {
release(kref);
return 1;
}
return 0;
}
/* 4. 回调函数模式 */
struct file_operations {
int (*open)(void);
int (*read)(void);
int (*write)(void);
int (*close)(void);
};
int my_open(void) { printf(" open\n"); return 0; }
int my_read(void) { printf(" read\n"); return 0; }
int my_write(void) { printf(" write\n"); return 0; }
int my_close(void) { printf(" close\n"); return 0; }
struct file_operations my_fops = {
.open = my_open,
.read = my_read,
.write = my_write,
.close = my_close,
};
int main() {
printf("=== 设计模式 — 内核的智慧 ===\n\n");
printf("--- 1. 链表模式 ---\n");
printf("list_head:\n");
printf(" 嵌入到结构体中\n");
printf(" list_add, list_del\n");
printf(" list_for_each_entry\n\n");
printf("--- 2. 通知链模式 ---\n");
printf("notifier_chain:\n");
printf(" 注册回调函数\n");
printf(" 事件发生时通知\n\n");
printf("--- 3. 引用计数模式 ---\n");
struct kref kref;
kref_init(&kref);
printf("kref_init: refcount = %d\n", kref.refcount);
kref_get(&kref);
printf("kref_get: refcount = %d\n", kref.refcount);
kref_put(&kref, NULL);
printf("kref_put: refcount = %d\n", kref.refcount);
printf("\n--- 4. 回调函数模式 ---\n");
printf("file_operations:\n");
my_fops.open();
my_fops.read();
my_fops.write();
my_fops.close();
printf("\n--- 5. 工作队列模式 ---\n");
printf("workqueue:\n");
printf(" 延迟执行\n");
printf(" 进程上下文\n");
printf(" schedule_work()\n\n");
printf("--- 6. 状态机模式 ---\n");
printf("状态机:\n");
printf(" 网络协议状态\n");
printf(" TCP: ESTABLISHED, TIME_WAIT\n");
printf(" 文件系统状态\n\n");
printf("--- 设计原则 ---\n");
printf("1. 分离关注点\n");
printf("2. 接口与实现分离\n");
printf("3. 组合优于继承\n");
printf("4. 依赖倒置\n");
return 0;
}道藏笔记
内核启示
内核中有许多经典的设计模式。
设计模式:
- 链表 — list_head 嵌入结构体
- 通知链 — 事件通知机制
- 工作队列 — 延迟执行
- 状态机 — 协议状态管理
- 引用计数 — kref 防止泄漏
- 回调函数 — file_operations 策略模式
设计原则:
- 分离关注点
- 接口与实现分离
- 组合优于继承
设计模式是智慧——解决常见问题的通用方案。
设计模式之试
设计模式一章中,把文件操作多态交给驱动实现的函数表叫什么?