Linux内核开发常用函数
在Linux内核开发中,proc_create
和kthread_run
是两类重要函数,分别用于proc文件系统操作和内核线程管理。以下是同类函数的详细分类解析:
一、proc文件系统相关函数族
1. 核心函数
函数原型 | 作用 | 参数说明 | 返回值 | 典型场景 |
---|---|---|---|---|
struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops) | 创建proc文件 | - name : 文件名- mode : 权限- parent : 父目录- proc_ops : 文件操作结构体 | 成功返回proc条目指针,失败返回NULL | 创建可读写的控制文件 |
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) | 创建proc目录 | - name : 目录名- parent : 父目录 | 成功返回目录指针,失败返回NULL | 创建类似/proc/module_name 的目录 |
void proc_remove(struct proc_dir_entry *de) | 删除proc条目 | de : 要删除的条目指针 | 无 | 模块卸载时清理proc文件 |
2. 辅助函数
函数 | 作用 | 示例 |
---|---|---|
proc_symlink | 创建符号链接 | proc_symlink("link", NULL, "/proc/real_file") |
proc_create_single | 创建只读文件(简化版) | 适用于仅需seq_show 的文件 |
proc_create_data | 创建支持私有数据的文件 | 传递自定义数据到文件操作函数 |
3. 旧版兼容函数(已逐步淘汰)
create_proc_entry() // 旧版创建方法(Linux 3.10前)
remove_proc_entry() // 旧版删除方法
二、内核线程相关函数族
1. 线程创建/管理
函数原型 | 作用 | 关键区别 | 使用场景 |
---|---|---|---|
struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char namefmt[], ...) | 创建并启动线程 | 宏定义,组合了kthread_create 和wake_up_process | 需要立即运行的线程 |
struct task_struct *kthread_create(threadfn, data, namefmt, ...) | 创建线程但不启动 | 需手动调用wake_up_process | 延迟启动或条件触发 |
int kthread_stop(struct task_struct *k) | 停止线程 | 发送停止信号,需线程内检查kthread_should_stop() | 模块退出时清理线程 |
bool kthread_should_stop(void) | 检查停止标志 | 线程主循环中需周期性调用 | 安全退出线程 |
2. 其他相关函数
函数 | 作用 |
---|---|
kthread_park() / kthread_unpark() | 暂停/恢复线程执行 |
kthread_bind() | 将线程绑定到特定CPU核心 |
三、对比与使用示例
proc_create vs 其他文件系统
// Proc文件系统
proc_create("status", 0444, dir, &proc_ops); // 创建只读状态文件// Sysfs文件系统(/sys/class/...)
sysfs_create_file(struct kobject *kobj, const struct attribute *attr);// Debugfs文件系统(调试专用)
debugfs_create_file("debug", 0644, debug_dir, data, &debug_fops);
kthread_run vs 工作队列
// 内核线程(适合长时间运行的任务)
kthread_run(reclaimer_thread, NULL, "my_kthread");// 工作队列(适合短任务调度)
struct workqueue_struct *wq = alloc_workqueue("my_wq", 0, 0);
INIT_WORK(&my_work, work_handler);
queue_work(wq, &my_work);
四、关键开发注意事项
Proc文件系统
- 内存安全:
proc_write
需使用copy_from_user
,禁止直接访问用户空间指针 - 原子操作:多进程访问时需通过锁或原子变量保护共享数据
- 资源释放:模块退出时必须调用
proc_remove
或remove_proc_subtree
内核线程
- 终止条件:线程函数必须检查
kthread_should_stop()
,否则无法正常退出 - 优先级控制:可通过
sched_setscheduler
设置线程优先级(如SCHED_FIFO
) - 栈大小:默认内核线程栈大小(通常8KB-16KB),避免栈溢出
五、完整代码片段示例
1. Proc文件创建
static const struct proc_ops my_proc_ops = {.proc_open = my_proc_open,.proc_read = seq_read,.proc_write = my_proc_write,.proc_lseek = seq_lseek,.proc_release = single_release,
};proc_create("config", 0666, proc_dir, &my_proc_ops);
2. 内核线程生命周期管理
static int my_thread(void *data) {while (!kthread_should_stop()) {// 执行任务...set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(HZ); // 休眠1秒}return 0;
}// 启动
task = kthread_run(my_thread, NULL, "my_thread");// 停止
kthread_stop(task);
六、调试技巧
- 查看Proc条目:
cat /proc/cgroup_reclaimer/control
- 线程状态监控:
ps -eLf | grep my_thread
- 内核日志:
dmesg -w
实时查看pr_info
输出 - Oops调试:确保所有函数有错误检查,使用
IS_ERR
判断线程创建结果
掌握这些函数的使用模式是内核模块开发的基础,合理选择取决于具体需求和执行上下文。