[BACK]Return to task.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / kern

Annotation of prex-old/sys/kern/task.c, Revision 1.1.1.1.2.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 2005-2007, Kohsuke Ohtani
                      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:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. Neither the name of the author nor the names of any co-contributors
                     14:  *    may be used to endorse or promote products derived from this software
                     15:  *    without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * task.c - task management routines
                     32:  */
                     33:
                     34: #include <kernel.h>
                     35: #include <kmem.h>
                     36: #include <sched.h>
                     37: #include <thread.h>
                     38: #include <ipc.h>
                     39: #include <vm.h>
                     40: #include <page.h>
                     41: #include <task.h>
                     42:
                     43: /*
                     44:  * Kernel task.
                     45:  * kern_task acts as a list head of all tasks in the system.
                     46:  */
1.1.1.1.2.1! nbrk       47: struct task    kern_task;
1.1       nbrk       48:
                     49: /**
                     50:  * task_create - create a new task.
                     51:  *
                     52:  * The child task will inherit some task states from its parent.
                     53:  *
                     54:  * Inherit status:
                     55:  *   Child data        Inherit from parent ?
                     56:  *   ----------------- ---------------------
                     57:  *   Task name         No
                     58:  *   Object list       No
                     59:  *   Threads           No
1.1.1.1.2.1! nbrk       60:  *   Memory map        New/Copy/Share
1.1       nbrk       61:  *   Suspend count     No
                     62:  *   Exception handler Yes
                     63:  *   Capability        Yes
                     64:  *
1.1.1.1.2.1! nbrk       65:  * vm_option:
        !            66:  *   VM_NEW:   The child task will have clean memory image.
        !            67:  *   VM_SHARE: The child task will share whole memory image with parent.
        !            68:  *   VM_COPY:  The parent's memory image is copied to the child's one.
        !            69:  *             However, the text region and read-only region will be
        !            70:  *             physically shared among them. VM_COPY is supported only
        !            71:  *             with MMU system.
        !            72:  *
        !            73:  * Note: The child task initially contains no threads.
1.1       nbrk       74:  */
                     75: int
                     76: task_create(task_t parent, int vm_option, task_t *child)
                     77: {
                     78:        task_t task;
                     79:        vm_map_t map = NULL;
                     80:        int err = 0;
                     81:
                     82:        switch (vm_option) {
                     83:        case VM_NEW:
                     84:        case VM_SHARE:
                     85: #ifdef CONFIG_MMU
                     86:        case VM_COPY:
                     87: #endif
                     88:                break;
                     89:        default:
                     90:                return EINVAL;
                     91:        }
                     92:        sched_lock();
                     93:        if (!task_valid(parent)) {
                     94:                err = ESRCH;
                     95:                goto out;
                     96:        }
                     97:        if (cur_task() != &kern_task) {
1.1.1.1.2.1! nbrk       98:                if (!task_access(parent)) {
1.1       nbrk       99:                        err = EPERM;
                    100:                        goto out;
                    101:                }
                    102:                /*
1.1.1.1.2.1! nbrk      103:                 * Set zero as child task id before copying
        !           104:                 * parent's memory space. So, the child task
        !           105:                 * can identify whether it is a child.
1.1       nbrk      106:                 */
                    107:                task = 0;
1.1.1.1.2.1! nbrk      108:                if (umem_copyout(&task, child, sizeof(task))) {
1.1       nbrk      109:                        err = EFAULT;
                    110:                        goto out;
                    111:                }
                    112:        }
                    113:
                    114:        if ((task = kmem_alloc(sizeof(struct task))) == NULL) {
                    115:                err = ENOMEM;
                    116:                goto out;
                    117:        }
                    118:        memset(task, 0, sizeof(struct task));
                    119:
                    120:        /*
                    121:         * Setup VM mapping.
                    122:         */
                    123:        switch (vm_option) {
                    124:        case VM_NEW:
                    125:                map = vm_create();
                    126:                break;
                    127:        case VM_SHARE:
                    128:                vm_reference(parent->map);
                    129:                map = parent->map;
                    130:                break;
                    131:        case VM_COPY:
                    132:                map = vm_fork(parent->map);
                    133:                break;
1.1.1.1.2.1! nbrk      134:        default:
        !           135:                /* DO NOTHING */
        !           136:                break;
1.1       nbrk      137:        }
                    138:        if (map == NULL) {
                    139:                kmem_free(task);
                    140:                err = ENOMEM;
                    141:                goto out;
                    142:        }
1.1.1.1.2.1! nbrk      143:
1.1       nbrk      144:        /*
                    145:         * Fill initial task data.
                    146:         */
                    147:        task->map = map;
1.1.1.1.2.1! nbrk      148:        task->handler = parent->handler;
1.1       nbrk      149:        task->capability = parent->capability;
                    150:        task->parent = parent;
                    151:        task->magic = TASK_MAGIC;
                    152:        list_init(&task->objects);
                    153:        list_init(&task->threads);
                    154:        list_insert(&kern_task.link, &task->link);
                    155:
                    156:        if (cur_task() == &kern_task)
                    157:                *child = task;
                    158:        else
1.1.1.1.2.1! nbrk      159:                err = umem_copyout(&task, child, sizeof(task));
1.1       nbrk      160:  out:
                    161:        sched_unlock();
                    162:        return err;
                    163: }
                    164:
                    165: /*
                    166:  * Terminate the specified task.
                    167:  */
                    168: int
                    169: task_terminate(task_t task)
                    170: {
                    171:        int err = 0;
                    172:        list_t head, n;
                    173:        thread_t th;
                    174:        object_t obj;
                    175:
                    176:        sched_lock();
                    177:        if (!task_valid(task)) {
                    178:                sched_unlock();
                    179:                return ESRCH;
                    180:        }
                    181:        if (!task_access(task)) {
                    182:                sched_unlock();
                    183:                return EPERM;
                    184:        }
                    185:
                    186:        /* Invalidate the task. */
                    187:        task->magic = 0;
                    188:
                    189:        /*
                    190:         * Terminate all threads except a current thread.
                    191:         */
                    192:        head = &task->threads;
                    193:        for (n = list_first(head); n != head; n = list_next(n)) {
                    194:                th = list_entry(n, struct thread, task_link);
                    195:                if (th != cur_thread)
                    196:                        thread_terminate(th);
                    197:        }
                    198:        /*
                    199:         * Delete all objects owned by the target task.
                    200:         */
                    201:        head = &task->objects;
                    202:        for (n = list_first(head); n != head; n = list_next(n)) {
                    203:                /*
1.1.1.1.2.1! nbrk      204:                 * A current task may not have the right to
        !           205:                 * delete target objects. So, we set the owner
        !           206:                 * of the object to the current task before
        !           207:                 * deleting it.
1.1       nbrk      208:                 */
                    209:                obj = list_entry(n, struct object, task_link);
                    210:                obj->owner = cur_task();
                    211:                object_destroy(obj);
                    212:        }
                    213:        /*
                    214:         * Release all other task related resources.
                    215:         */
1.1.1.1.2.1! nbrk      216:        timer_stop(&task->alarm);
1.1       nbrk      217:        vm_terminate(task->map);
                    218:        list_remove(&task->link);
                    219:        kmem_free(task);
                    220:
                    221:        if (task == cur_task()) {
                    222:                cur_thread->task = NULL;
                    223:                thread_terminate(cur_thread);
                    224:        }
                    225:        sched_unlock();
                    226:        return err;
                    227: }
                    228:
                    229: task_t
                    230: task_self(void)
                    231: {
                    232:
                    233:        return cur_task();
                    234: }
                    235:
                    236: /*
                    237:  * Suspend a task.
                    238:  */
                    239: int
                    240: task_suspend(task_t task)
                    241: {
                    242:        list_t head, n;
                    243:        thread_t th;
                    244:
                    245:        sched_lock();
                    246:        if (!task_valid(task)) {
1.1.1.1.2.1! nbrk      247:                sched_unlock();
        !           248:                return ESRCH;
        !           249:        }
        !           250:        if (!task_access(task)) {
        !           251:                sched_unlock();
        !           252:                return EPERM;
        !           253:        }
        !           254:
        !           255:        if (++task->suscnt == 1) {
1.1       nbrk      256:                /*
                    257:                 * Suspend all threads within the task.
                    258:                 */
                    259:                head = &task->threads;
                    260:                for (n = list_first(head); n != head; n = list_next(n)) {
                    261:                        th = list_entry(n, struct thread, task_link);
                    262:                        thread_suspend(th);
                    263:                }
                    264:        }
                    265:        sched_unlock();
1.1.1.1.2.1! nbrk      266:        return 0;
1.1       nbrk      267: }
                    268:
                    269: /*
                    270:  * Resume a task.
                    271:  *
                    272:  * A thread in the task will begin to run only when both
                    273:  * thread suspend count and task suspend count become 0.
                    274:  */
                    275: int
                    276: task_resume(task_t task)
                    277: {
                    278:        list_t head, n;
                    279:        thread_t th;
                    280:        int err = 0;
                    281:
                    282:        ASSERT(task != cur_task());
                    283:
                    284:        sched_lock();
                    285:        if (!task_valid(task)) {
                    286:                err = ESRCH;
1.1.1.1.2.1! nbrk      287:                goto out;
        !           288:        }
        !           289:        if (!task_access(task)) {
1.1       nbrk      290:                err = EPERM;
1.1.1.1.2.1! nbrk      291:                goto out;
        !           292:        }
        !           293:        if (task->suscnt == 0) {
1.1       nbrk      294:                err = EINVAL;
1.1.1.1.2.1! nbrk      295:                goto out;
        !           296:        }
        !           297:        if (--task->suscnt == 0) {
1.1       nbrk      298:                /*
                    299:                 * Resume all threads in the target task.
                    300:                 */
                    301:                head = &task->threads;
                    302:                for (n = list_first(head); n != head; n = list_next(n)) {
                    303:                        th = list_entry(n, struct thread, task_link);
                    304:                        thread_resume(th);
                    305:                }
                    306:        }
1.1.1.1.2.1! nbrk      307:  out:
1.1       nbrk      308:        sched_unlock();
                    309:        return err;
                    310: }
                    311:
                    312: /*
                    313:  * Set task name.
                    314:  *
                    315:  * The naming service is separated from task_create() because
                    316:  * the task name can be changed at anytime by exec().
                    317:  */
                    318: int
                    319: task_name(task_t task, const char *name)
                    320: {
                    321:        size_t len;
                    322:        int err = 0;
                    323:
                    324:        sched_lock();
                    325:        if (!task_valid(task)) {
                    326:                err = ESRCH;
1.1.1.1.2.1! nbrk      327:                goto out;
        !           328:        }
        !           329:        if (!task_access(task)) {
1.1       nbrk      330:                err = EPERM;
1.1.1.1.2.1! nbrk      331:                goto out;
        !           332:        }
        !           333:        if (cur_task() == &kern_task) {
        !           334:                strlcpy(task->name, name, MAXTASKNAME);
1.1       nbrk      335:        } else {
1.1.1.1.2.1! nbrk      336:                if (umem_strnlen(name, MAXTASKNAME, &len))
        !           337:                        err = EFAULT;
        !           338:                else if (len >= MAXTASKNAME)
        !           339:                        err = ENAMETOOLONG;
        !           340:                else
        !           341:                        err = umem_copyin(name, task->name, len + 1);
1.1       nbrk      342:        }
1.1.1.1.2.1! nbrk      343:  out:
1.1       nbrk      344:        sched_unlock();
                    345:        return err;
                    346: }
                    347:
                    348: /*
                    349:  * Get the capability of the specified task.
                    350:  */
                    351: int
                    352: task_getcap(task_t task, cap_t *cap)
                    353: {
1.1.1.1.2.1! nbrk      354:        cap_t curcap;
1.1       nbrk      355:
                    356:        sched_lock();
                    357:        if (!task_valid(task)) {
                    358:                sched_unlock();
                    359:                return ESRCH;
                    360:        }
1.1.1.1.2.1! nbrk      361:        curcap = task->capability;
1.1       nbrk      362:        sched_unlock();
                    363:
1.1.1.1.2.1! nbrk      364:        return umem_copyout(&curcap, cap, sizeof(cap_t));
1.1       nbrk      365: }
                    366:
                    367: /*
                    368:  * Set the capability of the specified task.
                    369:  */
                    370: int
                    371: task_setcap(task_t task, cap_t *cap)
                    372: {
1.1.1.1.2.1! nbrk      373:        cap_t newcap;
1.1       nbrk      374:
                    375:        if (!task_capable(CAP_SETPCAP))
                    376:                return EPERM;
                    377:
                    378:        sched_lock();
                    379:        if (!task_valid(task)) {
1.1.1.1.2.1! nbrk      380:                sched_unlock();
        !           381:                return ESRCH;
        !           382:        }
        !           383:        if (umem_copyin(cap, &newcap, sizeof(cap_t))) {
        !           384:                sched_unlock();
        !           385:                return EFAULT;
1.1       nbrk      386:        }
1.1.1.1.2.1! nbrk      387:        task->capability = newcap;
1.1       nbrk      388:        sched_unlock();
1.1.1.1.2.1! nbrk      389:        return 0;
1.1       nbrk      390: }
                    391:
                    392: /*
                    393:  * Check if the current task can access the specified task.
1.1.1.1.2.1! nbrk      394:  * Return true on success, or false on error.
1.1       nbrk      395:  */
                    396: int
                    397: task_access(task_t task)
                    398: {
                    399:
1.1.1.1.2.1! nbrk      400:        if (task == &kern_task)
        !           401:                return 0;
        !           402:        else {
        !           403:                if (task == cur_task() ||
        !           404:                    task->parent == cur_task() ||
        !           405:                    task_capable(CAP_TASK))
        !           406:                        return 1;
        !           407:        }
        !           408:        return 0;
1.1       nbrk      409: }
                    410:
                    411: /*
                    412:  * Create and setup boot tasks.
                    413:  */
                    414: void
                    415: task_bootstrap(void)
                    416: {
1.1.1.1.2.1! nbrk      417:        struct module *mod;
1.1       nbrk      418:        task_t task;
                    419:        thread_t th;
                    420:        void *stack;
1.1.1.1.2.1! nbrk      421:        vaddr_t sp;
1.1       nbrk      422:        int i;
                    423:
1.1.1.1.2.1! nbrk      424:        mod = &boot_info->tasks[0];
        !           425:        for (i = 0; i < boot_info->nr_tasks; i++) {
1.1       nbrk      426:                /*
                    427:                 * Create a new task.
                    428:                 */
                    429:                if (task_create(&kern_task, VM_NEW, &task))
                    430:                        break;
1.1.1.1.2.1! nbrk      431:                task_name(task, mod->name);
        !           432:                if (vm_load(task->map, mod, &stack))
1.1       nbrk      433:                        break;
                    434:
                    435:                /*
                    436:                 * Create and start a new thread.
                    437:                 */
                    438:                if (thread_create(task, &th))
                    439:                        break;
1.1.1.1.2.1! nbrk      440:                sp = (vaddr_t)stack + USTACK_SIZE - (sizeof(int) * 3);
        !           441:                if (thread_load(th, (void (*)(void))mod->entry, (void *)sp))
1.1       nbrk      442:                        break;
                    443:                thread_resume(th);
1.1.1.1.2.1! nbrk      444:
        !           445:                mod++;
1.1       nbrk      446:        }
                    447:        if (i != boot_info->nr_tasks)
1.1.1.1.2.1! nbrk      448:                panic("task_bootstrap: unable to load boot task");
1.1       nbrk      449: }
                    450:
1.1.1.1.2.1! nbrk      451: #ifdef DEBUG
1.1       nbrk      452: void
                    453: task_dump(void)
                    454: {
                    455:        list_t i, j;
                    456:        task_t task;
1.1.1.1.2.1! nbrk      457:        int nthreads;
1.1       nbrk      458:
1.1.1.1.2.1! nbrk      459:        printf("\nTask dump:\n");
        !           460:        printf(" mod task      nthrds susp exc hdlr cap      name\n");
        !           461:        printf(" --- --------- ------ ---- -------- -------- ------------\n");
1.1       nbrk      462:        i = &kern_task.link;
                    463:        do {
                    464:                task = list_entry(i, struct task, link);
                    465:                nthreads = 0;
1.1.1.1.2.1! nbrk      466:                j = list_first(&task->threads);
1.1       nbrk      467:                do {
                    468:                        nthreads++;
                    469:                        j = list_next(j);
                    470:                } while (j != &task->threads);
                    471:
1.1.1.1.2.1! nbrk      472:                printf(" %s %08x%c    %3d %4d %08x %08x %s\n",
        !           473:                       (task == &kern_task) ? "Knl" : "Usr", task,
        !           474:                       (task == cur_task()) ? '*' : ' ', nthreads,
        !           475:                       task->suscnt, task->handler, task->capability,
        !           476:                       task->name != NULL ? task->name : "no name");
1.1       nbrk      477:
                    478:                i = list_next(i);
                    479:        } while (i != &kern_task.link);
                    480: }
                    481: #endif
                    482:
1.1.1.1.2.1! nbrk      483: /*
        !           484:  * We assume the VM mapping of a kernel task has already
        !           485:  * been initialized in vm_init().
        !           486:  */
1.1       nbrk      487: void
                    488: task_init(void)
                    489: {
                    490:        /*
1.1.1.1.2.1! nbrk      491:         * Create a kernel task as the first task.
1.1       nbrk      492:         */
                    493:        strlcpy(kern_task.name, "kernel", MAXTASKNAME);
                    494:        list_init(&kern_task.link);
                    495:        list_init(&kern_task.objects);
                    496:        list_init(&kern_task.threads);
                    497:        kern_task.capability = 0xffffffff;
                    498:        kern_task.magic = TASK_MAGIC;
                    499: }

CVSweb