Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2445 → Rev 2446

/trunk/kernel/generic/src/proc/task.c
56,7 → 56,6
#include <errno.h>
#include <func.h>
#include <syscall/copy.h>
#include <console/klog.h>
 
#ifndef LOADED_PROG_STACK_PAGES_NO
#define LOADED_PROG_STACK_PAGES_NO 1
79,9 → 78,6
 
static task_id_t task_counter = 0;
 
static void ktaskclnp(void *arg);
static void ktaskgc(void *arg);
 
/** Initialize tasks
*
* Initialize kernel tasks support.
164,12 → 160,11
list_initialize(&ta->th_head);
ta->as = as;
ta->name = name;
ta->main_thread = NULL;
ta->refcount = 0;
atomic_set(&ta->refcount, 0);
atomic_set(&ta->lifecount, 0);
ta->context = CONTEXT;
 
ta->capabilities = 0;
ta->accept_new_threads = true;
ta->cycles = 0;
ipc_answerbox_init(&ta->answerbox);
191,10 → 186,8
atomic_inc(&as->refcount);
 
spinlock_lock(&tasks_lock);
 
ta->taskid = ++task_counter;
btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL);
 
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
 
207,9 → 200,26
*/
void task_destroy(task_t *t)
{
/*
* Remove the task from the task B+tree.
*/
spinlock_lock(&tasks_lock);
btree_remove(&tasks_btree, t->taskid, NULL);
spinlock_unlock(&tasks_lock);
 
/*
* Perform architecture specific task destruction.
*/
task_destroy_arch(t);
 
/*
* Free up dynamically allocated state.
*/
btree_destroy(&t->futexes);
 
/*
* Drop our reference to the address space.
*/
if (atomic_predec(&t->as->refcount) == 0)
as_destroy(t->as);
229,7 → 239,7
as_t *as;
as_area_t *a;
int rc;
thread_t *t1, *t2;
thread_t *t;
task_t *task;
uspace_arg_t *kernel_uarg;
 
263,19 → 273,12
/*
* Create the main thread.
*/
t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
"uinit", false);
ASSERT(t1);
ASSERT(t);
/*
* Create killer thread for the new task.
*/
t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc", true);
ASSERT(t2);
thread_ready(t2);
thread_ready(t);
 
thread_ready(t1);
 
return task;
}
 
347,6 → 350,9
 
/** Kill task.
*
* This function is idempotent.
* It signals all the task's threads to bail it out.
*
* @param id ID of the task to be killed.
*
* @return 0 on success or an error code from errno.h
355,7 → 361,6
{
ipl_t ipl;
task_t *ta;
thread_t *t;
link_t *cur;
 
if (id == 1)
363,36 → 368,22
ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
 
if (!(ta = task_find_by_id(id))) {
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
return ENOENT;
}
 
spinlock_lock(&ta->lock);
ta->refcount++;
spinlock_unlock(&ta->lock);
 
btree_remove(&tasks_btree, ta->taskid, NULL);
spinlock_unlock(&tasks_lock);
t = thread_create(ktaskclnp, NULL, ta, 0, "ktaskclnp", true);
spinlock_lock(&ta->lock);
ta->accept_new_threads = false;
ta->refcount--;
 
/*
* Interrupt all threads except ktaskclnp.
*/
*/
spinlock_lock(&ta->lock);
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
thread_t *thr;
bool sleeping = false;
bool sleeping = false;
thr = list_get_instance(cur, thread_t, th_link);
if (thr == t)
continue;
spinlock_lock(&thr->lock);
thr->interrupted = true;
403,13 → 394,9
if (sleeping)
waitq_interrupt_sleep(thr);
}
spinlock_unlock(&ta->lock);
interrupts_restore(ipl);
if (t)
thread_ready(t);
 
return 0;
}
 
425,7 → 412,8
printf("taskid name ctx address as cycles threads "
"calls callee\n");
printf("------ ---------- --- ---------- ---------- ---------- ------- " "------ ------>\n");
printf("------ ---------- --- ---------- ---------- ---------- ------- "
"------ ------>\n");
 
for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head;
cur = cur->next) {
464,135 → 452,5
interrupts_restore(ipl);
}
 
/** Kernel thread used to cleanup the task after it is killed. */
void ktaskclnp(void *arg)
{
ipl_t ipl;
thread_t *t = NULL, *main_thread;
link_t *cur;
bool again;
 
thread_detach(THREAD);
 
loop:
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
main_thread = TASK->main_thread;
/*
* Find a thread to join.
*/
again = false;
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
t = list_get_instance(cur, thread_t, th_link);
 
spinlock_lock(&t->lock);
if (t == THREAD) {
spinlock_unlock(&t->lock);
continue;
} else if (t == main_thread) {
spinlock_unlock(&t->lock);
continue;
} else if (t->join_type != None) {
spinlock_unlock(&t->lock);
again = true;
continue;
} else {
t->join_type = TaskClnp;
spinlock_unlock(&t->lock);
again = false;
break;
}
}
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
if (again) {
/*
* Other cleanup (e.g. ktaskgc) is in progress.
*/
scheduler();
goto loop;
}
if (t != THREAD) {
ASSERT(t != main_thread); /* uninit is joined and detached
* in ktaskgc */
thread_join(t);
thread_detach(t);
goto loop; /* go for another thread */
}
/*
* Now there are no other threads in this task
* and no new threads can be created.
*/
 
ipc_cleanup();
futex_cleanup();
klog_printf("Cleanup of task %llu completed.", TASK->taskid);
}
 
/** Kernel thread used to kill the userspace task when its main thread exits.
*
* This thread waits until the main userspace thread (i.e. uninit) exits.
* When this happens, the task is killed. In the meantime, exited threads
* are garbage collected.
*
* @param arg Pointer to the thread structure of the task's main thread.
*/
void ktaskgc(void *arg)
{
thread_t *t = (thread_t *) arg;
loop:
/*
* Userspace threads cannot detach themselves,
* therefore the thread pointer is guaranteed to be valid.
*/
if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) ==
ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */
ipl_t ipl;
link_t *cur;
thread_t *thr = NULL;
/*
* The join timed out. Try to do some garbage collection of
* Undead threads.
*/
more_gc:
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
for (cur = TASK->th_head.next; cur != &TASK->th_head;
cur = cur->next) {
thr = list_get_instance(cur, thread_t, th_link);
spinlock_lock(&thr->lock);
if (thr != t && thr->state == Undead &&
thr->join_type == None) {
thr->join_type = TaskGC;
spinlock_unlock(&thr->lock);
break;
}
spinlock_unlock(&thr->lock);
thr = NULL;
}
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
if (thr) {
thread_join(thr);
thread_detach(thr);
scheduler();
goto more_gc;
}
goto loop;
}
thread_detach(t);
task_kill(TASK->taskid);
}
 
/** @}
*/