source: mainline/kernel/generic/src/proc/task.c@ 0f94c3d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0f94c3d was 0f94c3d, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Read command line for multiboot modules on ia32 and copy it to task name. Other arches will need to initialize task names in the init structure to an empty string.

  • Property mode set to 100644
File size: 10.7 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[f761f1eb]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[cc73a8a1]29/** @addtogroup genericproc
[b45c443]30 * @{
31 */
32
[9179d0a]33/**
[b45c443]34 * @file
[9179d0a]35 * @brief Task management.
36 */
37
[f761f1eb]38#include <proc/thread.h>
39#include <proc/task.h>
[20d50a1]40#include <mm/as.h>
[085d973]41#include <mm/slab.h>
[31d8e10]42#include <atomic.h>
[f761f1eb]43#include <synch/spinlock.h>
[5573942]44#include <synch/waitq.h>
[f761f1eb]45#include <arch.h>
[8605b24]46#include <arch/barrier.h>
[b76a2217]47#include <adt/avl.h>
[7f6e755]48#include <adt/btree.h>
[5c9a08b]49#include <adt/list.h>
[6d9c49a]50#include <ipc/ipc.h>
[c98e6ee]51#include <ipc/ipcrsc.h>
[37c57f2]52#include <print.h>
[7509ddc]53#include <errno.h>
[95155b0c]54#include <func.h>
[e3c762cd]55#include <syscall/copy.h>
[8e5e78f]56
[b76a2217]57/** Spinlock protecting the tasks_tree AVL tree. */
[dc747e3]58SPINLOCK_INITIALIZE(tasks_lock);
[88169d9]59
[b76a2217]60/** AVL tree of active tasks.
[88169d9]61 *
[b76a2217]62 * The task is guaranteed to exist after it was found in the tasks_tree as
[6f4495f5]63 * long as:
[88169d9]64 * @li the tasks_lock is held,
[6f4495f5]65 * @li the task's lock is held when task's lock is acquired before releasing
66 * tasks_lock or
[7bb6b06]67 * @li the task's refcount is greater than 0
[88169d9]68 *
69 */
[b76a2217]70avltree_t tasks_tree;
[88169d9]71
[286e03d]72static task_id_t task_counter = 0;
[70527f1]73
[814c4f5]74/** Initialize kernel tasks support. */
[f761f1eb]75void task_init(void)
76{
[43114c5]77 TASK = NULL;
[b76a2217]78 avltree_create(&tasks_tree);
79}
80
81/*
[814c4f5]82 * The idea behind this walker is to remember a single task different from
83 * TASK.
[b76a2217]84 */
85static bool task_done_walker(avltree_node_t *node, void *arg)
86{
87 task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
88 task_t **tp = (task_t **) arg;
89
90 if (t != TASK) {
91 *tp = t;
92 return false; /* stop walking */
93 }
94
95 return true; /* continue the walk */
[f761f1eb]96}
97
[814c4f5]98/** Kill all tasks except the current task. */
[f74bbaf]99void task_done(void)
100{
101 task_t *t;
102 do { /* Repeat until there are any tasks except TASK */
103
104 /* Messing with task structures, avoid deadlock */
105 ipl_t ipl = interrupts_disable();
106 spinlock_lock(&tasks_lock);
107
108 t = NULL;
[b76a2217]109 avltree_walk(&tasks_tree, task_done_walker, &t);
[f74bbaf]110
111 if (t != NULL) {
112 task_id_t id = t->taskid;
113
114 spinlock_unlock(&tasks_lock);
115 interrupts_restore(ipl);
116
117#ifdef CONFIG_DEBUG
[52755f1]118 printf("Killing task %" PRIu64 "\n", id);
[f74bbaf]119#endif
120 task_kill(id);
[d4e38c7]121 thread_usleep(10000);
[f74bbaf]122 } else {
123 spinlock_unlock(&tasks_lock);
124 interrupts_restore(ipl);
125 }
126
127 } while (t != NULL);
128}
[70527f1]129
[814c4f5]130/** Create new task with no threads.
[70527f1]131 *
[814c4f5]132 * @param as Task's address space.
[24345a5]133 * @param name Symbolic name (a copy is made).
[70527f1]134 *
[814c4f5]135 * @return New task's structure.
[70527f1]136 *
137 */
[ff14c520]138task_t *task_create(as_t *as, char *name)
[f761f1eb]139{
[22f7769]140 ipl_t ipl;
[f761f1eb]141 task_t *ta;
[2ba7810]142 int i;
[f761f1eb]143
[bb68433]144 ta = (task_t *) malloc(sizeof(task_t), 0);
145
[963074b3]146 task_create_arch(ta);
147
[bb68433]148 spinlock_initialize(&ta->lock, "task_ta_lock");
149 list_initialize(&ta->th_head);
150 ta->as = as;
[24345a5]151
152 memcpy(ta->name, name, TASK_NAME_BUFLEN);
153 ta->name[TASK_NAME_BUFLEN - 1] = '\0';
154
[ea7890e7]155 atomic_set(&ta->refcount, 0);
156 atomic_set(&ta->lifecount, 0);
[cfffb290]157 ta->context = CONTEXT;
[7509ddc]158
[1077d91]159 ta->capabilities = 0;
[0313ff0]160 ta->cycles = 0;
[9a1b20c]161
162#ifdef CONFIG_UDEBUG
163 /* Init debugging stuff */
164 udebug_task_init(&ta->udebug);
165
166 /* Init kbox stuff */
[31696b4f]167 ipc_answerbox_init(&ta->kb.box, ta);
168 ta->kb.thread = NULL;
169 mutex_initialize(&ta->kb.cleanup_lock, MUTEX_PASSIVE);
170 ta->kb.finished = false;
[9a1b20c]171#endif
172
[12ab886]173 ipc_answerbox_init(&ta->answerbox, ta);
[cfffb290]174 for (i = 0; i < IPC_MAX_PHONES; i++)
[2ba7810]175 ipc_phone_init(&ta->phones[i]);
[6f4495f5]176 if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context,
177 ta->context)))
[2ba7810]178 ipc_phone_connect(&ta->phones[0], ipc_phone_0);
[5f62ef9]179 atomic_set(&ta->active_calls, 0);
[4fded58]180
[08a19ba]181 mutex_initialize(&ta->futexes_lock, MUTEX_PASSIVE);
[4fded58]182 btree_create(&ta->futexes);
[bb68433]183
184 ipl = interrupts_disable();
[482826d]185
186 /*
187 * Increment address space reference count.
188 */
[31d8e10]189 atomic_inc(&as->refcount);
[482826d]190
[bb68433]191 spinlock_lock(&tasks_lock);
[286e03d]192 ta->taskid = ++task_counter;
[b76a2217]193 avltree_node_initialize(&ta->tasks_tree_node);
194 ta->tasks_tree_node.key = ta->taskid;
195 avltree_insert(&tasks_tree, &ta->tasks_tree_node);
[bb68433]196 spinlock_unlock(&tasks_lock);
197 interrupts_restore(ipl);
198
[f761f1eb]199 return ta;
200}
201
[7509ddc]202/** Destroy task.
203 *
[814c4f5]204 * @param t Task to be destroyed.
[7509ddc]205 */
206void task_destroy(task_t *t)
207{
[ea7890e7]208 /*
209 * Remove the task from the task B+tree.
210 */
211 spinlock_lock(&tasks_lock);
[b76a2217]212 avltree_delete(&tasks_tree, &t->tasks_tree_node);
[ea7890e7]213 spinlock_unlock(&tasks_lock);
214
215 /*
216 * Perform architecture specific task destruction.
217 */
[31e8ddd]218 task_destroy_arch(t);
[ea7890e7]219
220 /*
221 * Free up dynamically allocated state.
222 */
[31e8ddd]223 btree_destroy(&t->futexes);
224
[ea7890e7]225 /*
226 * Drop our reference to the address space.
227 */
[31d8e10]228 if (atomic_predec(&t->as->refcount) == 0)
[31e8ddd]229 as_destroy(t->as);
230
231 free(t);
232 TASK = NULL;
[7509ddc]233}
234
[ec55358]235/** Syscall for reading task ID from userspace.
236 *
[814c4f5]237 * @param uspace_task_id userspace address of 8-byte buffer
238 * where to store current task ID.
[ec55358]239 *
[814c4f5]240 * @return Zero on success or an error code from @ref errno.h.
[ec55358]241 */
[7f1c620]242unative_t sys_task_get_id(task_id_t *uspace_task_id)
[ec55358]243{
244 /*
[814c4f5]245 * No need to acquire lock on TASK because taskid remains constant for
246 * the lifespan of the task.
[ec55358]247 */
[6f4495f5]248 return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid,
249 sizeof(TASK->taskid));
[ec55358]250}
251
[bc18d63]252/** Syscall for setting the task name.
253 *
254 * The name simplifies identifying the task in the task list.
255 *
256 * @param name The new name for the task. (typically the same
257 * as the command used to execute it).
258 *
259 * @return 0 on success or an error code from @ref errno.h.
260 */
261unative_t sys_task_set_name(const char *uspace_name, size_t name_len)
262{
263 int rc;
264 char namebuf[TASK_NAME_BUFLEN];
265
266 /* Cap length of name and copy it from userspace. */
267
268 if (name_len > TASK_NAME_BUFLEN - 1)
269 name_len = TASK_NAME_BUFLEN - 1;
270
271 rc = copy_from_uspace(namebuf, uspace_name, name_len);
272 if (rc != 0)
273 return (unative_t) rc;
274
275 namebuf[name_len] = '\0';
276 strcpy(TASK->name, namebuf);
277
278 return EOK;
279}
280
[9a8d91b]281/** Find task structure corresponding to task ID.
282 *
[814c4f5]283 * The tasks_lock must be already held by the caller of this function and
284 * interrupts must be disabled.
[9a8d91b]285 *
[814c4f5]286 * @param id Task ID.
[9a8d91b]287 *
[814c4f5]288 * @return Task structure address or NULL if there is no such task
289 * ID.
[9a8d91b]290 */
[814c4f5]291task_t *task_find_by_id(task_id_t id) { avltree_node_t *node;
[9a8d91b]292
[b76a2217]293 node = avltree_search(&tasks_tree, (avltree_key_t) id);
294
295 if (node)
296 return avltree_get_instance(node, task_t, tasks_tree_node);
297 return NULL;
[9a8d91b]298}
299
[0313ff0]300/** Get accounting data of given task.
301 *
[814c4f5]302 * Note that task lock of 't' must be already held and interrupts must be
303 * already disabled.
[0313ff0]304 *
[814c4f5]305 * @param t Pointer to thread.
[0313ff0]306 *
[814c4f5]307 * @return Number of cycles used by the task and all its threads
308 * so far.
[0313ff0]309 */
310uint64_t task_get_accounting(task_t *t)
311{
312 /* Accumulated value of task */
313 uint64_t ret = t->cycles;
314
315 /* Current values of threads */
316 link_t *cur;
317 for (cur = t->th_head.next; cur != &t->th_head; cur = cur->next) {
318 thread_t *thr = list_get_instance(cur, thread_t, th_link);
319
320 spinlock_lock(&thr->lock);
[62b6d17]321 /* Process only counted threads */
322 if (!thr->uncounted) {
[6f4495f5]323 if (thr == THREAD) {
324 /* Update accounting of current thread */
325 thread_update_accounting();
326 }
[62b6d17]327 ret += thr->cycles;
328 }
[0313ff0]329 spinlock_unlock(&thr->lock);
330 }
331
332 return ret;
333}
334
[7509ddc]335/** Kill task.
[ea7890e7]336 *
337 * This function is idempotent.
338 * It signals all the task's threads to bail it out.
[7509ddc]339 *
[814c4f5]340 * @param id ID of the task to be killed.
[7509ddc]341 *
[814c4f5]342 * @return Zero on success or an error code from errno.h.
[7509ddc]343 */
344int task_kill(task_id_t id)
345{
346 ipl_t ipl;
347 task_t *ta;
348 link_t *cur;
[9b6aae6]349
350 if (id == 1)
351 return EPERM;
[7509ddc]352
353 ipl = interrupts_disable();
354 spinlock_lock(&tasks_lock);
355 if (!(ta = task_find_by_id(id))) {
356 spinlock_unlock(&tasks_lock);
357 interrupts_restore(ipl);
358 return ENOENT;
359 }
[31e8ddd]360 spinlock_unlock(&tasks_lock);
[7509ddc]361
[b91bb65]362 /*
[814c4f5]363 * Interrupt all threads.
[ea7890e7]364 */
365 spinlock_lock(&ta->lock);
[7509ddc]366 for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
367 thread_t *thr;
[ea7890e7]368 bool sleeping = false;
[7509ddc]369
370 thr = list_get_instance(cur, thread_t, th_link);
[ae318d3]371
[7509ddc]372 spinlock_lock(&thr->lock);
373 thr->interrupted = true;
374 if (thr->state == Sleeping)
375 sleeping = true;
376 spinlock_unlock(&thr->lock);
377
378 if (sleeping)
[5573942]379 waitq_interrupt_sleep(thr);
[7509ddc]380 }
[34dcd3f]381 spinlock_unlock(&ta->lock);
382 interrupts_restore(ipl);
[7509ddc]383
384 return 0;
385}
386
[b76a2217]387static bool task_print_walker(avltree_node_t *node, void *arg)
388{
389 task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
390 int j;
391
392 spinlock_lock(&t->lock);
393
394 uint64_t cycles;
395 char suffix;
396 order(task_get_accounting(t), &cycles, &suffix);
[52755f1]397
398#ifdef __32_BITS__
[0f94c3d]399 printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %10p %10p %9" PRIu64
[8605b24]400 "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
401 suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
[52755f1]402#endif
403
404#ifdef __64_BITS__
[0f94c3d]405 printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %18p %18p %9" PRIu64
[8605b24]406 "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
407 suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
[52755f1]408#endif
409
[b76a2217]410 for (j = 0; j < IPC_MAX_PHONES; j++) {
411 if (t->phones[j].callee)
[52755f1]412 printf(" %d:%p", j, t->phones[j].callee);
[b76a2217]413 }
414 printf("\n");
415
416 spinlock_unlock(&t->lock);
417 return true;
418}
419
[37c57f2]420/** Print task list */
421void task_print_list(void)
422{
423 ipl_t ipl;
424
[f74bbaf]425 /* Messing with task structures, avoid deadlock */
[37c57f2]426 ipl = interrupts_disable();
427 spinlock_lock(&tasks_lock);
[52755f1]428
429#ifdef __32_BITS__
430 printf("taskid name ctx address as "
[8605b24]431 "cycles threads calls callee\n");
[0f94c3d]432 printf("------ ------------ --- ---------- ---------- "
[8605b24]433 "---------- ------- ------ ------>\n");
[52755f1]434#endif
435
436#ifdef __64_BITS__
437 printf("taskid name ctx address as "
[8605b24]438 "cycles threads calls callee\n");
[0f94c3d]439 printf("------ ------------ --- ------------------ ------------------ "
[8605b24]440 "---------- ------- ------ ------>\n");
[52755f1]441#endif
[37c57f2]442
[b76a2217]443 avltree_walk(&tasks_tree, task_print_walker, NULL);
[37c57f2]444
445 spinlock_unlock(&tasks_lock);
446 interrupts_restore(ipl);
447}
[7509ddc]448
[cc73a8a1]449/** @}
[b45c443]450 */
Note: See TracBrowser for help on using the repository browser.