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