文章目录
一、init_kthread_worker()宏
include/linux/kthread.h
初始化 kthread_worker 结构体
#define init_kthread_worker(worker) \
do { \
static struct lock_class_key __key; \
__init_kthread_worker((worker), "("#worker")->lock", &__key); \
} while (0)
1、__init_kthread_worker()函数
include/linux/kthread.h
void __init_kthread_worker(struct kthread_worker *worker,
const char *name,
struct lock_class_key *key)
{
memset(worker, 0, sizeof(struct kthread_worker));
// 初始化自旋锁
spin_lock_init(&worker->lock);
lockdep_set_class_and_name(&worker->lock, key, name);
// 初始化链表结点
INIT_LIST_HEAD(&worker->work_list);
// 初始化链表结点
INIT_LIST_HEAD(&worker->delayed_work_list);
}
二、kthread_worker_fn()函数
kernel/kthread.c
int kthread_worker_fn(void *worker_ptr)
{
// 指针类型转化
struct kthread_worker *worker = worker_ptr;
struct kthread_work *work;
...
// current是内核的一个全局变量,专门用来表示当前运行的进程或者线程
// 当某个线程运行这个函数时,线程会被保存到task指针
worker->task = current;
if (worker->flags & KTW_FREEZABLE)
set_freezable();
repeat:
// 设置当前线程的运行状态(当前的线程可以接收中断)
set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */
// 判断当前线程是否应该停止运行,详见下
if (kthread_should_stop()) {
// 设置当前进程线程为正在运行态
__set_current_state(TASK_RUNNING);
spin_lock_irq(&worker->lock);
// task原来是指向当前线程,现在要停止运行了,指针设置为指向空
worker->task = NULL;
spin_unlock_irq(&worker->lock);
return 0;
}
// 若线程没有结束运行,则接着执行下面的代码
// struct kthread_work
work = NULL;
spin_lock_irq(&worker->lock);
// 遍历工人的work_list成员
if (!list_empty(&worker->work_list)) {
// 根据链表结点获取具体工作结构体 kthread_work
work = list_first_entry(&worker->work_list,
struct kthread_work, node);
// 将work中的链表结点从worker的链表里面删除
list_del_init(&work->node);
}
worker->current_work = work;
spin_unlock_irq(&worker->lock);
if (work) {
// 设置当前线程为正在运行
__set_current_state(TASK_RUNNING);
// 自己实现的那个具体函数
work->func(work);
} else if (!freezing(current))
schedule();//让出处理机资源
try_to_freeze();
cond_resched();
// 其实是个死循环,每一次循环都会有一个链表节点对应的node被提取出来
goto repeat;
}
1、kthread_should_stop()函数
kernel/kthread.c
bool kthread_should_stop(void)
{
// 判断当前线程的标志位
return test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
}
- 调用kthread_stop()函数后,设置线程flags为KTHREAD_SHOULD_STOP
二、init_kthread_work()函数
include/linux/kthread.h
初始化kthread_work,为工作变量结构体指定一个具体的函数fn
#define kinit_thread_work(work, fn) \
do { \//初始化work成员变量
memset((work), 0, sizeof(struct kthread_work)); \
INIT_LIST_HEAD(&(work)->node); \//初始化work中的链表节点
(work)->func = (fn); \//fn就是我们自定义的
} while (0)
三、kthread_queue_work()函数
kernel/kthread.c
把具体的工作交付给worker
其实就是把work中的链表节点插入到worker对应的链表中
bool kthread_queue_work(struct kthread_worker *worker,
struct kthread_work *work)
{
bool ret = false;
unsigned long flags;
// 加锁,加锁前先关中断
spin_lock_irqsave(&worker->lock, flags);
// 详见下
if (!queuing_blocked(worker, work)) {
// 详见下
kthread_insert_work(worker, work, &worker->work_list);
ret = true;
}
// 解锁,加锁后开中断
spin_unlock_irqrestore(&worker->lock, flags);
return ret;
}
1、queuing_blocked()函数
kernel/kthread.c
static inline bool queuing_blocked(struct kthread_worker *worker,
struct kthread_work *work)
{
lockdep_assert_held(&worker->lock);
// 关键,判断节点是否为空,不为空表示已经挂载到worker,返回后不需要再挂载
// work->canceling非0表示要退出,返回后也不需要挂载了
return !list_empty(&work->node) || work->canceling;
}
2、kthread_insert_work()函数
kernel/kthread.c
work到worker的链表节点插入
static void kthread_insert_work(struct kthread_worker *worker,
struct kthread_work *work,
struct list_head *pos)
{
kthread_insert_work_sanity_check(worker, work);
// work对应的结点串到worker的结点链表中
list_add_tail(&work->node, pos);
work->worker = worker;
// current_work 表示当前worker正在执行的具体工作,为0表示还没开始工作
if (!worker->current_work && likely(worker->task))
wake_up_process(worker->task);// 唤醒worker开始工作,通过参数来唤醒,所以上面要先判空
}
// 然后具体工作等待被worker处理
四、kthread_flush_worker()函数
kernel/kthread.c
void kthread_flush_worker(struct kthread_worker *worker)
{
struct kthread_flush_work fwork = {
KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn),
COMPLETION_INITIALIZER_ONSTACK(fwork.done),
};
// 两件事:work中的node加入,唤醒worker工作
// 其实相当于在worker的链表最末尾新加了一个链表节点,这个具体工作最后被处理(就是最后执行kthread_flush_work_fn)
kthread_queue_work(worker, &fwork.work);
// 参数类型为 struct completion 完成量
// 进程进入休眠状态
// 会在 kthread_flush_work_fn 中唤醒此完成量,其实就是执行到最后kthread_work对应的函数就是这个,那么前面的都执行完毕了
wait_for_completion(&fwork.done);
}
1、KTHREAD_WORK_INIT()宏
#define KTHREAD_WORK_INIT(work, fn) { \
.node = LIST_HEAD_INIT((work).node), \
.func = (fn), \
}
2、COMPLETION_INITIALIZER_ONSTACK()宏
include/linux/completion.h
// 初始化完成量,初始化完赋值给 kthread_flush_work对应的done成员
(*({ init_completion(&work); &work; }))
3、kthread_flush_work_fn()函数
kernel/kthread.c
static void kthread_flush_work_fn(struct kthread_work *work)
{
struct kthread_flush_work *fwork =
container_of(work, struct kthread_flush_work, work);
// 唤醒阻塞在kthread_flush_worker的线程
complete(&fwork->done);
}