Subversion Repositories HelenOS

Rev

Rev 2436 | Rev 2632 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2436 Rev 2446
1
/*
1
/*
2
 * Copyright (c) 2001-2004 Jakub Jermar
2
 * Copyright (c) 2001-2004 Jakub Jermar
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup genericproc
29
/** @addtogroup genericproc
30
 * @{
30
 * @{
31
 */
31
 */
32
 
32
 
33
/**
33
/**
34
 * @file
34
 * @file
35
 * @brief   Task management.
35
 * @brief   Task management.
36
 */
36
 */
37
 
37
 
38
#include <main/uinit.h>
38
#include <main/uinit.h>
39
#include <proc/thread.h>
39
#include <proc/thread.h>
40
#include <proc/task.h>
40
#include <proc/task.h>
41
#include <proc/uarg.h>
41
#include <proc/uarg.h>
42
#include <mm/as.h>
42
#include <mm/as.h>
43
#include <mm/slab.h>
43
#include <mm/slab.h>
44
#include <atomic.h>
44
#include <atomic.h>
45
#include <synch/spinlock.h>
45
#include <synch/spinlock.h>
46
#include <synch/waitq.h>
46
#include <synch/waitq.h>
47
#include <arch.h>
47
#include <arch.h>
48
#include <panic.h>
48
#include <panic.h>
49
#include <adt/btree.h>
49
#include <adt/btree.h>
50
#include <adt/list.h>
50
#include <adt/list.h>
51
#include <ipc/ipc.h>
51
#include <ipc/ipc.h>
52
#include <security/cap.h>
52
#include <security/cap.h>
53
#include <memstr.h>
53
#include <memstr.h>
54
#include <print.h>
54
#include <print.h>
55
#include <lib/elf.h>
55
#include <lib/elf.h>
56
#include <errno.h>
56
#include <errno.h>
57
#include <func.h>
57
#include <func.h>
58
#include <syscall/copy.h>
58
#include <syscall/copy.h>
59
#include <console/klog.h>
-
 
60
 
59
 
61
#ifndef LOADED_PROG_STACK_PAGES_NO
60
#ifndef LOADED_PROG_STACK_PAGES_NO
62
#define LOADED_PROG_STACK_PAGES_NO 1
61
#define LOADED_PROG_STACK_PAGES_NO 1
63
#endif
62
#endif
64
 
63
 
65
/** Spinlock protecting the tasks_btree B+tree. */
64
/** Spinlock protecting the tasks_btree B+tree. */
66
SPINLOCK_INITIALIZE(tasks_lock);
65
SPINLOCK_INITIALIZE(tasks_lock);
67
 
66
 
68
/** B+tree of active tasks.
67
/** B+tree of active tasks.
69
 *
68
 *
70
 * The task is guaranteed to exist after it was found in the tasks_btree as
69
 * The task is guaranteed to exist after it was found in the tasks_btree as
71
 * long as:
70
 * long as:
72
 * @li the tasks_lock is held,
71
 * @li the tasks_lock is held,
73
 * @li the task's lock is held when task's lock is acquired before releasing
72
 * @li the task's lock is held when task's lock is acquired before releasing
74
 *     tasks_lock or
73
 *     tasks_lock or
75
 * @li the task's refcount is greater than 0
74
 * @li the task's refcount is greater than 0
76
 *
75
 *
77
 */
76
 */
78
btree_t tasks_btree;
77
btree_t tasks_btree;
79
 
78
 
80
static task_id_t task_counter = 0;
79
static task_id_t task_counter = 0;
81
 
80
 
82
static void ktaskclnp(void *arg);
-
 
83
static void ktaskgc(void *arg);
-
 
84
 
-
 
85
/** Initialize tasks
81
/** Initialize tasks
86
 *
82
 *
87
 * Initialize kernel tasks support.
83
 * Initialize kernel tasks support.
88
 *
84
 *
89
 */
85
 */
90
void task_init(void)
86
void task_init(void)
91
{
87
{
92
    TASK = NULL;
88
    TASK = NULL;
93
    btree_create(&tasks_btree);
89
    btree_create(&tasks_btree);
94
}
90
}
95
 
91
 
96
/** Kill all tasks except the current task.
92
/** Kill all tasks except the current task.
97
 *
93
 *
98
 */
94
 */
99
void task_done(void)
95
void task_done(void)
100
{
96
{
101
    task_t *t;
97
    task_t *t;
102
    do { /* Repeat until there are any tasks except TASK */
98
    do { /* Repeat until there are any tasks except TASK */
103
       
99
       
104
        /* Messing with task structures, avoid deadlock */
100
        /* Messing with task structures, avoid deadlock */
105
        ipl_t ipl = interrupts_disable();
101
        ipl_t ipl = interrupts_disable();
106
        spinlock_lock(&tasks_lock);
102
        spinlock_lock(&tasks_lock);
107
       
103
       
108
        t = NULL;
104
        t = NULL;
109
        link_t *cur;
105
        link_t *cur;
110
        for (cur = tasks_btree.leaf_head.next;
106
        for (cur = tasks_btree.leaf_head.next;
111
            cur != &tasks_btree.leaf_head; cur = cur->next) {
107
            cur != &tasks_btree.leaf_head; cur = cur->next) {
112
            btree_node_t *node;
108
            btree_node_t *node;
113
           
109
           
114
            node = list_get_instance(cur, btree_node_t, leaf_link);
110
            node = list_get_instance(cur, btree_node_t, leaf_link);
115
           
111
           
116
            unsigned int i;
112
            unsigned int i;
117
            for (i = 0; i < node->keys; i++) {
113
            for (i = 0; i < node->keys; i++) {
118
                if ((task_t *) node->value[i] != TASK) {
114
                if ((task_t *) node->value[i] != TASK) {
119
                    t = (task_t *) node->value[i];
115
                    t = (task_t *) node->value[i];
120
                    break;
116
                    break;
121
                }
117
                }
122
            }
118
            }
123
        }
119
        }
124
       
120
       
125
        if (t != NULL) {
121
        if (t != NULL) {
126
            task_id_t id = t->taskid;
122
            task_id_t id = t->taskid;
127
           
123
           
128
            spinlock_unlock(&tasks_lock);
124
            spinlock_unlock(&tasks_lock);
129
            interrupts_restore(ipl);
125
            interrupts_restore(ipl);
130
           
126
           
131
#ifdef CONFIG_DEBUG
127
#ifdef CONFIG_DEBUG
132
            printf("Killing task %llu\n", id);
128
            printf("Killing task %llu\n", id);
133
#endif          
129
#endif          
134
            task_kill(id);
130
            task_kill(id);
135
        } else {
131
        } else {
136
            spinlock_unlock(&tasks_lock);
132
            spinlock_unlock(&tasks_lock);
137
            interrupts_restore(ipl);
133
            interrupts_restore(ipl);
138
        }
134
        }
139
       
135
       
140
    } while (t != NULL);
136
    } while (t != NULL);
141
}
137
}
142
 
138
 
143
/** Create new task
139
/** Create new task
144
 *
140
 *
145
 * Create new task with no threads.
141
 * Create new task with no threads.
146
 *
142
 *
147
 * @param as Task's address space.
143
 * @param as Task's address space.
148
 * @param name Symbolic name.
144
 * @param name Symbolic name.
149
 *
145
 *
150
 * @return New task's structure
146
 * @return New task's structure
151
 *
147
 *
152
 */
148
 */
153
task_t *task_create(as_t *as, char *name)
149
task_t *task_create(as_t *as, char *name)
154
{
150
{
155
    ipl_t ipl;
151
    ipl_t ipl;
156
    task_t *ta;
152
    task_t *ta;
157
    int i;
153
    int i;
158
   
154
   
159
    ta = (task_t *) malloc(sizeof(task_t), 0);
155
    ta = (task_t *) malloc(sizeof(task_t), 0);
160
 
156
 
161
    task_create_arch(ta);
157
    task_create_arch(ta);
162
 
158
 
163
    spinlock_initialize(&ta->lock, "task_ta_lock");
159
    spinlock_initialize(&ta->lock, "task_ta_lock");
164
    list_initialize(&ta->th_head);
160
    list_initialize(&ta->th_head);
165
    ta->as = as;
161
    ta->as = as;
166
    ta->name = name;
162
    ta->name = name;
167
    ta->main_thread = NULL;
163
    atomic_set(&ta->refcount, 0);
168
    ta->refcount = 0;
164
    atomic_set(&ta->lifecount, 0);
169
    ta->context = CONTEXT;
165
    ta->context = CONTEXT;
170
 
166
 
171
    ta->capabilities = 0;
167
    ta->capabilities = 0;
172
    ta->accept_new_threads = true;
-
 
173
    ta->cycles = 0;
168
    ta->cycles = 0;
174
   
169
   
175
    ipc_answerbox_init(&ta->answerbox);
170
    ipc_answerbox_init(&ta->answerbox);
176
    for (i = 0; i < IPC_MAX_PHONES; i++)
171
    for (i = 0; i < IPC_MAX_PHONES; i++)
177
        ipc_phone_init(&ta->phones[i]);
172
        ipc_phone_init(&ta->phones[i]);
178
    if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context,
173
    if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context,
179
        ta->context)))
174
        ta->context)))
180
        ipc_phone_connect(&ta->phones[0], ipc_phone_0);
175
        ipc_phone_connect(&ta->phones[0], ipc_phone_0);
181
    atomic_set(&ta->active_calls, 0);
176
    atomic_set(&ta->active_calls, 0);
182
 
177
 
183
    mutex_initialize(&ta->futexes_lock);
178
    mutex_initialize(&ta->futexes_lock);
184
    btree_create(&ta->futexes);
179
    btree_create(&ta->futexes);
185
   
180
   
186
    ipl = interrupts_disable();
181
    ipl = interrupts_disable();
187
 
182
 
188
    /*
183
    /*
189
     * Increment address space reference count.
184
     * Increment address space reference count.
190
     */
185
     */
191
    atomic_inc(&as->refcount);
186
    atomic_inc(&as->refcount);
192
 
187
 
193
    spinlock_lock(&tasks_lock);
188
    spinlock_lock(&tasks_lock);
194
 
-
 
195
    ta->taskid = ++task_counter;
189
    ta->taskid = ++task_counter;
196
    btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL);
190
    btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL);
197
 
-
 
198
    spinlock_unlock(&tasks_lock);
191
    spinlock_unlock(&tasks_lock);
199
    interrupts_restore(ipl);
192
    interrupts_restore(ipl);
200
 
193
 
201
    return ta;
194
    return ta;
202
}
195
}
203
 
196
 
204
/** Destroy task.
197
/** Destroy task.
205
 *
198
 *
206
 * @param t Task to be destroyed.
199
 * @param t Task to be destroyed.
207
 */
200
 */
208
void task_destroy(task_t *t)
201
void task_destroy(task_t *t)
209
{
202
{
-
 
203
    /*
-
 
204
     * Remove the task from the task B+tree.
-
 
205
     */
-
 
206
    spinlock_lock(&tasks_lock);
-
 
207
    btree_remove(&tasks_btree, t->taskid, NULL);
-
 
208
    spinlock_unlock(&tasks_lock);
-
 
209
 
-
 
210
    /*
-
 
211
     * Perform architecture specific task destruction.
-
 
212
     */
210
    task_destroy_arch(t);
213
    task_destroy_arch(t);
-
 
214
 
-
 
215
    /*
-
 
216
     * Free up dynamically allocated state.
-
 
217
     */
211
    btree_destroy(&t->futexes);
218
    btree_destroy(&t->futexes);
212
 
219
 
-
 
220
    /*
-
 
221
     * Drop our reference to the address space.
-
 
222
     */
213
    if (atomic_predec(&t->as->refcount) == 0)
223
    if (atomic_predec(&t->as->refcount) == 0)
214
        as_destroy(t->as);
224
        as_destroy(t->as);
215
   
225
   
216
    free(t);
226
    free(t);
217
    TASK = NULL;
227
    TASK = NULL;
218
}
228
}
219
 
229
 
220
/** Create new task with 1 thread and run it
230
/** Create new task with 1 thread and run it
221
 *
231
 *
222
 * @param program_addr Address of program executable image.
232
 * @param program_addr Address of program executable image.
223
 * @param name Program name.
233
 * @param name Program name.
224
 *
234
 *
225
 * @return Task of the running program or NULL on error.
235
 * @return Task of the running program or NULL on error.
226
 */
236
 */
227
task_t *task_run_program(void *program_addr, char *name)
237
task_t *task_run_program(void *program_addr, char *name)
228
{
238
{
229
    as_t *as;
239
    as_t *as;
230
    as_area_t *a;
240
    as_area_t *a;
231
    int rc;
241
    int rc;
232
    thread_t *t1, *t2;
242
    thread_t *t;
233
    task_t *task;
243
    task_t *task;
234
    uspace_arg_t *kernel_uarg;
244
    uspace_arg_t *kernel_uarg;
235
 
245
 
236
    as = as_create(0);
246
    as = as_create(0);
237
    ASSERT(as);
247
    ASSERT(as);
238
 
248
 
239
    rc = elf_load((elf_header_t *) program_addr, as);
249
    rc = elf_load((elf_header_t *) program_addr, as);
240
    if (rc != EE_OK) {
250
    if (rc != EE_OK) {
241
        as_destroy(as);
251
        as_destroy(as);
242
        return NULL;
252
        return NULL;
243
    }
253
    }
244
   
254
   
245
    kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
255
    kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
246
    kernel_uarg->uspace_entry =
256
    kernel_uarg->uspace_entry =
247
        (void *) ((elf_header_t *) program_addr)->e_entry;
257
        (void *) ((elf_header_t *) program_addr)->e_entry;
248
    kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
258
    kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
249
    kernel_uarg->uspace_thread_function = NULL;
259
    kernel_uarg->uspace_thread_function = NULL;
250
    kernel_uarg->uspace_thread_arg = NULL;
260
    kernel_uarg->uspace_thread_arg = NULL;
251
    kernel_uarg->uspace_uarg = NULL;
261
    kernel_uarg->uspace_uarg = NULL;
252
   
262
   
253
    task = task_create(as, name);
263
    task = task_create(as, name);
254
    ASSERT(task);
264
    ASSERT(task);
255
 
265
 
256
    /*
266
    /*
257
     * Create the data as_area.
267
     * Create the data as_area.
258
     */
268
     */
259
    a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
269
    a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
260
        LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
270
        LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
261
        AS_AREA_ATTR_NONE, &anon_backend, NULL);
271
        AS_AREA_ATTR_NONE, &anon_backend, NULL);
262
 
272
 
263
    /*
273
    /*
264
     * Create the main thread.
274
     * Create the main thread.
265
     */
275
     */
266
    t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
276
    t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
267
        "uinit", false);
277
        "uinit", false);
268
    ASSERT(t1);
278
    ASSERT(t);
269
   
279
   
270
    /*
-
 
271
     * Create killer thread for the new task.
-
 
272
     */
-
 
273
    t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc", true);
-
 
274
    ASSERT(t2);
-
 
275
    thread_ready(t2);
280
    thread_ready(t);
276
 
-
 
277
    thread_ready(t1);
-
 
278
 
281
 
279
    return task;
282
    return task;
280
}
283
}
281
 
284
 
282
/** Syscall for reading task ID from userspace.
285
/** Syscall for reading task ID from userspace.
283
 *
286
 *
284
 * @param uspace_task_id Userspace address of 8-byte buffer where to store
287
 * @param uspace_task_id Userspace address of 8-byte buffer where to store
285
 * current task ID.
288
 * current task ID.
286
 *
289
 *
287
 * @return 0 on success or an error code from @ref errno.h.
290
 * @return 0 on success or an error code from @ref errno.h.
288
 */
291
 */
289
unative_t sys_task_get_id(task_id_t *uspace_task_id)
292
unative_t sys_task_get_id(task_id_t *uspace_task_id)
290
{
293
{
291
    /*
294
    /*
292
     * No need to acquire lock on TASK because taskid
295
     * No need to acquire lock on TASK because taskid
293
     * remains constant for the lifespan of the task.
296
     * remains constant for the lifespan of the task.
294
     */
297
     */
295
    return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid,
298
    return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid,
296
        sizeof(TASK->taskid));
299
        sizeof(TASK->taskid));
297
}
300
}
298
 
301
 
299
/** Find task structure corresponding to task ID.
302
/** Find task structure corresponding to task ID.
300
 *
303
 *
301
 * The tasks_lock must be already held by the caller of this function
304
 * The tasks_lock must be already held by the caller of this function
302
 * and interrupts must be disabled.
305
 * and interrupts must be disabled.
303
 *
306
 *
304
 * @param id Task ID.
307
 * @param id Task ID.
305
 *
308
 *
306
 * @return Task structure address or NULL if there is no such task ID.
309
 * @return Task structure address or NULL if there is no such task ID.
307
 */
310
 */
308
task_t *task_find_by_id(task_id_t id)
311
task_t *task_find_by_id(task_id_t id)
309
{
312
{
310
    btree_node_t *leaf;
313
    btree_node_t *leaf;
311
   
314
   
312
    return (task_t *) btree_search(&tasks_btree, (btree_key_t) id, &leaf);
315
    return (task_t *) btree_search(&tasks_btree, (btree_key_t) id, &leaf);
313
}
316
}
314
 
317
 
315
/** Get accounting data of given task.
318
/** Get accounting data of given task.
316
 *
319
 *
317
 * Note that task lock of 't' must be already held and
320
 * Note that task lock of 't' must be already held and
318
 * interrupts must be already disabled.
321
 * interrupts must be already disabled.
319
 *
322
 *
320
 * @param t Pointer to thread.
323
 * @param t Pointer to thread.
321
 *
324
 *
322
 */
325
 */
323
uint64_t task_get_accounting(task_t *t)
326
uint64_t task_get_accounting(task_t *t)
324
{
327
{
325
    /* Accumulated value of task */
328
    /* Accumulated value of task */
326
    uint64_t ret = t->cycles;
329
    uint64_t ret = t->cycles;
327
   
330
   
328
    /* Current values of threads */
331
    /* Current values of threads */
329
    link_t *cur;
332
    link_t *cur;
330
    for (cur = t->th_head.next; cur != &t->th_head; cur = cur->next) {
333
    for (cur = t->th_head.next; cur != &t->th_head; cur = cur->next) {
331
        thread_t *thr = list_get_instance(cur, thread_t, th_link);
334
        thread_t *thr = list_get_instance(cur, thread_t, th_link);
332
       
335
       
333
        spinlock_lock(&thr->lock);
336
        spinlock_lock(&thr->lock);
334
        /* Process only counted threads */
337
        /* Process only counted threads */
335
        if (!thr->uncounted) {
338
        if (!thr->uncounted) {
336
            if (thr == THREAD) {
339
            if (thr == THREAD) {
337
                /* Update accounting of current thread */
340
                /* Update accounting of current thread */
338
                thread_update_accounting();
341
                thread_update_accounting();
339
            }
342
            }
340
            ret += thr->cycles;
343
            ret += thr->cycles;
341
        }
344
        }
342
        spinlock_unlock(&thr->lock);
345
        spinlock_unlock(&thr->lock);
343
    }
346
    }
344
   
347
   
345
    return ret;
348
    return ret;
346
}
349
}
347
 
350
 
348
/** Kill task.
351
/** Kill task.
349
 *
352
 *
-
 
353
 * This function is idempotent.
-
 
354
 * It signals all the task's threads to bail it out.
-
 
355
 *
350
 * @param id ID of the task to be killed.
356
 * @param id ID of the task to be killed.
351
 *
357
 *
352
 * @return 0 on success or an error code from errno.h
358
 * @return 0 on success or an error code from errno.h
353
 */
359
 */
354
int task_kill(task_id_t id)
360
int task_kill(task_id_t id)
355
{
361
{
356
    ipl_t ipl;
362
    ipl_t ipl;
357
    task_t *ta;
363
    task_t *ta;
358
    thread_t *t;
-
 
359
    link_t *cur;
364
    link_t *cur;
360
 
365
 
361
    if (id == 1)
366
    if (id == 1)
362
        return EPERM;
367
        return EPERM;
363
   
368
   
364
    ipl = interrupts_disable();
369
    ipl = interrupts_disable();
365
    spinlock_lock(&tasks_lock);
370
    spinlock_lock(&tasks_lock);
366
 
-
 
367
    if (!(ta = task_find_by_id(id))) {
371
    if (!(ta = task_find_by_id(id))) {
368
        spinlock_unlock(&tasks_lock);
372
        spinlock_unlock(&tasks_lock);
369
        interrupts_restore(ipl);
373
        interrupts_restore(ipl);
370
        return ENOENT;
374
        return ENOENT;
371
    }
375
    }
372
 
-
 
373
    spinlock_lock(&ta->lock);
-
 
374
    ta->refcount++;
-
 
375
    spinlock_unlock(&ta->lock);
-
 
376
 
-
 
377
    btree_remove(&tasks_btree, ta->taskid, NULL);
-
 
378
    spinlock_unlock(&tasks_lock);
376
    spinlock_unlock(&tasks_lock);
379
   
377
   
380
    t = thread_create(ktaskclnp, NULL, ta, 0, "ktaskclnp", true);
-
 
381
   
-
 
382
    spinlock_lock(&ta->lock);
-
 
383
    ta->accept_new_threads = false;
-
 
384
    ta->refcount--;
-
 
385
 
-
 
386
    /*
378
    /*
387
     * Interrupt all threads except ktaskclnp.
379
     * Interrupt all threads except ktaskclnp.
388
     */
380
     */
-
 
381
    spinlock_lock(&ta->lock);
389
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
382
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
390
        thread_t *thr;
383
        thread_t *thr;
391
        bool  sleeping = false;
384
        bool sleeping = false;
392
       
385
       
393
        thr = list_get_instance(cur, thread_t, th_link);
386
        thr = list_get_instance(cur, thread_t, th_link);
394
        if (thr == t)
-
 
395
            continue;
-
 
396
           
387
           
397
        spinlock_lock(&thr->lock);
388
        spinlock_lock(&thr->lock);
398
        thr->interrupted = true;
389
        thr->interrupted = true;
399
        if (thr->state == Sleeping)
390
        if (thr->state == Sleeping)
400
            sleeping = true;
391
            sleeping = true;
401
        spinlock_unlock(&thr->lock);
392
        spinlock_unlock(&thr->lock);
402
       
393
       
403
        if (sleeping)
394
        if (sleeping)
404
            waitq_interrupt_sleep(thr);
395
            waitq_interrupt_sleep(thr);
405
    }
396
    }
406
   
-
 
407
    spinlock_unlock(&ta->lock);
397
    spinlock_unlock(&ta->lock);
408
    interrupts_restore(ipl);
398
    interrupts_restore(ipl);
409
   
399
   
410
    if (t)
-
 
411
        thread_ready(t);
-
 
412
 
-
 
413
    return 0;
400
    return 0;
414
}
401
}
415
 
402
 
416
/** Print task list */
403
/** Print task list */
417
void task_print_list(void)
404
void task_print_list(void)
418
{
405
{
419
    link_t *cur;
406
    link_t *cur;
420
    ipl_t ipl;
407
    ipl_t ipl;
421
   
408
   
422
    /* Messing with task structures, avoid deadlock */
409
    /* Messing with task structures, avoid deadlock */
423
    ipl = interrupts_disable();
410
    ipl = interrupts_disable();
424
    spinlock_lock(&tasks_lock);
411
    spinlock_lock(&tasks_lock);
425
   
412
   
426
    printf("taskid name       ctx address    as         cycles     threads "
413
    printf("taskid name       ctx address    as         cycles     threads "
427
        "calls  callee\n");
414
        "calls  callee\n");
428
    printf("------ ---------- --- ---------- ---------- ---------- ------- "        "------ ------>\n");
415
    printf("------ ---------- --- ---------- ---------- ---------- ------- "
-
 
416
        "------ ------>\n");
429
 
417
 
430
    for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head;
418
    for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head;
431
        cur = cur->next) {
419
        cur = cur->next) {
432
        btree_node_t *node;
420
        btree_node_t *node;
433
        unsigned int i;
421
        unsigned int i;
434
       
422
       
435
        node = list_get_instance(cur, btree_node_t, leaf_link);
423
        node = list_get_instance(cur, btree_node_t, leaf_link);
436
        for (i = 0; i < node->keys; i++) {
424
        for (i = 0; i < node->keys; i++) {
437
            task_t *t;
425
            task_t *t;
438
            int j;
426
            int j;
439
 
427
 
440
            t = (task_t *) node->value[i];
428
            t = (task_t *) node->value[i];
441
       
429
       
442
            spinlock_lock(&t->lock);
430
            spinlock_lock(&t->lock);
443
           
431
           
444
            uint64_t cycles;
432
            uint64_t cycles;
445
            char suffix;
433
            char suffix;
446
            order(task_get_accounting(t), &cycles, &suffix);
434
            order(task_get_accounting(t), &cycles, &suffix);
447
           
435
           
448
            printf("%-6llu %-10s %-3ld %#10zx %#10zx %9llu%c %7zd "
436
            printf("%-6llu %-10s %-3ld %#10zx %#10zx %9llu%c %7zd "
449
                "%6zd", t->taskid, t->name, t->context, t, t->as,
437
                "%6zd", t->taskid, t->name, t->context, t, t->as,
450
                cycles, suffix, t->refcount,
438
                cycles, suffix, t->refcount,
451
                atomic_get(&t->active_calls));
439
                atomic_get(&t->active_calls));
452
            for (j = 0; j < IPC_MAX_PHONES; j++) {
440
            for (j = 0; j < IPC_MAX_PHONES; j++) {
453
                if (t->phones[j].callee)
441
                if (t->phones[j].callee)
454
                    printf(" %zd:%#zx", j,
442
                    printf(" %zd:%#zx", j,
455
                        t->phones[j].callee);
443
                        t->phones[j].callee);
456
            }
444
            }
457
            printf("\n");
445
            printf("\n");
458
           
446
           
459
            spinlock_unlock(&t->lock);
447
            spinlock_unlock(&t->lock);
460
        }
448
        }
461
    }
449
    }
462
 
450
 
463
    spinlock_unlock(&tasks_lock);
451
    spinlock_unlock(&tasks_lock);
464
    interrupts_restore(ipl);
452
    interrupts_restore(ipl);
465
}
453
}
466
 
-
 
467
/** Kernel thread used to cleanup the task after it is killed. */
-
 
468
void ktaskclnp(void *arg)
-
 
469
{
-
 
470
    ipl_t ipl;
-
 
471
    thread_t *t = NULL, *main_thread;
-
 
472
    link_t *cur;
-
 
473
    bool again;
-
 
474
 
-
 
475
    thread_detach(THREAD);
-
 
476
 
-
 
477
loop:
-
 
478
    ipl = interrupts_disable();
-
 
479
    spinlock_lock(&TASK->lock);
-
 
480
   
-
 
481
    main_thread = TASK->main_thread;
-
 
482
   
-
 
483
    /*
-
 
484
     * Find a thread to join.
-
 
485
     */
-
 
486
    again = false;
-
 
487
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
-
 
488
        t = list_get_instance(cur, thread_t, th_link);
-
 
489
 
-
 
490
        spinlock_lock(&t->lock);
-
 
491
        if (t == THREAD) {
-
 
492
            spinlock_unlock(&t->lock);
-
 
493
            continue;
-
 
494
        } else if (t == main_thread) {
-
 
495
            spinlock_unlock(&t->lock);
-
 
496
            continue;
-
 
497
        } else if (t->join_type != None) {
-
 
498
            spinlock_unlock(&t->lock);
-
 
499
            again = true;
-
 
500
            continue;
-
 
501
        } else {
-
 
502
            t->join_type = TaskClnp;
-
 
503
            spinlock_unlock(&t->lock);
-
 
504
            again = false;
-
 
505
            break;
-
 
506
        }
-
 
507
    }
-
 
508
   
-
 
509
    spinlock_unlock(&TASK->lock);
-
 
510
    interrupts_restore(ipl);
-
 
511
   
-
 
512
    if (again) {
-
 
513
        /*
-
 
514
         * Other cleanup (e.g. ktaskgc) is in progress.
-
 
515
         */
-
 
516
        scheduler();
-
 
517
        goto loop;
-
 
518
    }
-
 
519
   
-
 
520
    if (t != THREAD) {
-
 
521
        ASSERT(t != main_thread);   /* uninit is joined and detached
-
 
522
                         * in ktaskgc */
-
 
523
        thread_join(t);
-
 
524
        thread_detach(t);
-
 
525
        goto loop;          /* go for another thread */
-
 
526
    }
-
 
527
   
-
 
528
    /*
-
 
529
     * Now there are no other threads in this task
-
 
530
     * and no new threads can be created.
-
 
531
     */
-
 
532
 
-
 
533
    ipc_cleanup();
-
 
534
    futex_cleanup();
-
 
535
    klog_printf("Cleanup of task %llu completed.", TASK->taskid);
-
 
536
}
-
 
537
 
-
 
538
/** Kernel thread used to kill the userspace task when its main thread exits.
-
 
539
 *
-
 
540
 * This thread waits until the main userspace thread (i.e. uninit) exits.
-
 
541
 * When this happens, the task is killed. In the meantime, exited threads
-
 
542
 * are garbage collected.
-
 
543
 *
-
 
544
 * @param arg Pointer to the thread structure of the task's main thread.
-
 
545
 */
-
 
546
void ktaskgc(void *arg)
-
 
547
{
-
 
548
    thread_t *t = (thread_t *) arg;
-
 
549
loop:  
-
 
550
    /*
-
 
551
     * Userspace threads cannot detach themselves,
-
 
552
     * therefore the thread pointer is guaranteed to be valid.
-
 
553
     */
-
 
554
    if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) ==
-
 
555
        ESYNCH_TIMEOUT) {   /* sleep uninterruptibly here! */
-
 
556
        ipl_t ipl;
-
 
557
        link_t *cur;
-
 
558
        thread_t *thr = NULL;
-
 
559
   
-
 
560
        /*
-
 
561
         * The join timed out. Try to do some garbage collection of
-
 
562
         * Undead threads.
-
 
563
         */
-
 
564
more_gc:       
-
 
565
        ipl = interrupts_disable();
-
 
566
        spinlock_lock(&TASK->lock);
-
 
567
       
-
 
568
        for (cur = TASK->th_head.next; cur != &TASK->th_head;
-
 
569
            cur = cur->next) {
-
 
570
            thr = list_get_instance(cur, thread_t, th_link);
-
 
571
            spinlock_lock(&thr->lock);
-
 
572
            if (thr != t && thr->state == Undead &&
-
 
573
                thr->join_type == None) {
-
 
574
                thr->join_type = TaskGC;
-
 
575
                spinlock_unlock(&thr->lock);
-
 
576
                break;
-
 
577
            }
-
 
578
            spinlock_unlock(&thr->lock);
-
 
579
            thr = NULL;
-
 
580
        }
-
 
581
        spinlock_unlock(&TASK->lock);
-
 
582
        interrupts_restore(ipl);
-
 
583
       
-
 
584
        if (thr) {
-
 
585
            thread_join(thr);
-
 
586
            thread_detach(thr);
-
 
587
            scheduler();
-
 
588
            goto more_gc;
-
 
589
        }
-
 
590
           
-
 
591
        goto loop;
-
 
592
    }
-
 
593
    thread_detach(t);
-
 
594
    task_kill(TASK->taskid);
-
 
595
}
-
 
596
 
454
 
597
/** @}
455
/** @}
598
 */
456
 */
599
 
457