Subversion Repositories HelenOS

Rev

Rev 3186 | Rev 3359 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 jermar 1
/*
2071 jermar 2
 * Copyright (c) 2001-2004 Jakub Jermar
1 jermar 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
 
1757 jermar 29
/** @addtogroup genericproc
1702 cejka 30
 * @{
31
 */
32
 
1248 jermar 33
/**
1702 cejka 34
 * @file
1248 jermar 35
 * @brief   Task management.
36
 */
37
 
1 jermar 38
#include <proc/thread.h>
39
#include <proc/task.h>
703 jermar 40
#include <mm/as.h>
814 palkovsky 41
#include <mm/slab.h>
2183 jermar 42
#include <atomic.h>
1 jermar 43
#include <synch/spinlock.h>
2109 jermar 44
#include <synch/waitq.h>
1 jermar 45
#include <arch.h>
3137 jermar 46
#include <arch/barrier.h>
2504 jermar 47
#include <adt/avl.h>
1159 jermar 48
#include <adt/btree.h>
788 jermar 49
#include <adt/list.h>
955 palkovsky 50
#include <ipc/ipc.h>
3222 svoboda 51
#include <ipc/ipcrsc.h>
1060 palkovsky 52
#include <print.h>
1579 jermar 53
#include <errno.h>
2050 decky 54
#include <func.h>
1288 jermar 55
#include <syscall/copy.h>
973 palkovsky 56
 
2504 jermar 57
/** Spinlock protecting the tasks_tree AVL tree. */
623 jermar 58
SPINLOCK_INITIALIZE(tasks_lock);
1636 jermar 59
 
2504 jermar 60
/** AVL tree of active tasks.
1636 jermar 61
 *
2504 jermar 62
 * The task is guaranteed to exist after it was found in the tasks_tree as
2087 jermar 63
 * long as:
1636 jermar 64
 * @li the tasks_lock is held,
2087 jermar 65
 * @li the task's lock is held when task's lock is acquired before releasing
66
 *     tasks_lock or
1880 jermar 67
 * @li the task's refcount is greater than 0
1636 jermar 68
 *
69
 */
2504 jermar 70
avltree_t tasks_tree;
1636 jermar 71
 
1005 palkovsky 72
static task_id_t task_counter = 0;
1 jermar 73
 
107 decky 74
/** Initialize tasks
75
 *
76
 * Initialize kernel tasks support.
77
 *
78
 */
1 jermar 79
void task_init(void)
80
{
15 jermar 81
    TASK = NULL;
2504 jermar 82
    avltree_create(&tasks_tree);
1 jermar 83
}
84
 
2504 jermar 85
/*
86
 * The idea behind this walker is to remember a single task different from TASK.
87
 */
88
static bool task_done_walker(avltree_node_t *node, void *arg)
89
{
90
    task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
91
    task_t **tp = (task_t **) arg;
92
 
93
    if (t != TASK) {
94
        *tp = t;
95
        return false;   /* stop walking */
96
    }
97
 
98
    return true;    /* continue the walk */
99
}
100
 
2227 decky 101
/** Kill all tasks except the current task.
102
 *
103
 */
104
void task_done(void)
105
{
106
    task_t *t;
107
    do { /* Repeat until there are any tasks except TASK */
108
 
109
        /* Messing with task structures, avoid deadlock */
110
        ipl_t ipl = interrupts_disable();
111
        spinlock_lock(&tasks_lock);
112
 
113
        t = NULL;
2504 jermar 114
        avltree_walk(&tasks_tree, task_done_walker, &t);
2227 decky 115
 
116
        if (t != NULL) {
117
            task_id_t id = t->taskid;
118
 
119
            spinlock_unlock(&tasks_lock);
120
            interrupts_restore(ipl);
121
 
122
#ifdef CONFIG_DEBUG
3063 decky 123
            printf("Killing task %" PRIu64 "\n", id);
2227 decky 124
#endif          
125
            task_kill(id);
2632 decky 126
            thread_usleep(10000);
2227 decky 127
        } else {
128
            spinlock_unlock(&tasks_lock);
129
            interrupts_restore(ipl);
130
        }
131
 
132
    } while (t != NULL);
133
}
107 decky 134
 
135
/** Create new task
136
 *
137
 * Create new task with no threads.
138
 *
703 jermar 139
 * @param as Task's address space.
1062 jermar 140
 * @param name Symbolic name.
107 decky 141
 *
973 palkovsky 142
 * @return New task's structure
107 decky 143
 *
144
 */
1062 jermar 145
task_t *task_create(as_t *as, char *name)
1 jermar 146
{
413 jermar 147
    ipl_t ipl;
1 jermar 148
    task_t *ta;
1040 palkovsky 149
    int i;
1 jermar 150
 
822 palkovsky 151
    ta = (task_t *) malloc(sizeof(task_t), 0);
152
 
1185 jermar 153
    task_create_arch(ta);
154
 
822 palkovsky 155
    spinlock_initialize(&ta->lock, "task_ta_lock");
156
    list_initialize(&ta->th_head);
157
    ta->as = as;
1062 jermar 158
    ta->name = name;
2446 jermar 159
    atomic_set(&ta->refcount, 0);
160
    atomic_set(&ta->lifecount, 0);
1839 decky 161
    ta->context = CONTEXT;
1579 jermar 162
 
1174 jermar 163
    ta->capabilities = 0;
2039 decky 164
    ta->cycles = 0;
1040 palkovsky 165
 
2802 jermar 166
    ipc_answerbox_init(&ta->answerbox, ta);
1839 decky 167
    for (i = 0; i < IPC_MAX_PHONES; i++)
1040 palkovsky 168
        ipc_phone_init(&ta->phones[i]);
2087 jermar 169
    if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context,
170
        ta->context)))
1040 palkovsky 171
        ipc_phone_connect(&ta->phones[0], ipc_phone_0);
998 palkovsky 172
    atomic_set(&ta->active_calls, 0);
1460 jermar 173
 
3186 jermar 174
    mutex_initialize(&ta->futexes_lock, MUTEX_PASSIVE);
1460 jermar 175
    btree_create(&ta->futexes);
822 palkovsky 176
 
177
    ipl = interrupts_disable();
1468 jermar 178
 
179
    /*
180
     * Increment address space reference count.
181
     */
2183 jermar 182
    atomic_inc(&as->refcount);
1468 jermar 183
 
822 palkovsky 184
    spinlock_lock(&tasks_lock);
1005 palkovsky 185
    ta->taskid = ++task_counter;
2504 jermar 186
    avltree_node_initialize(&ta->tasks_tree_node);
187
    ta->tasks_tree_node.key = ta->taskid;
188
    avltree_insert(&tasks_tree, &ta->tasks_tree_node);
822 palkovsky 189
    spinlock_unlock(&tasks_lock);
190
    interrupts_restore(ipl);
191
 
1 jermar 192
    return ta;
193
}
194
 
1579 jermar 195
/** Destroy task.
196
 *
197
 * @param t Task to be destroyed.
198
 */
199
void task_destroy(task_t *t)
200
{
2446 jermar 201
    /*
202
     * Remove the task from the task B+tree.
203
     */
204
    spinlock_lock(&tasks_lock);
2504 jermar 205
    avltree_delete(&tasks_tree, &t->tasks_tree_node);
2446 jermar 206
    spinlock_unlock(&tasks_lock);
207
 
208
    /*
209
     * Perform architecture specific task destruction.
210
     */
1587 jermar 211
    task_destroy_arch(t);
2446 jermar 212
 
213
    /*
214
     * Free up dynamically allocated state.
215
     */
1587 jermar 216
    btree_destroy(&t->futexes);
217
 
2446 jermar 218
    /*
219
     * Drop our reference to the address space.
220
     */
2183 jermar 221
    if (atomic_predec(&t->as->refcount) == 0)
1587 jermar 222
        as_destroy(t->as);
223
 
224
    free(t);
225
    TASK = NULL;
1579 jermar 226
}
227
 
1176 jermar 228
/** Syscall for reading task ID from userspace.
229
 *
2087 jermar 230
 * @param uspace_task_id Userspace address of 8-byte buffer where to store
231
 * current task ID.
1176 jermar 232
 *
1288 jermar 233
 * @return 0 on success or an error code from @ref errno.h.
1176 jermar 234
 */
1780 jermar 235
unative_t sys_task_get_id(task_id_t *uspace_task_id)
1176 jermar 236
{
237
    /*
238
     * No need to acquire lock on TASK because taskid
239
     * remains constant for the lifespan of the task.
240
     */
2087 jermar 241
    return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid,
242
        sizeof(TASK->taskid));
1176 jermar 243
}
244
 
1178 jermar 245
/** Find task structure corresponding to task ID.
246
 *
247
 * The tasks_lock must be already held by the caller of this function
248
 * and interrupts must be disabled.
249
 *
250
 * @param id Task ID.
251
 *
252
 * @return Task structure address or NULL if there is no such task ID.
253
 */
254
task_t *task_find_by_id(task_id_t id)
255
{
2504 jermar 256
    avltree_node_t *node;
1178 jermar 257
 
2504 jermar 258
    node = avltree_search(&tasks_tree, (avltree_key_t) id);
259
 
260
    if (node)
261
        return avltree_get_instance(node, task_t, tasks_tree_node);
262
    return NULL;
1178 jermar 263
}
264
 
2039 decky 265
/** Get accounting data of given task.
266
 *
2048 jermar 267
 * Note that task lock of 't' must be already held and
2039 decky 268
 * interrupts must be already disabled.
269
 *
270
 * @param t Pointer to thread.
271
 *
272
 */
273
uint64_t task_get_accounting(task_t *t)
274
{
275
    /* Accumulated value of task */
276
    uint64_t ret = t->cycles;
277
 
278
    /* Current values of threads */
279
    link_t *cur;
280
    for (cur = t->th_head.next; cur != &t->th_head; cur = cur->next) {
281
        thread_t *thr = list_get_instance(cur, thread_t, th_link);
282
 
283
        spinlock_lock(&thr->lock);
2042 decky 284
        /* Process only counted threads */
285
        if (!thr->uncounted) {
2087 jermar 286
            if (thr == THREAD) {
287
                /* Update accounting of current thread */
288
                thread_update_accounting();
289
            }
2042 decky 290
            ret += thr->cycles;
291
        }
2039 decky 292
        spinlock_unlock(&thr->lock);
293
    }
294
 
295
    return ret;
296
}
297
 
1579 jermar 298
/** Kill task.
299
 *
2446 jermar 300
 * This function is idempotent.
301
 * It signals all the task's threads to bail it out.
302
 *
1579 jermar 303
 * @param id ID of the task to be killed.
304
 *
305
 * @return 0 on success or an error code from errno.h
306
 */
307
int task_kill(task_id_t id)
308
{
309
    ipl_t ipl;
310
    task_t *ta;
311
    link_t *cur;
1600 jermar 312
 
313
    if (id == 1)
314
        return EPERM;
1579 jermar 315
 
316
    ipl = interrupts_disable();
317
    spinlock_lock(&tasks_lock);
318
    if (!(ta = task_find_by_id(id))) {
319
        spinlock_unlock(&tasks_lock);
320
        interrupts_restore(ipl);
321
        return ENOENT;
322
    }
1587 jermar 323
    spinlock_unlock(&tasks_lock);
1579 jermar 324
 
1585 jermar 325
    /*
1687 jermar 326
     * Interrupt all threads except ktaskclnp.
2446 jermar 327
     */
328
    spinlock_lock(&ta->lock);
1579 jermar 329
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
330
        thread_t *thr;
2446 jermar 331
        bool sleeping = false;
1579 jermar 332
 
333
        thr = list_get_instance(cur, thread_t, th_link);
334
 
335
        spinlock_lock(&thr->lock);
336
        thr->interrupted = true;
337
        if (thr->state == Sleeping)
338
            sleeping = true;
339
        spinlock_unlock(&thr->lock);
340
 
341
        if (sleeping)
2109 jermar 342
            waitq_interrupt_sleep(thr);
1579 jermar 343
    }
1580 jermar 344
    spinlock_unlock(&ta->lock);
345
    interrupts_restore(ipl);
1579 jermar 346
 
347
    return 0;
348
}
349
 
2504 jermar 350
static bool task_print_walker(avltree_node_t *node, void *arg)
351
{
352
    task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
353
    int j;
354
 
355
    spinlock_lock(&t->lock);
356
 
357
    uint64_t cycles;
358
    char suffix;
359
    order(task_get_accounting(t), &cycles, &suffix);
3063 decky 360
 
361
#ifdef __32_BITS__  
3137 jermar 362
    printf("%-6" PRIu64 " %-10s %-3" PRIu32 " %10p %10p %9" PRIu64
363
        "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
364
        suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
3063 decky 365
#endif
366
 
367
#ifdef __64_BITS__
3137 jermar 368
    printf("%-6" PRIu64 " %-10s %-3" PRIu32 " %18p %18p %9" PRIu64
369
        "%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
370
        suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
3063 decky 371
#endif
372
 
2504 jermar 373
    for (j = 0; j < IPC_MAX_PHONES; j++) {
374
        if (t->phones[j].callee)
3063 decky 375
            printf(" %d:%p", j, t->phones[j].callee);
2504 jermar 376
    }
377
    printf("\n");
378
 
379
    spinlock_unlock(&t->lock);
380
    return true;
381
}
382
 
1060 palkovsky 383
/** Print task list */
384
void task_print_list(void)
385
{
386
    ipl_t ipl;
387
 
2227 decky 388
    /* Messing with task structures, avoid deadlock */
1060 palkovsky 389
    ipl = interrupts_disable();
390
    spinlock_lock(&tasks_lock);
391
 
3063 decky 392
#ifdef __32_BITS__  
393
    printf("taskid name       ctx address    as         "
3137 jermar 394
        "cycles     threads calls  callee\n");
3063 decky 395
    printf("------ ---------- --- ---------- ---------- "
3137 jermar 396
        "---------- ------- ------ ------>\n");
3063 decky 397
#endif
398
 
399
#ifdef __64_BITS__
400
    printf("taskid name       ctx address            as                 "
3137 jermar 401
        "cycles     threads calls  callee\n");
3063 decky 402
    printf("------ ---------- --- ------------------ ------------------ "
3137 jermar 403
        "---------- ------- ------ ------>\n");
3063 decky 404
#endif
405
 
2504 jermar 406
    avltree_walk(&tasks_tree, task_print_walker, NULL);
1159 jermar 407
 
1060 palkovsky 408
    spinlock_unlock(&tasks_lock);
409
    interrupts_restore(ipl);
410
}
1579 jermar 411
 
1757 jermar 412
/** @}
1702 cejka 413
 */