[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

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:  */
                     47: struct task kern_task;
                     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
                     60:  *   Memory map        New/Duplicate/Share
                     61:  *   Suspend count     No
                     62:  *   Exception handler Yes
                     63:  *   Capability        Yes
                     64:  *
                     65:  * If vm_option is VM_COPY, the child task will have the same memory
                     66:  * image with the parent task. Especially, text region and read-only
                     67:  * region are physically shared among them. VM_COPY is supported only
                     68:  * with MMU system.
                     69:  * The child task initially contains no threads.
                     70:  */
                     71: int
                     72: task_create(task_t parent, int vm_option, task_t *child)
                     73: {
                     74:        task_t task;
                     75:        vm_map_t map = NULL;
                     76:        int err = 0;
                     77:
                     78:        switch (vm_option) {
                     79:        case VM_NEW:
                     80:        case VM_SHARE:
                     81: #ifdef CONFIG_MMU
                     82:        case VM_COPY:
                     83: #endif
                     84:                break;
                     85:        default:
                     86:                return EINVAL;
                     87:        }
                     88:        sched_lock();
                     89:        if (!task_valid(parent)) {
                     90:                err = ESRCH;
                     91:                goto out;
                     92:        }
                     93:        if (cur_task() != &kern_task) {
                     94:                if(!task_access(parent)) {
                     95:                        err = EPERM;
                     96:                        goto out;
                     97:                }
                     98:                /*
                     99:                 * Set zero as child task id before copying parent's
                    100:                 * memory space. So, the child task can identify
                    101:                 * whether it is a child.
                    102:                 */
                    103:                task = 0;
                    104:                if (umem_copyout(&task, child, sizeof(task_t))) {
                    105:                        err = EFAULT;
                    106:                        goto out;
                    107:                }
                    108:        }
                    109:
                    110:        if ((task = kmem_alloc(sizeof(struct task))) == NULL) {
                    111:                err = ENOMEM;
                    112:                goto out;
                    113:        }
                    114:        memset(task, 0, sizeof(struct task));
                    115:
                    116:        /*
                    117:         * Setup VM mapping.
                    118:         */
                    119:        switch (vm_option) {
                    120:        case VM_NEW:
                    121:                map = vm_create();
                    122:                break;
                    123:        case VM_SHARE:
                    124:                vm_reference(parent->map);
                    125:                map = parent->map;
                    126:                break;
                    127:        case VM_COPY:
                    128:                map = vm_fork(parent->map);
                    129:                break;
                    130:        }
                    131:        if (map == NULL) {
                    132:                kmem_free(task);
                    133:                err = ENOMEM;
                    134:                goto out;
                    135:        }
                    136:        /*
                    137:         * Fill initial task data.
                    138:         */
                    139:        task->map = map;
                    140:        task->exc_handler = parent->exc_handler;
                    141:        task->capability = parent->capability;
                    142:        task->parent = parent;
                    143:        task->magic = TASK_MAGIC;
                    144:        list_init(&task->objects);
                    145:        list_init(&task->threads);
                    146:        list_insert(&kern_task.link, &task->link);
                    147:
                    148:        if (cur_task() == &kern_task)
                    149:                *child = task;
                    150:        else
                    151:                err = umem_copyout(&task, child, sizeof(task_t));
                    152:  out:
                    153:        sched_unlock();
                    154:        return err;
                    155: }
                    156:
                    157: /*
                    158:  * Terminate the specified task.
                    159:  */
                    160: int
                    161: task_terminate(task_t task)
                    162: {
                    163:        int err = 0;
                    164:        list_t head, n;
                    165:        thread_t th;
                    166:        object_t obj;
                    167:
                    168:        sched_lock();
                    169:        if (!task_valid(task)) {
                    170:                sched_unlock();
                    171:                return ESRCH;
                    172:        }
                    173:        if (!task_access(task)) {
                    174:                sched_unlock();
                    175:                return EPERM;
                    176:        }
                    177:
                    178:        /* Invalidate the task. */
                    179:        task->magic = 0;
                    180:
                    181:        /*
                    182:         * Terminate all threads except a current thread.
                    183:         */
                    184:        head = &task->threads;
                    185:        for (n = list_first(head); n != head; n = list_next(n)) {
                    186:                th = list_entry(n, struct thread, task_link);
                    187:                if (th != cur_thread)
                    188:                        thread_terminate(th);
                    189:        }
                    190:        /*
                    191:         * Delete all objects owned by the target task.
                    192:         */
                    193:        head = &task->objects;
                    194:        for (n = list_first(head); n != head; n = list_next(n)) {
                    195:                /*
                    196:                 * A current task may not have the right to delete
                    197:                 * target objects. So, we set the owner of the object
                    198:                 * to the current task before deleting it.
                    199:                 */
                    200:                obj = list_entry(n, struct object, task_link);
                    201:                obj->owner = cur_task();
                    202:                object_destroy(obj);
                    203:        }
                    204:        /*
                    205:         * Release all other task related resources.
                    206:         */
                    207:        vm_terminate(task->map);
                    208:        list_remove(&task->link);
                    209:        kmem_free(task);
                    210:
                    211:        if (task == cur_task()) {
                    212:                cur_thread->task = NULL;
                    213:                thread_terminate(cur_thread);
                    214:        }
                    215:        sched_unlock();
                    216:        return err;
                    217: }
                    218:
                    219: task_t
                    220: task_self(void)
                    221: {
                    222:
                    223:        return cur_task();
                    224: }
                    225:
                    226: /*
                    227:  * Suspend a task.
                    228:  */
                    229: int
                    230: task_suspend(task_t task)
                    231: {
                    232:        list_t head, n;
                    233:        thread_t th;
                    234:        int err = 0;
                    235:
                    236:        sched_lock();
                    237:        if (!task_valid(task)) {
                    238:                err = ESRCH;
                    239:        } else if (!task_access(task)) {
                    240:                err = EPERM;
                    241:        } else if (++task->suspend_count == 1) {
                    242:                /*
                    243:                 * Suspend all threads within the task.
                    244:                 */
                    245:                head = &task->threads;
                    246:                for (n = list_first(head); n != head; n = list_next(n)) {
                    247:                        th = list_entry(n, struct thread, task_link);
                    248:                        thread_suspend(th);
                    249:                }
                    250:        }
                    251:        sched_unlock();
                    252:        return err;
                    253: }
                    254:
                    255: /*
                    256:  * Resume a task.
                    257:  *
                    258:  * A thread in the task will begin to run only when both
                    259:  * thread suspend count and task suspend count become 0.
                    260:  */
                    261: int
                    262: task_resume(task_t task)
                    263: {
                    264:        list_t head, n;
                    265:        thread_t th;
                    266:        int err = 0;
                    267:
                    268:        ASSERT(task != cur_task());
                    269:
                    270:        sched_lock();
                    271:        if (!task_valid(task)) {
                    272:                err = ESRCH;
                    273:        } else if (!task_access(task)) {
                    274:                err = EPERM;
                    275:        } else if (task->suspend_count == 0) {
                    276:                err = EINVAL;
                    277:        } else if (--task->suspend_count == 0) {
                    278:                /*
                    279:                 * Resume all threads in the target task.
                    280:                 */
                    281:                head = &task->threads;
                    282:                for (n = list_first(head); n != head; n = list_next(n)) {
                    283:                        th = list_entry(n, struct thread, task_link);
                    284:                        thread_resume(th);
                    285:                }
                    286:        }
                    287:        sched_unlock();
                    288:        return err;
                    289: }
                    290:
                    291: /*
                    292:  * Set task name.
                    293:  *
                    294:  * The naming service is separated from task_create() because
                    295:  * the task name can be changed at anytime by exec().
                    296:  */
                    297: int
                    298: task_name(task_t task, const char *name)
                    299: {
                    300:        size_t len;
                    301:        int err = 0;
                    302:
                    303:        sched_lock();
                    304:        if (!task_valid(task)) {
                    305:                err = ESRCH;
                    306:        } else if (!task_access(task)) {
                    307:                err = EPERM;
                    308:        } else {
                    309:                if (cur_task() == &kern_task)
                    310:                        strlcpy(task->name, name, MAXTASKNAME);
                    311:                else {
                    312:                        if (umem_strnlen(name, MAXTASKNAME, &len))
                    313:                                err = EFAULT;
                    314:                        else if (len >= MAXTASKNAME)
                    315:                                err = ENAMETOOLONG;
                    316:                        else
                    317:                                err = umem_copyin((void *)name, task->name,
                    318:                                                  len + 1);
                    319:                }
                    320:        }
                    321:        sched_unlock();
                    322:        return err;
                    323: }
                    324:
                    325: /*
                    326:  * Get the capability of the specified task.
                    327:  */
                    328: int
                    329: task_getcap(task_t task, cap_t *cap)
                    330: {
                    331:        cap_t cur_cap;
                    332:
                    333:        sched_lock();
                    334:        if (!task_valid(task)) {
                    335:                sched_unlock();
                    336:                return ESRCH;
                    337:        }
                    338:        cur_cap = task->capability;
                    339:        sched_unlock();
                    340:
                    341:        return umem_copyout(&cur_cap, cap, sizeof(cap_t));
                    342: }
                    343:
                    344: /*
                    345:  * Set the capability of the specified task.
                    346:  */
                    347: int
                    348: task_setcap(task_t task, cap_t *cap)
                    349: {
                    350:        cap_t new_cap;
                    351:        int err = 0;
                    352:
                    353:        if (!task_capable(CAP_SETPCAP))
                    354:                return EPERM;
                    355:
                    356:        sched_lock();
                    357:        if (!task_valid(task)) {
                    358:                err = ESRCH;
                    359:        } else if (umem_copyin(cap, &new_cap, sizeof(cap_t))) {
                    360:                err = EFAULT;
                    361:        } else {
                    362:                task->capability = new_cap;
                    363:        }
                    364:        sched_unlock();
                    365:        return err;
                    366: }
                    367:
                    368: /*
                    369:  * Check if the current task can access the specified task.
                    370:  */
                    371: int
                    372: task_access(task_t task)
                    373: {
                    374:
                    375:        return (task != &kern_task &&
                    376:                (task == cur_task() || task->parent == cur_task() ||
                    377:                 task_capable(CAP_TASK)));
                    378: }
                    379:
                    380: /*
                    381:  * Create and setup boot tasks.
                    382:  */
                    383: void
                    384: task_bootstrap(void)
                    385: {
                    386:        struct module *m;
                    387:        task_t task;
                    388:        thread_t th;
                    389:        void *stack;
                    390:        int i;
                    391:
                    392:        m = &boot_info->tasks[0];
                    393:        for (i = 0; i < boot_info->nr_tasks; i++, m++) {
                    394:                /*
                    395:                 * Create a new task.
                    396:                 */
                    397:                if (task_create(&kern_task, VM_NEW, &task))
                    398:                        break;
                    399:                task_name(task, m->name);
                    400:                if (vm_load(task->map, m, &stack))
                    401:                        break;
                    402:
                    403:                /*
                    404:                 * Create and start a new thread.
                    405:                 */
                    406:                if (thread_create(task, &th))
                    407:                        break;
                    408:                stack = (void *)((u_long)stack + USTACK_SIZE - sizeof(int));
                    409:                if (thread_load(th, (void (*)(void))m->entry, stack))
                    410:                        break;
                    411:                thread_resume(th);
                    412:        }
                    413:        if (i != boot_info->nr_tasks)
                    414:                panic("task_boot");
                    415: }
                    416:
                    417: #if defined(DEBUG) && defined(CONFIG_KDUMP)
                    418: void
                    419: task_dump(void)
                    420: {
                    421:        list_t i, j;
                    422:        task_t task;
                    423:        int nobjs, nthreads;
                    424:
                    425:        printk("Task dump:\n");
                    426:        printk(" mod task      nobjs  nthrds vm map   susp exc hdlr "
                    427:               "cap      name\n");
                    428:        printk(" --- --------- ------ ------ -------- ---- -------- "
                    429:               "-------- ------------\n");
                    430:
                    431:        i = &kern_task.link;
                    432:        do {
                    433:                task = list_entry(i, struct task, link);
                    434:
                    435:                nthreads = 0;
                    436:                j = &task->threads;
                    437:                j = list_next(j);
                    438:                do {
                    439:                        nthreads++;
                    440:                        j = list_next(j);
                    441:                } while (j != &task->threads);
                    442:
                    443:                nobjs = 0;
                    444:                j = &task->objects;
                    445:                j = list_next(j);
                    446:                do {
                    447:                        nobjs++;
                    448:                        j = list_next(j);
                    449:                } while (j != &task->objects);
                    450:
                    451:                printk(" %s %08x%c    %3d    %3d %08x %4d %08x %08x %s\n",
                    452:                       (task == &kern_task) ? "Knl" : "Usr",
                    453:                       task, (task == cur_task()) ? '*' : ' ', nobjs,
                    454:                       nthreads, task->map, task->suspend_count,
                    455:                       task->exc_handler, task->capability,
                    456:                       task->name ? task->name : "no name");
                    457:
                    458:                i = list_next(i);
                    459:        } while (i != &kern_task.link);
                    460: }
                    461:
                    462: void
                    463: boot_dump(void)
                    464: {
                    465:        struct module *m;
                    466:        int i;
                    467:
                    468:        printk(" text base data base text size data size bss size   "
                    469:               "task name\n");
                    470:        printk(" --------- --------- --------- --------- ---------- "
                    471:               "----------\n");
                    472:
                    473:        m = &boot_info->tasks[0];
                    474:        for (i = 0; i < boot_info->nr_tasks; i++, m++) {
                    475:                printk("  %8x  %8x  %8d  %8d  %8d  %s\n",
                    476:                       m->text, m->data, m->textsz,
                    477:                       m->datasz, m->bsssz, m->name);
                    478:        }
                    479: }
                    480: #endif
                    481:
                    482: void
                    483: task_init(void)
                    484: {
                    485:        /*
                    486:         * Create a kernel task as a first task in the system.
                    487:         *
                    488:         * Note: We assume the VM mapping for a kernel task has
                    489:         * already been initialized in vm_init().
                    490:         */
                    491:        strlcpy(kern_task.name, "kernel", MAXTASKNAME);
                    492:        list_init(&kern_task.link);
                    493:        list_init(&kern_task.objects);
                    494:        list_init(&kern_task.threads);
                    495:        kern_task.capability = 0xffffffff;
                    496:        kern_task.magic = TASK_MAGIC;
                    497: }

CVSweb