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

Last change on this file since d89b259 was 5a5269d, checked in by GitHub <noreply@…>, 6 years ago

Change type of uspace pointers in kernel from pointer type to numeric (#170)

From kernel's perspective, userspace addresses are not valid pointers,
and can only be used in calls to copy_to/from_uspace().
Therefore, we change the type of those arguments and variables to
uspace_addr_t which is an alias for sysarg_t.

This allows the compiler to catch accidental direct accesses to
userspace addresses.

Additionally, to avoid losing the type information in code,
a macro uspace_ptr(type) is used that translates to uspace_addr_t.
I makes no functional difference, but allows keeping the type information
in code in case we implement some sort of static checking for it in the future.

However, ccheck doesn't like that, so instead of using uspace_ptr(char),
we use uspace_ptr_char which is defined as
#define uspace_ptr_char uspace_ptr(char).

  • Property mode set to 100644
File size: 16.5 KB
RevLine 
[f761f1eb]1/*
[278b4a30]2 * Copyright (c) 2010 Jakub Jermar
[ef1eab7]3 * Copyright (c) 2018 Jiri Svoboda
[f761f1eb]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[174156fd]30/** @addtogroup kernel_generic_proc
[b45c443]31 * @{
32 */
33
[9179d0a]34/**
[b45c443]35 * @file
[5ba201d]36 * @brief Task management.
[9179d0a]37 */
38
[63e27ef]39#include <assert.h>
[f761f1eb]40#include <proc/thread.h>
41#include <proc/task.h>
[20d50a1]42#include <mm/as.h>
[085d973]43#include <mm/slab.h>
[31d8e10]44#include <atomic.h>
[f761f1eb]45#include <synch/spinlock.h>
[5573942]46#include <synch/waitq.h>
[f761f1eb]47#include <arch.h>
[05882233]48#include <barrier.h>
[5c9a08b]49#include <adt/list.h>
[ef1eab7]50#include <adt/odict.h>
[3f74275]51#include <cap/cap.h>
[6d9c49a]52#include <ipc/ipc.h>
[c98e6ee]53#include <ipc/ipcrsc.h>
[5d0500c]54#include <ipc/event.h>
[bab75df6]55#include <stdio.h>
[7509ddc]56#include <errno.h>
[b2e121a]57#include <halt.h>
[19f857a]58#include <str.h>
[e3c762cd]59#include <syscall/copy.h>
[95ad426]60#include <macros.h>
[8e5e78f]61
[ef1eab7]62/** Spinlock protecting the @c tasks ordered dictionary. */
[da1bafb]63IRQ_SPINLOCK_INITIALIZE(tasks_lock);
[88169d9]64
[88cc71c0]65/** Ordered dictionary of active tasks by task ID.
66 *
67 * Members are task_t structures.
[88169d9]68 *
[ef1eab7]69 * The task is guaranteed to exist after it was found in the @c tasks
70 * dictionary as long as:
[5ba201d]71 *
[88169d9]72 * @li the tasks_lock is held,
[6f4495f5]73 * @li the task's lock is held when task's lock is acquired before releasing
74 * tasks_lock or
[7bb6b06]75 * @li the task's refcount is greater than 0
[88169d9]76 *
77 */
[ef1eab7]78odict_t tasks;
[88169d9]79
[286e03d]80static task_id_t task_counter = 0;
[70527f1]81
[82d515e9]82static slab_cache_t *task_cache;
[103de761]83
[121966e]84/* Forward declarations. */
85static void task_kill_internal(task_t *);
[b7fd2a0]86static errno_t tsk_constructor(void *, unsigned int);
[ef1eab7]87static size_t tsk_destructor(void *);
88
89static void *tasks_getkey(odlink_t *);
90static int tasks_cmp(void *, void *);
[121966e]91
[da1bafb]92/** Initialize kernel tasks support.
93 *
94 */
[f761f1eb]95void task_init(void)
96{
[43114c5]97 TASK = NULL;
[ef1eab7]98 odict_initialize(&tasks, tasks_getkey, tasks_cmp);
[82d515e9]99 task_cache = slab_cache_create("task_t", sizeof(task_t), 0,
[49115ac]100 tsk_constructor, tsk_destructor, 0);
[b76a2217]101}
102
[da1bafb]103/** Kill all tasks except the current task.
104 *
105 */
[f74bbaf]106void task_done(void)
107{
[da1bafb]108 size_t tasks_left;
[ef1eab7]109 task_t *task;
[2f2beb4]110
[cdc4334]111 if (ipc_box_0) {
112 task_t *task_0 = ipc_box_0->task;
113 ipc_box_0 = NULL;
[2f2beb4]114 /*
115 * The first task is held by kinit(), we need to release it or
116 * it will never finish cleanup.
117 */
118 task_release(task_0);
119 }
[a35b458]120
[da1bafb]121 /* Repeat until there are any tasks except TASK */
122 do {
[121966e]123#ifdef CONFIG_DEBUG
124 printf("Killing tasks... ");
125#endif
[da1bafb]126 irq_spinlock_lock(&tasks_lock, true);
[121966e]127 tasks_left = 0;
[ef1eab7]128
[aab5e46]129 task = task_first();
130 while (task != NULL) {
[ef1eab7]131 if (task != TASK) {
132 tasks_left++;
133#ifdef CONFIG_DEBUG
134 printf("[%" PRIu64 "] ", task->taskid);
135#endif
136 task_kill_internal(task);
137 }
138
[aab5e46]139 task = task_next(task);
[ef1eab7]140 }
141
[da1bafb]142 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]143
[121966e]144 thread_sleep(1);
[a35b458]145
[f74bbaf]146#ifdef CONFIG_DEBUG
[121966e]147 printf("\n");
148#endif
[da1bafb]149 } while (tasks_left > 0);
[f74bbaf]150}
[70527f1]151
[b7fd2a0]152errno_t tsk_constructor(void *obj, unsigned int kmflags)
[59ee56f]153{
[da1bafb]154 task_t *task = (task_t *) obj;
[c46bfbc]155
[b7fd2a0]156 errno_t rc = caps_task_alloc(task);
[c46bfbc]157 if (rc != EOK)
158 return rc;
[a35b458]159
[e3306d04]160 atomic_store(&task->refcount, 0);
161 atomic_store(&task->lifecount, 0);
[a35b458]162
[da1bafb]163 irq_spinlock_initialize(&task->lock, "task_t_lock");
[a35b458]164
[55b77d9]165 list_initialize(&task->threads);
[a35b458]166
[da1bafb]167 ipc_answerbox_init(&task->answerbox, task);
[a35b458]168
[86939b1]169 spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
170 list_initialize(&task->active_calls);
[a35b458]171
[59ee56f]172#ifdef CONFIG_UDEBUG
173 /* Init kbox stuff */
[da1bafb]174 task->kb.thread = NULL;
175 ipc_answerbox_init(&task->kb.box, task);
176 mutex_initialize(&task->kb.cleanup_lock, MUTEX_PASSIVE);
[59ee56f]177#endif
[a35b458]178
[7f11dc6]179 return EOK;
[59ee56f]180}
181
[49115ac]182size_t tsk_destructor(void *obj)
183{
184 task_t *task = (task_t *) obj;
[a35b458]185
[3f74275]186 caps_task_free(task);
[49115ac]187 return 0;
188}
189
[814c4f5]190/** Create new task with no threads.
[70527f1]191 *
[5ba201d]192 * @param as Task's address space.
193 * @param name Symbolic name (a copy is made).
[70527f1]194 *
[5ba201d]195 * @return New task's structure.
[70527f1]196 *
197 */
[a000878c]198task_t *task_create(as_t *as, const char *name)
[f761f1eb]199{
[abf6c01]200 task_t *task = (task_t *) slab_alloc(task_cache, FRAME_ATOMIC);
201 if (!task)
[6a32cc5f]202 return NULL;
[a35b458]203
[da1bafb]204 task_create_arch(task);
[a35b458]205
[da1bafb]206 task->as = as;
207 str_cpy(task->name, TASK_NAME_BUFLEN, name);
[a35b458]208
[473d5d2]209 task->container = CONTAINER;
[719a208]210 task->perms = 0;
[da1bafb]211 task->ucycles = 0;
212 task->kcycles = 0;
[7ad17de]213
[3f74275]214 caps_task_init(task);
[e9d15d9]215
[da1bafb]216 task->ipc_info.call_sent = 0;
[be06914]217 task->ipc_info.call_received = 0;
[da1bafb]218 task->ipc_info.answer_sent = 0;
[be06914]219 task->ipc_info.answer_received = 0;
220 task->ipc_info.irq_notif_received = 0;
[da1bafb]221 task->ipc_info.forwarded = 0;
[5d0500c]222
223 event_task_init(task);
[a35b458]224
[c33f39f]225 task->answerbox.active = true;
226
[9a1b20c]227#ifdef CONFIG_UDEBUG
228 /* Init debugging stuff */
[da1bafb]229 udebug_task_init(&task->udebug);
[a35b458]230
[9a1b20c]231 /* Init kbox stuff */
[c33f39f]232 task->kb.box.active = true;
[da1bafb]233 task->kb.finished = false;
[9a1b20c]234#endif
[a35b458]235
[cdc4334]236 if ((ipc_box_0) &&
237 (container_check(ipc_box_0->task->container, task->container))) {
[eadaeae8]238 cap_phone_handle_t phone_handle;
[334c103]239 errno_t rc = phone_alloc(task, true, &phone_handle, NULL);
[09d01f2]240 if (rc != EOK) {
[6a32cc5f]241 task->as = NULL;
242 task_destroy_arch(task);
243 slab_free(task_cache, task);
244 return NULL;
245 }
[a35b458]246
[48bcf49]247 kobject_t *phone_obj = kobject_get(task, phone_handle,
248 KOBJECT_TYPE_PHONE);
[cdc4334]249 (void) ipc_phone_connect(phone_obj->phone, ipc_box_0);
[05ffb41]250 }
[a35b458]251
[da1bafb]252 irq_spinlock_lock(&tasks_lock, true);
[a35b458]253
[da1bafb]254 task->taskid = ++task_counter;
[ef1eab7]255 odlink_initialize(&task->ltasks);
256 odict_insert(&task->ltasks, &tasks, NULL);
[a35b458]257
[da1bafb]258 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]259
[da1bafb]260 return task;
[f761f1eb]261}
262
[7509ddc]263/** Destroy task.
264 *
[da1bafb]265 * @param task Task to be destroyed.
[5ba201d]266 *
[7509ddc]267 */
[da1bafb]268void task_destroy(task_t *task)
[7509ddc]269{
[ea7890e7]270 /*
[ca4c5596]271 * Remove the task from the task odict.
[ea7890e7]272 */
[da1bafb]273 irq_spinlock_lock(&tasks_lock, true);
[ef1eab7]274 odict_remove(&task->ltasks);
[da1bafb]275 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]276
[ea7890e7]277 /*
278 * Perform architecture specific task destruction.
279 */
[da1bafb]280 task_destroy_arch(task);
[a35b458]281
[ea7890e7]282 /*
283 * Drop our reference to the address space.
284 */
[da1bafb]285 as_release(task->as);
[a35b458]286
[82d515e9]287 slab_free(task_cache, task);
[7509ddc]288}
289
[278b4a30]290/** Hold a reference to a task.
291 *
292 * Holding a reference to a task prevents destruction of that task.
293 *
[da1bafb]294 * @param task Task to be held.
295 *
[278b4a30]296 */
[da1bafb]297void task_hold(task_t *task)
[278b4a30]298{
[da1bafb]299 atomic_inc(&task->refcount);
[278b4a30]300}
301
302/** Release a reference to a task.
303 *
304 * The last one to release a reference to a task destroys the task.
305 *
[da1bafb]306 * @param task Task to be released.
307 *
[278b4a30]308 */
[da1bafb]309void task_release(task_t *task)
[278b4a30]310{
[da1bafb]311 if ((atomic_predec(&task->refcount)) == 0)
312 task_destroy(task);
[278b4a30]313}
314
[dd8d5a7]315#ifdef __32_BITS__
316
317/** Syscall for reading task ID from userspace (32 bits)
[ec55358]318 *
[dd8d5a7]319 * @param uspace_taskid Pointer to user-space buffer
320 * where to store current task ID.
[5ba201d]321 *
322 * @return Zero on success or an error code from @ref errno.h.
[ec55358]323 *
324 */
[5a5269d]325sys_errno_t sys_task_get_id(uspace_ptr_sysarg64_t uspace_taskid)
[ec55358]326{
327 /*
[814c4f5]328 * No need to acquire lock on TASK because taskid remains constant for
329 * the lifespan of the task.
[ec55358]330 */
[b7fd2a0]331 return (sys_errno_t) copy_to_uspace(uspace_taskid, &TASK->taskid,
[6f4495f5]332 sizeof(TASK->taskid));
[ec55358]333}
334
[dd8d5a7]335#endif /* __32_BITS__ */
336
337#ifdef __64_BITS__
338
339/** Syscall for reading task ID from userspace (64 bits)
340 *
341 * @return Current task ID.
342 *
343 */
344sysarg_t sys_task_get_id(void)
345{
346 /*
347 * No need to acquire lock on TASK because taskid remains constant for
348 * the lifespan of the task.
349 */
350 return TASK->taskid;
351}
352
353#endif /* __64_BITS__ */
354
[bc18d63]355/** Syscall for setting the task name.
356 *
357 * The name simplifies identifying the task in the task list.
358 *
[5ba201d]359 * @param name The new name for the task. (typically the same
360 * as the command used to execute it).
[bc18d63]361 *
362 * @return 0 on success or an error code from @ref errno.h.
[5ba201d]363 *
[bc18d63]364 */
[5a5269d]365sys_errno_t sys_task_set_name(const uspace_ptr_char uspace_name, size_t name_len)
[bc18d63]366{
367 char namebuf[TASK_NAME_BUFLEN];
[a35b458]368
[bc18d63]369 /* Cap length of name and copy it from userspace. */
370 if (name_len > TASK_NAME_BUFLEN - 1)
371 name_len = TASK_NAME_BUFLEN - 1;
[a35b458]372
[b7fd2a0]373 errno_t rc = copy_from_uspace(namebuf, uspace_name, name_len);
[a53ed3a]374 if (rc != EOK)
[b7fd2a0]375 return (sys_errno_t) rc;
[a35b458]376
[f4b1535]377 namebuf[name_len] = '\0';
[a35b458]378
[577f042a]379 /*
380 * As the task name is referenced also from the
381 * threads, lock the threads' lock for the course
382 * of the update.
383 */
[a35b458]384
[577f042a]385 irq_spinlock_lock(&tasks_lock, true);
386 irq_spinlock_lock(&TASK->lock, false);
387 irq_spinlock_lock(&threads_lock, false);
[a35b458]388
[577f042a]389 /* Set task name */
[f4b1535]390 str_cpy(TASK->name, TASK_NAME_BUFLEN, namebuf);
[a35b458]391
[577f042a]392 irq_spinlock_unlock(&threads_lock, false);
393 irq_spinlock_unlock(&TASK->lock, false);
394 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]395
[bc18d63]396 return EOK;
397}
398
[1e9f8ab]399/** Syscall to forcefully terminate a task
400 *
401 * @param uspace_taskid Pointer to task ID in user space.
402 *
403 * @return 0 on success or an error code from @ref errno.h.
404 *
405 */
[5a5269d]406sys_errno_t sys_task_kill(uspace_ptr_task_id_t uspace_taskid)
[1e9f8ab]407{
408 task_id_t taskid;
[b7fd2a0]409 errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(taskid));
[a53ed3a]410 if (rc != EOK)
[b7fd2a0]411 return (sys_errno_t) rc;
[a35b458]412
[b7fd2a0]413 return (sys_errno_t) task_kill(taskid);
[1e9f8ab]414}
415
[9a8d91b]416/** Find task structure corresponding to task ID.
417 *
[814c4f5]418 * The tasks_lock must be already held by the caller of this function and
419 * interrupts must be disabled.
[9a8d91b]420 *
[5ba201d]421 * @param id Task ID.
422 *
[e1b6742]423 * @return Task structure address or NULL if there is no such task ID.
[9a8d91b]424 *
425 */
[5ba201d]426task_t *task_find_by_id(task_id_t id)
427{
[63e27ef]428 assert(interrupts_disabled());
429 assert(irq_spinlock_locked(&tasks_lock));
[1d432f9]430
[ef1eab7]431 odlink_t *odlink = odict_find_eq(&tasks, &id, NULL);
432 if (odlink != NULL)
433 return odict_get_instance(odlink, task_t, ltasks);
[a35b458]434
[b76a2217]435 return NULL;
[9a8d91b]436}
437
[aab5e46]438/** Get count of tasks.
439 *
440 * @return Number of tasks in the system
441 */
442size_t task_count(void)
443{
444 assert(interrupts_disabled());
445 assert(irq_spinlock_locked(&tasks_lock));
446
447 return odict_count(&tasks);
448}
449
450/** Get first task (task with lowest ID).
451 *
452 * @return Pointer to first task or @c NULL if there are none.
453 */
454task_t *task_first(void)
455{
456 odlink_t *odlink;
457
458 assert(interrupts_disabled());
459 assert(irq_spinlock_locked(&tasks_lock));
460
461 odlink = odict_first(&tasks);
462 if (odlink == NULL)
463 return NULL;
464
465 return odict_get_instance(odlink, task_t, ltasks);
466}
467
468/** Get next task (with higher task ID).
469 *
470 * @param cur Current task
471 * @return Pointer to next task or @c NULL if there are no more tasks.
472 */
473task_t *task_next(task_t *cur)
474{
475 odlink_t *odlink;
476
477 assert(interrupts_disabled());
478 assert(irq_spinlock_locked(&tasks_lock));
479
480 odlink = odict_next(&cur->ltasks, &tasks);
481 if (odlink == NULL)
482 return NULL;
483
484 return odict_get_instance(odlink, task_t, ltasks);
485}
486
[0313ff0]487/** Get accounting data of given task.
488 *
[1d432f9]489 * Note that task lock of 'task' must be already held and interrupts must be
[814c4f5]490 * already disabled.
[0313ff0]491 *
[da1bafb]492 * @param task Pointer to the task.
[88dea9d]493 * @param ucycles Out pointer to sum of all user cycles.
494 * @param kcycles Out pointer to sum of all kernel cycles.
[0313ff0]495 *
496 */
[da1bafb]497void task_get_accounting(task_t *task, uint64_t *ucycles, uint64_t *kcycles)
[0313ff0]498{
[63e27ef]499 assert(interrupts_disabled());
500 assert(irq_spinlock_locked(&task->lock));
[1d432f9]501
[a2a00e8]502 /* Accumulated values of task */
[da1bafb]503 uint64_t uret = task->ucycles;
504 uint64_t kret = task->kcycles;
[a35b458]505
[0313ff0]506 /* Current values of threads */
[feeac0d]507 list_foreach(task->threads, th_link, thread_t, thread) {
[da1bafb]508 irq_spinlock_lock(&thread->lock, false);
[a35b458]509
[62b6d17]510 /* Process only counted threads */
[da1bafb]511 if (!thread->uncounted) {
512 if (thread == THREAD) {
[6f4495f5]513 /* Update accounting of current thread */
[a2a00e8]514 thread_update_accounting(false);
[da1bafb]515 }
[a35b458]516
[da1bafb]517 uret += thread->ucycles;
518 kret += thread->kcycles;
[62b6d17]519 }
[a35b458]520
[da1bafb]521 irq_spinlock_unlock(&thread->lock, false);
[0313ff0]522 }
[a35b458]523
[a2a00e8]524 *ucycles = uret;
525 *kcycles = kret;
[0313ff0]526}
527
[da1bafb]528static void task_kill_internal(task_t *task)
[121966e]529{
[df58e44]530 irq_spinlock_lock(&task->lock, false);
531 irq_spinlock_lock(&threads_lock, false);
[a35b458]532
[121966e]533 /*
534 * Interrupt all threads.
535 */
[a35b458]536
[feeac0d]537 list_foreach(task->threads, th_link, thread_t, thread) {
[121966e]538 bool sleeping = false;
[a35b458]539
[da1bafb]540 irq_spinlock_lock(&thread->lock, false);
[a35b458]541
[da1bafb]542 thread->interrupted = true;
543 if (thread->state == Sleeping)
[121966e]544 sleeping = true;
[a35b458]545
[da1bafb]546 irq_spinlock_unlock(&thread->lock, false);
[a35b458]547
[121966e]548 if (sleeping)
[da1bafb]549 waitq_interrupt_sleep(thread);
[121966e]550 }
[a35b458]551
[df58e44]552 irq_spinlock_unlock(&threads_lock, false);
[da1bafb]553 irq_spinlock_unlock(&task->lock, false);
[121966e]554}
555
[7509ddc]556/** Kill task.
[ea7890e7]557 *
558 * This function is idempotent.
559 * It signals all the task's threads to bail it out.
[7509ddc]560 *
[5ba201d]561 * @param id ID of the task to be killed.
562 *
563 * @return Zero on success or an error code from errno.h.
[7509ddc]564 *
565 */
[b7fd2a0]566errno_t task_kill(task_id_t id)
[7509ddc]567{
[9b6aae6]568 if (id == 1)
569 return EPERM;
[a35b458]570
[da1bafb]571 irq_spinlock_lock(&tasks_lock, true);
[a35b458]572
[da1bafb]573 task_t *task = task_find_by_id(id);
574 if (!task) {
575 irq_spinlock_unlock(&tasks_lock, true);
[7509ddc]576 return ENOENT;
577 }
[a35b458]578
[da1bafb]579 task_kill_internal(task);
580 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]581
[da1bafb]582 return EOK;
[7509ddc]583}
584
[5bcf1f9]585/** Kill the currently running task.
586 *
587 * @param notify Send out fault notifications.
588 *
589 * @return Zero on success or an error code from errno.h.
590 *
591 */
592void task_kill_self(bool notify)
593{
594 /*
595 * User space can subscribe for FAULT events to take action
596 * whenever a task faults (to take a dump, run a debugger, etc.).
597 * The notification is always available, but unless udebug is enabled,
598 * that's all you get.
[ae7d03c]599 */
[5bcf1f9]600 if (notify) {
[f9061b4]601 /* Notify the subscriber that a fault occurred. */
602 if (event_notify_3(EVENT_FAULT, false, LOWER32(TASK->taskid),
603 UPPER32(TASK->taskid), (sysarg_t) THREAD) == EOK) {
[5bcf1f9]604#ifdef CONFIG_UDEBUG
605 /* Wait for a debugging session. */
606 udebug_thread_fault();
607#endif
608 }
609 }
[a35b458]610
[5bcf1f9]611 irq_spinlock_lock(&tasks_lock, true);
612 task_kill_internal(TASK);
613 irq_spinlock_unlock(&tasks_lock, true);
[a35b458]614
[5bcf1f9]615 thread_exit();
616}
617
618/** Process syscall to terminate the current task.
619 *
620 * @param notify Send out fault notifications.
621 *
622 */
[b7fd2a0]623sys_errno_t sys_task_exit(sysarg_t notify)
[5bcf1f9]624{
625 task_kill_self(notify);
[88e43bc]626 unreachable();
[5bcf1f9]627}
628
[ef1eab7]629static void task_print(task_t *task, bool additional)
[b76a2217]630{
[da1bafb]631 irq_spinlock_lock(&task->lock, false);
[a35b458]632
[a2a00e8]633 uint64_t ucycles;
634 uint64_t kcycles;
[1ba37fa]635 char usuffix, ksuffix;
[da1bafb]636 task_get_accounting(task, &ucycles, &kcycles);
[e535eeb]637 order_suffix(ucycles, &ucycles, &usuffix);
638 order_suffix(kcycles, &kcycles, &ksuffix);
[a35b458]639
[da1bafb]640#ifdef __32_BITS__
[ef1eab7]641 if (additional)
[077842c]642 printf("%-8" PRIu64 " %9zu", task->taskid,
[036e97c]643 atomic_load(&task->refcount));
[c0f13d2]644 else
645 printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %10p %10p"
646 " %9" PRIu64 "%c %9" PRIu64 "%c\n", task->taskid,
[473d5d2]647 task->name, task->container, task, task->as,
[c0f13d2]648 ucycles, usuffix, kcycles, ksuffix);
[52755f1]649#endif
[a35b458]650
[52755f1]651#ifdef __64_BITS__
[ef1eab7]652 if (additional)
[7e752b2]653 printf("%-8" PRIu64 " %9" PRIu64 "%c %9" PRIu64 "%c "
[077842c]654 "%9zu\n", task->taskid, ucycles, usuffix, kcycles,
[036e97c]655 ksuffix, atomic_load(&task->refcount));
[c0f13d2]656 else
657 printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %18p %18p\n",
[473d5d2]658 task->taskid, task->name, task->container, task, task->as);
[52755f1]659#endif
[a35b458]660
[da1bafb]661 irq_spinlock_unlock(&task->lock, false);
[b76a2217]662}
663
[c0f13d2]664/** Print task list
665 *
666 * @param additional Print additional information.
667 *
668 */
669void task_print_list(bool additional)
[37c57f2]670{
[f74bbaf]671 /* Messing with task structures, avoid deadlock */
[da1bafb]672 irq_spinlock_lock(&tasks_lock, true);
[a35b458]673
[5ba201d]674#ifdef __32_BITS__
[c0f13d2]675 if (additional)
[48dcc69]676 printf("[id ] [threads] [calls] [callee\n");
[c0f13d2]677 else
[473d5d2]678 printf("[id ] [name ] [ctn] [address ] [as ]"
[c0f13d2]679 " [ucycles ] [kcycles ]\n");
[52755f1]680#endif
[a35b458]681
[52755f1]682#ifdef __64_BITS__
[c0f13d2]683 if (additional)
[be06914]684 printf("[id ] [ucycles ] [kcycles ] [threads] [calls]"
[c0f13d2]685 " [callee\n");
686 else
[473d5d2]687 printf("[id ] [name ] [ctn] [address ]"
[c0f13d2]688 " [as ]\n");
[52755f1]689#endif
[a35b458]690
[ef1eab7]691 task_t *task;
692
[aab5e46]693 task = task_first();
694 while (task != NULL) {
[ef1eab7]695 task_print(task, additional);
[aab5e46]696 task = task_next(task);
[ef1eab7]697 }
[a35b458]698
[da1bafb]699 irq_spinlock_unlock(&tasks_lock, true);
[37c57f2]700}
[7509ddc]701
[ef1eab7]702/** Get key function for the @c tasks ordered dictionary.
703 *
704 * @param odlink Link
705 * @return Pointer to task ID cast as 'void *'
706 */
707static void *tasks_getkey(odlink_t *odlink)
708{
709 task_t *task = odict_get_instance(odlink, task_t, ltasks);
710 return (void *) &task->taskid;
711}
712
713/** Key comparison function for the @c tasks ordered dictionary.
714 *
715 * @param a Pointer to thread A ID
716 * @param b Pointer to thread B ID
717 * @return -1, 0, 1 iff ID A is less than, equal to, greater than B
718 */
719static int tasks_cmp(void *a, void *b)
720{
721 task_id_t ida = *(task_id_t *)a;
722 task_id_t idb = *(task_id_t *)b;
723
724 if (ida < idb)
725 return -1;
726 else if (ida == idb)
727 return 0;
728 else
729 return +1;
730}
731
[cc73a8a1]732/** @}
[b45c443]733 */
Note: See TracBrowser for help on using the repository browser.