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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dd20cbb was 9e87562, checked in by Jakub Jermar <jakub@…>, 8 years ago

Make all accesses to capabilites exclusive

This commit makes sure that all accesses to the capabilities array and other
metadata are protected by a mutex. This is necessary for future resizing of the
capabilities array.

Group task's capabilities by type so that it is possible to visit all
capabilities of the given type effectively.

Provide cap_publish() and cap_unpublish() to automate steps that make the
capability visible/invisible to userspace and insert/remove the capability from
the respective type list.

  • Property mode set to 100644
File size: 15.0 KB
RevLine 
[f761f1eb]1/*
[278b4a30]2 * Copyright (c) 2010 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
[5ba201d]35 * @brief Task management.
[9179d0a]36 */
37
[63e27ef]38#include <assert.h>
[f761f1eb]39#include <proc/thread.h>
40#include <proc/task.h>
[20d50a1]41#include <mm/as.h>
[085d973]42#include <mm/slab.h>
[31d8e10]43#include <atomic.h>
[669f3d32]44#include <synch/futex.h>
[f761f1eb]45#include <synch/spinlock.h>
[5573942]46#include <synch/waitq.h>
[f761f1eb]47#include <arch.h>
[8605b24]48#include <arch/barrier.h>
[b76a2217]49#include <adt/avl.h>
[7f6e755]50#include <adt/btree.h>
[5c9a08b]51#include <adt/list.h>
[3f74275]52#include <cap/cap.h>
[6d9c49a]53#include <ipc/ipc.h>
[c98e6ee]54#include <ipc/ipcrsc.h>
[5d0500c]55#include <ipc/event.h>
[37c57f2]56#include <print.h>
[7509ddc]57#include <errno.h>
[95155b0c]58#include <func.h>
[19f857a]59#include <str.h>
[e3c762cd]60#include <syscall/copy.h>
[95ad426]61#include <macros.h>
[8e5e78f]62
[b76a2217]63/** Spinlock protecting the tasks_tree AVL tree. */
[da1bafb]64IRQ_SPINLOCK_INITIALIZE(tasks_lock);
[88169d9]65
[b76a2217]66/** AVL tree of active tasks.
[88169d9]67 *
[b76a2217]68 * The task is guaranteed to exist after it was found in the tasks_tree as
[6f4495f5]69 * long as:
[5ba201d]70 *
[88169d9]71 * @li the tasks_lock is held,
[6f4495f5]72 * @li the task's lock is held when task's lock is acquired before releasing
73 * tasks_lock or
[7bb6b06]74 * @li the task's refcount is greater than 0
[88169d9]75 *
76 */
[b76a2217]77avltree_t tasks_tree;
[88169d9]78
[286e03d]79static task_id_t task_counter = 0;
[70527f1]80
[103de761]81static slab_cache_t *task_slab;
82
[121966e]83/* Forward declarations. */
84static void task_kill_internal(task_t *);
[da1bafb]85static int tsk_constructor(void *, unsigned int);
[49115ac]86static size_t tsk_destructor(void *obj);
[121966e]87
[da1bafb]88/** Initialize kernel tasks support.
89 *
90 */
[f761f1eb]91void task_init(void)
92{
[43114c5]93 TASK = NULL;
[b76a2217]94 avltree_create(&tasks_tree);
[f97f1e51]95 task_slab = slab_cache_create("task_t", sizeof(task_t), 0,
[49115ac]96 tsk_constructor, tsk_destructor, 0);
[b76a2217]97}
98
[da1bafb]99/** Task finish walker.
100 *
[121966e]101 * The idea behind this walker is to kill and count all tasks different from
[814c4f5]102 * TASK.
[da1bafb]103 *
[b76a2217]104 */
105static bool task_done_walker(avltree_node_t *node, void *arg)
106{
[da1bafb]107 task_t *task = avltree_get_instance(node, task_t, tasks_tree_node);
108 size_t *cnt = (size_t *) arg;
[5ba201d]109
[da1bafb]110 if (task != TASK) {
[121966e]111 (*cnt)++;
[da1bafb]112
[121966e]113#ifdef CONFIG_DEBUG
[da1bafb]114 printf("[%"PRIu64"] ", task->taskid);
[121966e]115#endif
[da1bafb]116
117 task_kill_internal(task);
[b76a2217]118 }
[5ba201d]119
120 /* Continue the walk */
121 return true;
[f761f1eb]122}
123
[da1bafb]124/** Kill all tasks except the current task.
125 *
126 */
[f74bbaf]127void task_done(void)
128{
[da1bafb]129 size_t tasks_left;
[2f2beb4]130
131 if (ipc_phone_0) {
132 task_t *task_0 = ipc_phone_0->task;
133 ipc_phone_0 = NULL;
134 /*
135 * The first task is held by kinit(), we need to release it or
136 * it will never finish cleanup.
137 */
138 task_release(task_0);
139 }
[5ba201d]140
[da1bafb]141 /* Repeat until there are any tasks except TASK */
142 do {
[121966e]143#ifdef CONFIG_DEBUG
144 printf("Killing tasks... ");
145#endif
[da1bafb]146
147 irq_spinlock_lock(&tasks_lock, true);
[121966e]148 tasks_left = 0;
149 avltree_walk(&tasks_tree, task_done_walker, &tasks_left);
[da1bafb]150 irq_spinlock_unlock(&tasks_lock, true);
151
[121966e]152 thread_sleep(1);
[da1bafb]153
[f74bbaf]154#ifdef CONFIG_DEBUG
[121966e]155 printf("\n");
156#endif
[da1bafb]157 } while (tasks_left > 0);
[f74bbaf]158}
[70527f1]159
[da1bafb]160int tsk_constructor(void *obj, unsigned int kmflags)
[59ee56f]161{
[da1bafb]162 task_t *task = (task_t *) obj;
163
164 atomic_set(&task->refcount, 0);
165 atomic_set(&task->lifecount, 0);
[5ba201d]166
[da1bafb]167 irq_spinlock_initialize(&task->lock, "task_t_lock");
[5ba201d]168
[55b77d9]169 list_initialize(&task->threads);
[e7ac23d0]170
[3f74275]171 caps_task_alloc(task);
[5ba201d]172
[da1bafb]173 ipc_answerbox_init(&task->answerbox, task);
[5ba201d]174
[86939b1]175 spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
176 list_initialize(&task->active_calls);
[3ac5086]177
[59ee56f]178#ifdef CONFIG_UDEBUG
179 /* Init kbox stuff */
[da1bafb]180 task->kb.thread = NULL;
181 ipc_answerbox_init(&task->kb.box, task);
182 mutex_initialize(&task->kb.cleanup_lock, MUTEX_PASSIVE);
[59ee56f]183#endif
[5ba201d]184
[59ee56f]185 return 0;
186}
187
[49115ac]188size_t tsk_destructor(void *obj)
189{
190 task_t *task = (task_t *) obj;
191
[3f74275]192 caps_task_free(task);
[49115ac]193 return 0;
194}
195
[814c4f5]196/** Create new task with no threads.
[70527f1]197 *
[5ba201d]198 * @param as Task's address space.
199 * @param name Symbolic name (a copy is made).
[70527f1]200 *
[5ba201d]201 * @return New task's structure.
[70527f1]202 *
203 */
[a000878c]204task_t *task_create(as_t *as, const char *name)
[f761f1eb]205{
[da1bafb]206 task_t *task = (task_t *) slab_alloc(task_slab, 0);
207 task_create_arch(task);
208
209 task->as = as;
210 str_cpy(task->name, TASK_NAME_BUFLEN, name);
211
[473d5d2]212 task->container = CONTAINER;
[719a208]213 task->perms = 0;
[da1bafb]214 task->ucycles = 0;
215 task->kcycles = 0;
[7ad17de]216
[3f74275]217 caps_task_init(task);
[e9d15d9]218
[da1bafb]219 task->ipc_info.call_sent = 0;
[be06914]220 task->ipc_info.call_received = 0;
[da1bafb]221 task->ipc_info.answer_sent = 0;
[be06914]222 task->ipc_info.answer_received = 0;
223 task->ipc_info.irq_notif_received = 0;
[da1bafb]224 task->ipc_info.forwarded = 0;
[5d0500c]225
226 event_task_init(task);
[da1bafb]227
[c33f39f]228 task->answerbox.active = true;
229
[9a1b20c]230#ifdef CONFIG_UDEBUG
231 /* Init debugging stuff */
[da1bafb]232 udebug_task_init(&task->udebug);
[5ba201d]233
[9a1b20c]234 /* Init kbox stuff */
[c33f39f]235 task->kb.box.active = true;
[da1bafb]236 task->kb.finished = false;
[9a1b20c]237#endif
[5ba201d]238
[59ee56f]239 if ((ipc_phone_0) &&
[05ffb41]240 (container_check(ipc_phone_0->task->container, task->container))) {
241 int cap = phone_alloc(task);
242 assert(cap == 0);
243 (void) ipc_phone_connect(phone_get(task, 0), ipc_phone_0);
244 }
[5ba201d]245
[669f3d32]246 futex_task_init(task);
[bb68433]247
[6193351]248 /*
249 * Get a reference to the address space.
250 */
[da1bafb]251 as_hold(task->as);
252
253 irq_spinlock_lock(&tasks_lock, true);
254
255 task->taskid = ++task_counter;
256 avltree_node_initialize(&task->tasks_tree_node);
257 task->tasks_tree_node.key = task->taskid;
258 avltree_insert(&tasks_tree, &task->tasks_tree_node);
259
260 irq_spinlock_unlock(&tasks_lock, true);
261
262 return task;
[f761f1eb]263}
264
[7509ddc]265/** Destroy task.
266 *
[da1bafb]267 * @param task Task to be destroyed.
[5ba201d]268 *
[7509ddc]269 */
[da1bafb]270void task_destroy(task_t *task)
[7509ddc]271{
[ea7890e7]272 /*
273 * Remove the task from the task B+tree.
274 */
[da1bafb]275 irq_spinlock_lock(&tasks_lock, true);
276 avltree_delete(&tasks_tree, &task->tasks_tree_node);
277 irq_spinlock_unlock(&tasks_lock, true);
[5ba201d]278
[ea7890e7]279 /*
280 * Perform architecture specific task destruction.
281 */
[da1bafb]282 task_destroy_arch(task);
[5ba201d]283
[ea7890e7]284 /*
285 * Free up dynamically allocated state.
286 */
[669f3d32]287 futex_task_deinit(task);
[5ba201d]288
[ea7890e7]289 /*
290 * Drop our reference to the address space.
291 */
[da1bafb]292 as_release(task->as);
[31e8ddd]293
[da1bafb]294 slab_free(task_slab, task);
[7509ddc]295}
296
[278b4a30]297/** Hold a reference to a task.
298 *
299 * Holding a reference to a task prevents destruction of that task.
300 *
[da1bafb]301 * @param task Task to be held.
302 *
[278b4a30]303 */
[da1bafb]304void task_hold(task_t *task)
[278b4a30]305{
[da1bafb]306 atomic_inc(&task->refcount);
[278b4a30]307}
308
309/** Release a reference to a task.
310 *
311 * The last one to release a reference to a task destroys the task.
312 *
[da1bafb]313 * @param task Task to be released.
314 *
[278b4a30]315 */
[da1bafb]316void task_release(task_t *task)
[278b4a30]317{
[da1bafb]318 if ((atomic_predec(&task->refcount)) == 0)
319 task_destroy(task);
[278b4a30]320}
321
[dd8d5a7]322#ifdef __32_BITS__
323
324/** Syscall for reading task ID from userspace (32 bits)
[ec55358]325 *
[dd8d5a7]326 * @param uspace_taskid Pointer to user-space buffer
327 * where to store current task ID.
[5ba201d]328 *
329 * @return Zero on success or an error code from @ref errno.h.
[ec55358]330 *
331 */
[dd8d5a7]332sysarg_t sys_task_get_id(sysarg64_t *uspace_taskid)
[ec55358]333{
334 /*
[814c4f5]335 * No need to acquire lock on TASK because taskid remains constant for
336 * the lifespan of the task.
[ec55358]337 */
[dd8d5a7]338 return (sysarg_t) copy_to_uspace(uspace_taskid, &TASK->taskid,
[6f4495f5]339 sizeof(TASK->taskid));
[ec55358]340}
341
[dd8d5a7]342#endif /* __32_BITS__ */
343
344#ifdef __64_BITS__
345
346/** Syscall for reading task ID from userspace (64 bits)
347 *
348 * @return Current task ID.
349 *
350 */
351sysarg_t sys_task_get_id(void)
352{
353 /*
354 * No need to acquire lock on TASK because taskid remains constant for
355 * the lifespan of the task.
356 */
357 return TASK->taskid;
358}
359
360#endif /* __64_BITS__ */
361
[bc18d63]362/** Syscall for setting the task name.
363 *
364 * The name simplifies identifying the task in the task list.
365 *
[5ba201d]366 * @param name The new name for the task. (typically the same
367 * as the command used to execute it).
[bc18d63]368 *
369 * @return 0 on success or an error code from @ref errno.h.
[5ba201d]370 *
[bc18d63]371 */
[96b02eb9]372sysarg_t sys_task_set_name(const char *uspace_name, size_t name_len)
[bc18d63]373{
374 char namebuf[TASK_NAME_BUFLEN];
[5ba201d]375
[bc18d63]376 /* Cap length of name and copy it from userspace. */
377 if (name_len > TASK_NAME_BUFLEN - 1)
378 name_len = TASK_NAME_BUFLEN - 1;
[5ba201d]379
[577f042a]380 int rc = copy_from_uspace(namebuf, uspace_name, name_len);
[bc18d63]381 if (rc != 0)
[96b02eb9]382 return (sysarg_t) rc;
[5ba201d]383
[f4b1535]384 namebuf[name_len] = '\0';
[577f042a]385
386 /*
387 * As the task name is referenced also from the
388 * threads, lock the threads' lock for the course
389 * of the update.
390 */
391
392 irq_spinlock_lock(&tasks_lock, true);
393 irq_spinlock_lock(&TASK->lock, false);
394 irq_spinlock_lock(&threads_lock, false);
395
396 /* Set task name */
[f4b1535]397 str_cpy(TASK->name, TASK_NAME_BUFLEN, namebuf);
[5ba201d]398
[577f042a]399 irq_spinlock_unlock(&threads_lock, false);
400 irq_spinlock_unlock(&TASK->lock, false);
401 irq_spinlock_unlock(&tasks_lock, true);
402
[bc18d63]403 return EOK;
404}
405
[1e9f8ab]406/** Syscall to forcefully terminate a task
407 *
408 * @param uspace_taskid Pointer to task ID in user space.
409 *
410 * @return 0 on success or an error code from @ref errno.h.
411 *
412 */
413sysarg_t sys_task_kill(task_id_t *uspace_taskid)
414{
415 task_id_t taskid;
[5bcf1f9]416 int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(taskid));
[1e9f8ab]417 if (rc != 0)
418 return (sysarg_t) rc;
[5bcf1f9]419
[1e9f8ab]420 return (sysarg_t) task_kill(taskid);
421}
422
[9a8d91b]423/** Find task structure corresponding to task ID.
424 *
[814c4f5]425 * The tasks_lock must be already held by the caller of this function and
426 * interrupts must be disabled.
[9a8d91b]427 *
[5ba201d]428 * @param id Task ID.
429 *
[e1b6742]430 * @return Task structure address or NULL if there is no such task ID.
[9a8d91b]431 *
432 */
[5ba201d]433task_t *task_find_by_id(task_id_t id)
434{
[63e27ef]435 assert(interrupts_disabled());
436 assert(irq_spinlock_locked(&tasks_lock));
[1d432f9]437
[e1b6742]438 avltree_node_t *node =
439 avltree_search(&tasks_tree, (avltree_key_t) id);
[5ba201d]440
[b76a2217]441 if (node)
[da1bafb]442 return avltree_get_instance(node, task_t, tasks_tree_node);
[5ba201d]443
[b76a2217]444 return NULL;
[9a8d91b]445}
446
[0313ff0]447/** Get accounting data of given task.
448 *
[1d432f9]449 * Note that task lock of 'task' must be already held and interrupts must be
[814c4f5]450 * already disabled.
[0313ff0]451 *
[da1bafb]452 * @param task Pointer to the task.
[88dea9d]453 * @param ucycles Out pointer to sum of all user cycles.
454 * @param kcycles Out pointer to sum of all kernel cycles.
[0313ff0]455 *
456 */
[da1bafb]457void task_get_accounting(task_t *task, uint64_t *ucycles, uint64_t *kcycles)
[0313ff0]458{
[63e27ef]459 assert(interrupts_disabled());
460 assert(irq_spinlock_locked(&task->lock));
[1d432f9]461
[a2a00e8]462 /* Accumulated values of task */
[da1bafb]463 uint64_t uret = task->ucycles;
464 uint64_t kret = task->kcycles;
[0313ff0]465
466 /* Current values of threads */
[feeac0d]467 list_foreach(task->threads, th_link, thread_t, thread) {
[da1bafb]468 irq_spinlock_lock(&thread->lock, false);
[0313ff0]469
[62b6d17]470 /* Process only counted threads */
[da1bafb]471 if (!thread->uncounted) {
472 if (thread == THREAD) {
[6f4495f5]473 /* Update accounting of current thread */
[a2a00e8]474 thread_update_accounting(false);
[da1bafb]475 }
476
477 uret += thread->ucycles;
478 kret += thread->kcycles;
[62b6d17]479 }
[da1bafb]480
481 irq_spinlock_unlock(&thread->lock, false);
[0313ff0]482 }
483
[a2a00e8]484 *ucycles = uret;
485 *kcycles = kret;
[0313ff0]486}
487
[da1bafb]488static void task_kill_internal(task_t *task)
[121966e]489{
[df58e44]490 irq_spinlock_lock(&task->lock, false);
491 irq_spinlock_lock(&threads_lock, false);
[5ba201d]492
[121966e]493 /*
494 * Interrupt all threads.
495 */
[df58e44]496
[feeac0d]497 list_foreach(task->threads, th_link, thread_t, thread) {
[121966e]498 bool sleeping = false;
499
[da1bafb]500 irq_spinlock_lock(&thread->lock, false);
[121966e]501
[da1bafb]502 thread->interrupted = true;
503 if (thread->state == Sleeping)
[121966e]504 sleeping = true;
[da1bafb]505
506 irq_spinlock_unlock(&thread->lock, false);
[121966e]507
508 if (sleeping)
[da1bafb]509 waitq_interrupt_sleep(thread);
[121966e]510 }
[da1bafb]511
[df58e44]512 irq_spinlock_unlock(&threads_lock, false);
[da1bafb]513 irq_spinlock_unlock(&task->lock, false);
[121966e]514}
515
[7509ddc]516/** Kill task.
[ea7890e7]517 *
518 * This function is idempotent.
519 * It signals all the task's threads to bail it out.
[7509ddc]520 *
[5ba201d]521 * @param id ID of the task to be killed.
522 *
523 * @return Zero on success or an error code from errno.h.
[7509ddc]524 *
525 */
526int task_kill(task_id_t id)
527{
[9b6aae6]528 if (id == 1)
529 return EPERM;
[7509ddc]530
[da1bafb]531 irq_spinlock_lock(&tasks_lock, true);
532
533 task_t *task = task_find_by_id(id);
534 if (!task) {
535 irq_spinlock_unlock(&tasks_lock, true);
[7509ddc]536 return ENOENT;
537 }
[da1bafb]538
539 task_kill_internal(task);
540 irq_spinlock_unlock(&tasks_lock, true);
541
542 return EOK;
[7509ddc]543}
544
[5bcf1f9]545/** Kill the currently running task.
546 *
547 * @param notify Send out fault notifications.
548 *
549 * @return Zero on success or an error code from errno.h.
550 *
551 */
552void task_kill_self(bool notify)
553{
554 /*
555 * User space can subscribe for FAULT events to take action
556 * whenever a task faults (to take a dump, run a debugger, etc.).
557 * The notification is always available, but unless udebug is enabled,
558 * that's all you get.
559 */
560 if (notify) {
[f9061b4]561 /* Notify the subscriber that a fault occurred. */
562 if (event_notify_3(EVENT_FAULT, false, LOWER32(TASK->taskid),
563 UPPER32(TASK->taskid), (sysarg_t) THREAD) == EOK) {
[5bcf1f9]564#ifdef CONFIG_UDEBUG
565 /* Wait for a debugging session. */
566 udebug_thread_fault();
567#endif
568 }
569 }
570
571 irq_spinlock_lock(&tasks_lock, true);
572 task_kill_internal(TASK);
573 irq_spinlock_unlock(&tasks_lock, true);
574
575 thread_exit();
576}
577
578/** Process syscall to terminate the current task.
579 *
580 * @param notify Send out fault notifications.
581 *
582 */
583sysarg_t sys_task_exit(sysarg_t notify)
584{
585 task_kill_self(notify);
586
587 /* Unreachable */
588 return EOK;
589}
590
[b76a2217]591static bool task_print_walker(avltree_node_t *node, void *arg)
592{
[c0f13d2]593 bool *additional = (bool *) arg;
[da1bafb]594 task_t *task = avltree_get_instance(node, task_t, tasks_tree_node);
595 irq_spinlock_lock(&task->lock, false);
[5ba201d]596
[a2a00e8]597 uint64_t ucycles;
598 uint64_t kcycles;
[1ba37fa]599 char usuffix, ksuffix;
[da1bafb]600 task_get_accounting(task, &ucycles, &kcycles);
[e535eeb]601 order_suffix(ucycles, &ucycles, &usuffix);
602 order_suffix(kcycles, &kcycles, &ksuffix);
[88dea9d]603
[da1bafb]604#ifdef __32_BITS__
[c0f13d2]605 if (*additional)
[97d17fe]606 printf("%-8" PRIu64 " %9" PRIua, task->taskid,
607 atomic_get(&task->refcount));
[c0f13d2]608 else
609 printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %10p %10p"
610 " %9" PRIu64 "%c %9" PRIu64 "%c\n", task->taskid,
[473d5d2]611 task->name, task->container, task, task->as,
[c0f13d2]612 ucycles, usuffix, kcycles, ksuffix);
[52755f1]613#endif
[5ba201d]614
[52755f1]615#ifdef __64_BITS__
[c0f13d2]616 if (*additional)
[7e752b2]617 printf("%-8" PRIu64 " %9" PRIu64 "%c %9" PRIu64 "%c "
[9e87562]618 "%9" PRIua "\n", task->taskid, ucycles, usuffix, kcycles,
[97d17fe]619 ksuffix, atomic_get(&task->refcount));
[c0f13d2]620 else
621 printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %18p %18p\n",
[473d5d2]622 task->taskid, task->name, task->container, task, task->as);
[52755f1]623#endif
[5ba201d]624
[da1bafb]625 irq_spinlock_unlock(&task->lock, false);
[b76a2217]626 return true;
627}
628
[c0f13d2]629/** Print task list
630 *
631 * @param additional Print additional information.
632 *
633 */
634void task_print_list(bool additional)
[37c57f2]635{
[f74bbaf]636 /* Messing with task structures, avoid deadlock */
[da1bafb]637 irq_spinlock_lock(&tasks_lock, true);
[5ba201d]638
639#ifdef __32_BITS__
[c0f13d2]640 if (additional)
[48dcc69]641 printf("[id ] [threads] [calls] [callee\n");
[c0f13d2]642 else
[473d5d2]643 printf("[id ] [name ] [ctn] [address ] [as ]"
[c0f13d2]644 " [ucycles ] [kcycles ]\n");
[52755f1]645#endif
[5ba201d]646
[52755f1]647#ifdef __64_BITS__
[c0f13d2]648 if (additional)
[be06914]649 printf("[id ] [ucycles ] [kcycles ] [threads] [calls]"
[c0f13d2]650 " [callee\n");
651 else
[473d5d2]652 printf("[id ] [name ] [ctn] [address ]"
[c0f13d2]653 " [as ]\n");
[52755f1]654#endif
[5ba201d]655
[c0f13d2]656 avltree_walk(&tasks_tree, task_print_walker, &additional);
[5ba201d]657
[da1bafb]658 irq_spinlock_unlock(&tasks_lock, true);
[37c57f2]659}
[7509ddc]660
[cc73a8a1]661/** @}
[b45c443]662 */
Note: See TracBrowser for help on using the repository browser.