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