kthread.c 9.5 KB

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