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