task.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) 2012-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <errno.h>
  18. #include <stddef.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <kern/init.h>
  22. #include <kern/kmem.h>
  23. #include <kern/list.h>
  24. #include <kern/log.h>
  25. #include <kern/macros.h>
  26. #include <kern/shell.h>
  27. #include <kern/spinlock.h>
  28. #include <kern/task.h>
  29. #include <kern/thread.h>
  30. #include <vm/vm_map.h>
  31. #ifdef __LP64__
  32. #define TASK_INFO_ADDR_FMT "%016lx"
  33. #else /* __LP64__ */
  34. #define TASK_INFO_ADDR_FMT "%08lx"
  35. #endif /* __LP64__ */
  36. struct task task_kernel_task;
  37. /*
  38. * Cache for allocated tasks.
  39. */
  40. static struct kmem_cache task_cache;
  41. /*
  42. * Global list of tasks.
  43. */
  44. static struct list task_list;
  45. static struct spinlock task_list_lock;
  46. static void
  47. task_init(struct task *task, const char *name, struct vm_map *map)
  48. {
  49. task->nr_refs = 1;
  50. spinlock_init(&task->lock);
  51. list_init(&task->threads);
  52. task->map = map;
  53. strlcpy(task->name, name, sizeof(task->name));
  54. }
  55. #ifdef CONFIG_SHELL
  56. static void
  57. task_shell_info(struct shell *shell, int argc, char *argv[])
  58. {
  59. struct task *task;
  60. int error;
  61. (void)shell;
  62. if (argc == 1) {
  63. task_info(NULL, printf_ln);
  64. return;
  65. } else {
  66. task = task_lookup(argv[1]);
  67. if (task == NULL) {
  68. error = EINVAL;
  69. goto error;
  70. }
  71. task_info(task, printf_ln);
  72. task_unref(task);
  73. }
  74. return;
  75. error:
  76. printf_ln("task: info: %s", strerror(error));
  77. }
  78. static struct shell_cmd task_shell_cmds[] = {
  79. SHELL_CMD_INITIALIZER("task_info", task_shell_info,
  80. "task_info [<task_name>]",
  81. "display tasks and threads"),
  82. };
  83. static int __init
  84. task_setup_shell(void)
  85. {
  86. SHELL_REGISTER_CMDS(task_shell_cmds, shell_get_main_cmd_set());
  87. return 0;
  88. }
  89. INIT_OP_DEFINE(task_setup_shell,
  90. INIT_OP_DEP(printf_setup, true),
  91. INIT_OP_DEP(shell_setup, true),
  92. INIT_OP_DEP(task_setup, true),
  93. INIT_OP_DEP(thread_setup, true));
  94. #endif /* CONFIG_SHELL */
  95. static int __init
  96. task_setup(void)
  97. {
  98. struct task *kernel_task;
  99. kernel_task = task_get_kernel_task();
  100. kmem_cache_init(&task_cache, "task", sizeof(struct task), 0, NULL, 0);
  101. list_init(&task_list);
  102. spinlock_init(&task_list_lock);
  103. task_init(kernel_task, "x15", vm_map_get_kernel_map());
  104. list_insert_head(&task_list, &kernel_task->node);
  105. return 0;
  106. }
  107. INIT_OP_DEFINE(task_setup,
  108. INIT_OP_DEP(kmem_setup, true),
  109. INIT_OP_DEP(spinlock_setup, true),
  110. INIT_OP_DEP(vm_map_setup, true));
  111. int
  112. task_create(struct task **taskp, const char *name)
  113. {
  114. struct vm_map *map;
  115. struct task *task;
  116. int error;
  117. task = kmem_cache_alloc(&task_cache);
  118. if (task == NULL) {
  119. error = ENOMEM;
  120. goto error_task;
  121. }
  122. error = vm_map_create(&map);
  123. if (error) {
  124. goto error_map;
  125. }
  126. task_init(task, name, map);
  127. spinlock_lock(&task_list_lock);
  128. list_insert_tail(&task_list, &task->node);
  129. spinlock_unlock(&task_list_lock);
  130. *taskp = task;
  131. return 0;
  132. error_map:
  133. kmem_cache_free(&task_cache, task);
  134. error_task:
  135. return error;
  136. }
  137. struct task *
  138. task_lookup(const char *name)
  139. {
  140. struct task *task;
  141. spinlock_lock(&task_list_lock);
  142. list_for_each_entry(&task_list, task, node) {
  143. spinlock_lock(&task->lock);
  144. if (strcmp(task->name, name) == 0) {
  145. task_ref(task);
  146. spinlock_unlock(&task->lock);
  147. spinlock_unlock(&task_list_lock);
  148. return task;
  149. }
  150. spinlock_unlock(&task->lock);
  151. }
  152. spinlock_unlock(&task_list_lock);
  153. return NULL;
  154. }
  155. void
  156. task_add_thread(struct task *task, struct thread *thread)
  157. {
  158. spinlock_lock(&task->lock);
  159. list_insert_tail(&task->threads, &thread->task_node);
  160. spinlock_unlock(&task->lock);
  161. }
  162. void
  163. task_remove_thread(struct task *task, struct thread *thread)
  164. {
  165. spinlock_lock(&task->lock);
  166. list_remove(&thread->task_node);
  167. spinlock_unlock(&task->lock);
  168. }
  169. struct thread *
  170. task_lookup_thread(struct task *task, const char *name)
  171. {
  172. struct thread *thread;
  173. spinlock_lock(&task->lock);
  174. list_for_each_entry(&task->threads, thread, task_node) {
  175. if (strcmp(thread_name(thread), name) == 0) {
  176. thread_ref(thread);
  177. spinlock_unlock(&task->lock);
  178. return thread;
  179. }
  180. }
  181. spinlock_unlock(&task->lock);
  182. return NULL;
  183. }
  184. void
  185. task_info(struct task *task, log_print_fn_t print_fn)
  186. {
  187. struct thread *thread;
  188. if (task == NULL) {
  189. spinlock_lock(&task_list_lock);
  190. list_for_each_entry(&task_list, task, node) {
  191. task_info(task, print_fn);
  192. }
  193. spinlock_unlock(&task_list_lock);
  194. return;
  195. }
  196. spinlock_lock(&task->lock);
  197. print_fn("task: name: %s, threads:", task->name);
  198. /*
  199. * Don't grab any lock when accessing threads, so that the function
  200. * can be used to debug in the middle of most critical sections.
  201. * Threads are only destroyed after being removed from their task
  202. * so holding the task lock is enough to guarantee existence.
  203. *
  204. * TODO Handle tasks and threads names modifications.
  205. */
  206. list_for_each_entry(&task->threads, thread, task_node) {
  207. print_fn(TASK_INFO_ADDR_FMT " %c %8s:" TASK_INFO_ADDR_FMT
  208. " %.2s:%02hu %02u %s",
  209. (unsigned long)thread,
  210. thread_state_to_chr(thread_state(thread)),
  211. thread_wchan_desc(thread),
  212. (unsigned long)thread_wchan_addr(thread),
  213. thread_sched_class_to_str(thread_user_sched_class(thread)),
  214. thread_user_priority(thread),
  215. thread_real_global_priority(thread),
  216. thread_name(thread));
  217. }
  218. spinlock_unlock(&task->lock);
  219. }