[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     ! 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