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

Annotation of prex/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/Copy/Share
        !            61:  *   Suspend count     No
        !            62:  *   Exception handler Yes
        !            63:  *   Capability        Yes
        !            64:  *
        !            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.
        !            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) {
        !            98:                if (!task_access(parent)) {
        !            99:                        err = EPERM;
        !           100:                        goto out;
        !           101:                }
        !           102:                /*
        !           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.
        !           106:                 */
        !           107:                task = 0;
        !           108:                if (umem_copyout(&task, child, sizeof(task))) {
        !           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;
        !           134:        default:
        !           135:                /* DO NOTHING */
        !           136:                break;
        !           137:        }
        !           138:        if (map == NULL) {
        !           139:                kmem_free(task);
        !           140:                err = ENOMEM;
        !           141:                goto out;
        !           142:        }
        !           143:
        !           144:        /*
        !           145:         * Fill initial task data.
        !           146:         */
        !           147:        task->map = map;
        !           148:        task->handler = parent->handler;
        !           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
        !           159:                err = umem_copyout(&task, child, sizeof(task));
        !           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:                /*
        !           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.
        !           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:         */
        !           216:        timer_stop(&task->alarm);
        !           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)) {
        !           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) {
        !           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();
        !           266:        return 0;
        !           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;
        !           287:                goto out;
        !           288:        }
        !           289:        if (!task_access(task)) {
        !           290:                err = EPERM;
        !           291:                goto out;
        !           292:        }
        !           293:        if (task->suscnt == 0) {
        !           294:                err = EINVAL;
        !           295:                goto out;
        !           296:        }
        !           297:        if (--task->suscnt == 0) {
        !           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:        }
        !           307:  out:
        !           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;
        !           327:                goto out;
        !           328:        }
        !           329:        if (!task_access(task)) {
        !           330:                err = EPERM;
        !           331:                goto out;
        !           332:        }
        !           333:        if (cur_task() == &kern_task) {
        !           334:                strlcpy(task->name, name, MAXTASKNAME);
        !           335:        } else {
        !           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);
        !           342:        }
        !           343:  out:
        !           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: {
        !           354:        cap_t curcap;
        !           355:
        !           356:        sched_lock();
        !           357:        if (!task_valid(task)) {
        !           358:                sched_unlock();
        !           359:                return ESRCH;
        !           360:        }
        !           361:        curcap = task->capability;
        !           362:        sched_unlock();
        !           363:
        !           364:        return umem_copyout(&curcap, cap, sizeof(cap_t));
        !           365: }
        !           366:
        !           367: /*
        !           368:  * Set the capability of the specified task.
        !           369:  */
        !           370: int
        !           371: task_setcap(task_t task, cap_t *cap)
        !           372: {
        !           373:        cap_t newcap;
        !           374:
        !           375:        if (!task_capable(CAP_SETPCAP))
        !           376:                return EPERM;
        !           377:
        !           378:        sched_lock();
        !           379:        if (!task_valid(task)) {
        !           380:                sched_unlock();
        !           381:                return ESRCH;
        !           382:        }
        !           383:        if (umem_copyin(cap, &newcap, sizeof(cap_t))) {
        !           384:                sched_unlock();
        !           385:                return EFAULT;
        !           386:        }
        !           387:        task->capability = newcap;
        !           388:        sched_unlock();
        !           389:        return 0;
        !           390: }
        !           391:
        !           392: /*
        !           393:  * Check if the current task can access the specified task.
        !           394:  * Return true on success, or false on error.
        !           395:  */
        !           396: int
        !           397: task_access(task_t task)
        !           398: {
        !           399:
        !           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;
        !           409: }
        !           410:
        !           411: /*
        !           412:  * Create and setup boot tasks.
        !           413:  */
        !           414: void
        !           415: task_bootstrap(void)
        !           416: {
        !           417:        struct module *mod;
        !           418:        task_t task;
        !           419:        thread_t th;
        !           420:        void *stack;
        !           421:        vaddr_t sp;
        !           422:        int i;
        !           423:
        !           424:        mod = &boot_info->tasks[0];
        !           425:        for (i = 0; i < boot_info->nr_tasks; i++) {
        !           426:                /*
        !           427:                 * Create a new task.
        !           428:                 */
        !           429:                if (task_create(&kern_task, VM_NEW, &task))
        !           430:                        break;
        !           431:                task_name(task, mod->name);
        !           432:                if (vm_load(task->map, mod, &stack))
        !           433:                        break;
        !           434:
        !           435:                /*
        !           436:                 * Create and start a new thread.
        !           437:                 */
        !           438:                if (thread_create(task, &th))
        !           439:                        break;
        !           440:                sp = (vaddr_t)stack + USTACK_SIZE - (sizeof(int) * 3);
        !           441:                if (thread_load(th, (void (*)(void))mod->entry, (void *)sp))
        !           442:                        break;
        !           443:                thread_resume(th);
        !           444:
        !           445:                mod++;
        !           446:        }
        !           447:        if (i != boot_info->nr_tasks)
        !           448:                panic("task_bootstrap: unable to load boot task");
        !           449: }
        !           450:
        !           451: #ifdef DEBUG
        !           452: void
        !           453: task_dump(void)
        !           454: {
        !           455:        list_t i, j;
        !           456:        task_t task;
        !           457:        int nthreads;
        !           458:
        !           459:        printf("\nTask dump:\n");
        !           460:        printf(" mod task      nthrds susp exc hdlr cap      name\n");
        !           461:        printf(" --- --------- ------ ---- -------- -------- ------------\n");
        !           462:        i = &kern_task.link;
        !           463:        do {
        !           464:                task = list_entry(i, struct task, link);
        !           465:                nthreads = 0;
        !           466:                j = list_first(&task->threads);
        !           467:                do {
        !           468:                        nthreads++;
        !           469:                        j = list_next(j);
        !           470:                } while (j != &task->threads);
        !           471:
        !           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");
        !           477:
        !           478:                i = list_next(i);
        !           479:        } while (i != &kern_task.link);
        !           480: }
        !           481: #endif
        !           482:
        !           483: /*
        !           484:  * We assume the VM mapping of a kernel task has already
        !           485:  * been initialized in vm_init().
        !           486:  */
        !           487: void
        !           488: task_init(void)
        !           489: {
        !           490:        /*
        !           491:         * Create a kernel task as the first task.
        !           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