1 #include <common/glib.h>
2 #include <common/kthread.h>
3 #include <common/spinlock.h>
4 #include <debug/bug.h>
5 #include <sched/sched.h>
6 #include <time/sleep.h>
7 
8 static spinlock_t __kthread_create_lock;           // kthread创建过程的锁
9 static struct List kthread_create_list;            // kthread创建任务的链表
10 struct process_control_block *kthreadd_pcb = NULL; // kthreadd守护线程的pcb
11 
12 // 枚举各个标志位是在第几位
13 enum KTHREAD_BITS
14 {
15     KTHREAD_IS_PER_CPU = 0,
16     KTHREAD_SHOULD_STOP,
17     KTHREAD_SHOULD_PARK,
18 };
19 
20 /**
21  * @brief kthread的创建信息(仅在创建过程中存在)
22  *
23  */
24 struct kthread_create_info_t
25 {
26     // 传递给kthread的信息
27     int (*thread_fn)(void *data);
28     void *data;
29     int node;
30 
31     // kthreadd守护进程传递给kthread_create的结果,
32     // 成功则返回PCB,不成功则该值为负数错误码。若该值为NULL,意味着创建过程尚未完成
33     struct process_control_block *result;
34 
35     struct List list;
36 };
37 
38 /**
39  * @brief 获取pcb中的kthread结构体
40  *
41  * @param pcb pcb
42  * @return struct kthread* kthread信息结构体
43  */
to_kthread(struct process_control_block * pcb)44 struct kthread_info_t *to_kthread(struct process_control_block *pcb)
45 {
46     WARN_ON(!(pcb->flags & PF_KTHREAD));
47     return pcb->worker_private;
48 }
49 
__kthread_create_on_node(int (* thread_fn)(void * data),void * data,int node,const char name_fmt[],va_list args)50 static struct process_control_block *__kthread_create_on_node(int (*thread_fn)(void *data), void *data, int node,
51                                                               const char name_fmt[], va_list args)
52 {
53     struct process_control_block *pcb = NULL;
54     struct kthread_create_info_t *create = kzalloc(sizeof(struct kthread_create_info_t), 0);
55 
56     if (create == NULL)
57         return ERR_PTR(-ENOMEM);
58     BUG_ON(name_fmt == NULL);
59 
60     create->thread_fn = thread_fn;
61     create->data = data;
62     create->node = node;
63     create->result = NULL;
64     list_init(&create->list);
65 
66     spin_lock(&__kthread_create_lock);
67     list_append(&kthread_create_list, &create->list);
68     spin_unlock(&__kthread_create_lock);
69     // kdebug("to wakeup kthread daemon..., current preempt=%d, rflags=%#018lx", current_pcb->preempt_count,
70 
71     // todo: 使用completion优化这里
72     while (kthreadd_pcb == NULL) // 若kthreadd未初始化,则等待kthreadd启动
73         barrier();
74 
75     // 唤醒kthreadd守护进程
76     process_wakeup_immediately(kthreadd_pcb);
77 
78     // 等待创建完成
79     // todo: 使用completion机制以降低忙等时间
80     while (create->result == NULL)
81         pause();
82     // 获取结果
83     pcb = create->result;
84     if (!IS_ERR(create->result))
85     {
86         // 为内核线程设置名字
87         char pcb_name[PCB_NAME_LEN];
88         va_list get_args;
89         va_copy(get_args, args);
90         // 获取到字符串的前16字节
91         int len = vsnprintf(pcb_name, name_fmt, PCB_NAME_LEN, get_args);
92         if (len >= PCB_NAME_LEN)
93         {
94             // 名字过大 放到full_name字段中
95             struct kthread_info_t *kthread = to_kthread(pcb);
96             char *full_name = kzalloc(1024, 0);
97             vsprintf(full_name, name_fmt, get_args);
98             kthread->full_name = full_name;
99         }
100         // 将前16Bytes放到pcb的name字段
101         process_set_pcb_name(pcb, pcb_name);
102         va_end(get_args);
103     }
104 
105     kfree(create);
106     return pcb;
107 }
108 
109 /**
110  * @brief 让当前内核线程退出,并返回result参数给kthread_stop()函数
111  *
112  * @param result 返回值
113  */
kthread_exit(long result)114 void kthread_exit(long result)
115 {
116     struct kthread_info_t *kt = to_kthread(current_pcb);
117     kt->result = result;
118     kt->exited = true;
119     process_do_exit(0);
120 }
121 
122 /**
123  * @brief 在当前结点上创建一个内核线程
124  *
125  * @param thread_fn 该内核线程要执行的函数
126  * @param data 传递给 thread_fn 的参数数据
127  * @param node 线程的任务和线程结构都分配在这个节点上
128  * @param name_fmt printf-style format string for the thread name
129  * @param arg name_fmt的参数
130  * @return 返回一个pcb或者是ERR_PTR(-ENOMEM)
131  *
132  * 请注意,该宏会创建一个内核线程,并将其设置为停止状态。您可以使用wake_up_process来启动这个线程。
133  * 新的线程的调度策略为SCHED_NORMAL,并且能在所有的cpu上运行
134  *
135  * 当内核线程被唤醒时,会运行thread_fn函数,并将data作为参数传入。
136  * 内核线程可以直接返回,也可以在kthread_should_stop为真时返回。
137  */
kthread_create_on_node(int (* thread_fn)(void * data),void * data,int node,const char name_fmt[],...)138 struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data), void *data, int node,
139                                                      const char name_fmt[], ...)
140 {
141     struct process_control_block *pcb;
142     va_list args;
143     va_start(args, name_fmt);
144     pcb = __kthread_create_on_node(thread_fn, data, node, name_fmt, args);
145     va_end(args);
146     return pcb;
147 }
148 /**
149  * @brief 内核线程的包裹程序
150  * 当内核线程被运行后,从kernel_thread_func跳转到这里。
151  * @param _create 内核线程的创建信息
152  * @return int 内核线程的退出返回值
153  */
kthread(void * _create)154 static int kthread(void *_create)
155 {
156     struct kthread_create_info_t *create = _create;
157     // 将这几个信息从kthread_create_info中拷贝过来。以免在kthread_create_info被free后,数据丢失从而导致错误。
158     int (*thread_fn)(void *data) = create->thread_fn;
159     void *data = create->data;
160 
161     int retval = 0;
162 
163     struct kthread_info_t *self = to_kthread(current_pcb);
164 
165     self->thread_fn = thread_fn;
166     self->data = data;
167 
168     // todo: 增加调度参数设定
169     // todo: 当前内核线程继承了kthreadd的优先级以及调度策略,需要在这里进行更新
170 
171     // 设置当前进程为不可被打断
172     current_pcb->state = PROC_UNINTERRUPTIBLE;
173 
174     // 将当前pcb返回给创建者
175     create->result = current_pcb;
176 
177     current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态
178     io_mfence();
179 
180     // 发起调度,使得当前内核线程休眠。直到创建者通过process_wakeup将当前内核线程唤醒
181     sched();
182 
183     retval = -EINTR;
184     // 如果发起者没有调用kthread_stop(),则该kthread的功能函数开始执行
185     if (!(self->flags & (1 << KTHREAD_SHOULD_STOP)))
186     {
187         retval = thread_fn(data);
188     }
189     kthread_exit(retval);
190 }
191 
__create_kthread(struct kthread_create_info_t * create)192 static void __create_kthread(struct kthread_create_info_t *create)
193 {
194     pid_t pid = kernel_thread(kthread, create, CLONE_FS | CLONE_SIGNAL);
195     io_mfence();
196     if (IS_ERR((void *)pid))
197     {
198         // todo: 使用complete机制完善这里
199 
200         create->result = (struct process_control_block *)pid;
201     }
202 }
203 
204 #pragma GCC push_options
205 #pragma GCC optimize("O0")
206 /**
207  * @brief kthread守护线程
208  *
209  * @param unused
210  * @return int 不应当退出
211  */
kthreadd(void * unused)212 int kthreadd(void *unused)
213 {
214     barrier();
215     kinfo("kthread daemon started!");
216     struct process_control_block *pcb = current_pcb;
217     barrier();
218     kthreadd_pcb = current_pcb;
219     barrier();
220     current_pcb->flags |= PF_NOFREEZE;
221 
222     for (;;)
223     {
224         current_pcb->state = PROC_INTERRUPTIBLE;
225 
226         // 所有的创建任务都被处理完了
227         if (list_empty(&kthread_create_list))
228             sched();
229 
230         spin_lock(&__kthread_create_lock);
231 
232         // 循环取出链表中的任务
233         while (!list_empty(&kthread_create_list))
234         {
235 
236             // 从链表中取出第一个要创建的内核线程任务
237             struct kthread_create_info_t *create =
238                 container_of(kthread_create_list.next, struct kthread_create_info_t, list);
239             list_del_init(&create->list);
240             spin_unlock(&__kthread_create_lock);
241 
242             __create_kthread(create);
243 
244             spin_lock(&__kthread_create_lock);
245         }
246         spin_unlock(&__kthread_create_lock);
247     }
248     barrier();
249 }
250 
251 #pragma GCC pop_options
252 
253 /**
254  * @brief 内核线程调用该函数,检查自身的标志位,判断自己是否应该执行完任务后退出
255  *
256  * @return true 内核线程应该退出
257  * @return false 无需退出
258  */
kthread_should_stop(void)259 bool kthread_should_stop(void)
260 {
261     struct kthread_info_t *self = to_kthread(current_pcb);
262     if (self->flags & (1 << KTHREAD_SHOULD_STOP))
263         return true;
264 
265     return false;
266 }
267 
268 /**
269  * @brief 向kthread发送停止信号,请求其结束
270  *
271  * @param pcb 内核线程的pcb
272  * @return int 错误码
273  */
kthread_stop(struct process_control_block * pcb)274 int kthread_stop(struct process_control_block *pcb)
275 {
276     int retval;
277     struct kthread_info_t *target = to_kthread(pcb);
278     target->flags |= (1 << KTHREAD_SHOULD_STOP);
279     process_wakeup(pcb);
280     // 等待指定的内核线程退出
281     // todo: 使用completion机制改进这里
282     while (target->exited == false)
283         rs_usleep(5000);
284     retval = target->result;
285 
286     // 释放内核线程的页表
287     process_exit_mm(pcb);
288     process_release_pcb(pcb);
289     return retval;
290 }
291 
292 /**
293  * @brief 设置pcb中的worker_private字段(只应被设置一次)
294  *
295  * @param pcb pcb
296  * @return bool 成功或失败
297  */
kthread_set_worker_private(struct process_control_block * pcb)298 bool kthread_set_worker_private(struct process_control_block *pcb)
299 {
300     if (WARN_ON_ONCE(to_kthread(pcb)))
301         return false;
302 
303     struct kthread_info_t *kt = kzalloc(sizeof(struct kthread_info_t), 0);
304     if (kt == NULL)
305         return false;
306     pcb->worker_private = kt;
307     return true;
308 }
309 
310 /**
311  * @brief 初始化kthread机制(只应被process_init调用)
312  *
313  * @return int 错误码
314  */
kthread_mechanism_init()315 int kthread_mechanism_init()
316 {
317     kinfo("Initializing kthread mechanism...");
318     spin_init(&__kthread_create_lock);
319     list_init(&kthread_create_list);
320     // 创建kthreadd守护进程
321     kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_SIGNAL);
322 
323     return 0;
324 }
325 
326 /**
327  * @brief 释放pcb指向的worker private
328  *
329  * @param pcb 要释放的pcb
330  */
free_kthread_struct(struct process_control_block * pcb)331 void free_kthread_struct(struct process_control_block *pcb)
332 {
333     struct kthread_info_t *kthread = to_kthread(pcb);
334     if (!kthread)
335     {
336         return;
337     }
338     pcb->worker_private = NULL;
339     kfree(kthread->full_name);
340     kfree(kthread);
341 }