Annotation of prex/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/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