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