kthread.c 8.7 KB

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