|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/sys/kern/task.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /*- 2 * Copyright (c) 2005-2009, 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 <sync.h> 40 #include <vm.h> 41 #include <exception.h> 42 #include <task.h> 43 #include <hal.h> 44 #include <sys/bootinfo.h> 45 46 struct task kernel_task; /* kernel task */ 47 static struct list task_list; /* list for all tasks */ 48 static int ntasks; /* number of tasks in system */ 49 50 /** 51 * task_create - create a new task. 52 * 53 * vm_option: 54 * VM_NEW: The child task will have fresh memory image. 55 * VM_SHARE: The child task will share whole memory image with parent. 56 * VM_COPY: The parent's memory image is copied to the child's one. 57 * VM_COPY is supported only with MMU system. 58 * 59 * Note: The child task initially contains no threads. 60 */ 61 int 62 task_create(task_t parent, int vm_option, task_t *childp) 63 { 64 struct task *task; 65 vm_map_t map = NULL; 66 67 ASSERT(parent != NULL); 68 69 switch (vm_option) { 70 case VM_NEW: 71 case VM_SHARE: 72 #ifdef CONFIG_MMU 73 case VM_COPY: 74 #endif 75 break; 76 default: 77 return EINVAL; 78 } 79 if (ntasks >= MAXTASKS) 80 return EAGAIN; 81 82 sched_lock(); 83 if (!task_valid(parent)) { 84 sched_unlock(); 85 return ESRCH; 86 } 87 if ((curtask->flags & TF_SYSTEM) == 0) { 88 if (!task_access(parent)) { 89 sched_unlock(); 90 return EPERM; 91 } 92 /* 93 * It's important to set zero as task id before 94 * copying parent's memory space. Otherwise, we 95 * have to switch VM space to copy it. 96 */ 97 task = 0; 98 if (copyout(&task, childp, sizeof(task))) { 99 sched_unlock(); 100 return EFAULT; 101 } 102 } 103 104 if ((task = kmem_alloc(sizeof(*task))) == NULL) { 105 sched_unlock(); 106 return ENOMEM; 107 } 108 memset(task, 0, sizeof(*task)); 109 110 /* 111 * Setup VM mapping. 112 */ 113 switch (vm_option) { 114 case VM_NEW: 115 map = vm_create(); 116 break; 117 case VM_SHARE: 118 vm_reference(parent->map); 119 map = parent->map; 120 break; 121 case VM_COPY: 122 map = vm_dup(parent->map); 123 break; 124 } 125 if (map == NULL) { 126 kmem_free(task); 127 sched_unlock(); 128 return ENOMEM; 129 } 130 131 /* 132 * Fill initial task data. 133 */ 134 task->map = map; 135 task->handler = parent->handler; 136 task->capability = parent->capability; 137 task->parent = parent; 138 task->flags = TF_DEFAULT; 139 strlcpy(task->name, "*noname", MAXTASKNAME); 140 list_init(&task->threads); 141 list_init(&task->objects); 142 list_init(&task->mutexes); 143 list_init(&task->conds); 144 list_init(&task->sems); 145 list_insert(&task_list, &task->link); 146 ntasks++; 147 148 if (curtask->flags & TF_SYSTEM) 149 *childp = task; 150 else { 151 /* 152 * No page fault here because we have already 153 * checked it. 154 */ 155 copyout(&task, childp, sizeof(task)); 156 } 157 158 sched_unlock(); 159 return 0; 160 } 161 162 /* 163 * Terminate the specified task. 164 */ 165 int 166 task_terminate(task_t task) 167 { 168 list_t head, n; 169 thread_t t; 170 171 sched_lock(); 172 if (!task_valid(task)) { 173 sched_unlock(); 174 return ESRCH; 175 } 176 if (!task_access(task)) { 177 sched_unlock(); 178 return EPERM; 179 } 180 181 list_remove(&task->link); 182 task->handler = EXC_DFL; 183 184 /* 185 * Clean up all resources owned by the target task. 186 */ 187 timer_stop(&task->alarm); 188 object_cleanup(task); 189 mutex_cleanup(task); 190 cond_cleanup(task); 191 sem_cleanup(task); 192 193 /* 194 * Terminate each thread in the task. 195 */ 196 head = &task->threads; 197 for (n = list_first(head); n != head; n = list_next(n)) { 198 t = list_entry(n, struct thread, task_link); 199 if (t != curthread) 200 thread_destroy(t); 201 } 202 if (task == curtask) 203 thread_destroy(curthread); 204 205 vm_terminate(task->map); 206 task->map = NULL; 207 kmem_free(task); 208 ntasks--; 209 sched_unlock(); 210 return 0; 211 } 212 213 /* 214 * Return the current task. 215 */ 216 task_t 217 task_self(void) 218 { 219 220 return curthread->task; 221 } 222 223 /* 224 * Suspend a task. 225 */ 226 int 227 task_suspend(task_t task) 228 { 229 list_t head, n; 230 thread_t t; 231 232 sched_lock(); 233 if (!task_valid(task)) { 234 sched_unlock(); 235 return ESRCH; 236 } 237 if (!task_access(task)) { 238 sched_unlock(); 239 return EPERM; 240 } 241 242 if (++task->suscnt == 1) { 243 /* 244 * Suspend all threads within the task. 245 */ 246 head = &task->threads; 247 for (n = list_first(head); n != head; n = list_next(n)) { 248 t = list_entry(n, struct thread, task_link); 249 thread_suspend(t); 250 } 251 } 252 sched_unlock(); 253 return 0; 254 } 255 256 /* 257 * Resume a task. 258 * 259 * A thread in the task will begin to run only when both 260 * thread suspend count and task suspend count become 0. 261 */ 262 int 263 task_resume(task_t task) 264 { 265 list_t head, n; 266 thread_t t; 267 268 ASSERT(task != curtask); 269 270 sched_lock(); 271 if (!task_valid(task)) { 272 sched_unlock(); 273 return ESRCH; 274 } 275 if (!task_access(task)) { 276 sched_unlock(); 277 return EPERM; 278 } 279 if (task->suscnt == 0) { 280 sched_unlock(); 281 return EINVAL; 282 } 283 284 if (--task->suscnt == 0) { 285 /* 286 * Resume all threads in the target task. 287 */ 288 head = &task->threads; 289 for (n = list_first(head); n != head; n = list_next(n)) { 290 t = list_entry(n, struct thread, task_link); 291 thread_resume(t); 292 } 293 } 294 sched_unlock(); 295 return 0; 296 } 297 298 /* 299 * Set task name. 300 * 301 * The naming service is separated from task_create() because 302 * the task name can be changed at anytime by exec(). 303 */ 304 int 305 task_setname(task_t task, const char *name) 306 { 307 char str[MAXTASKNAME]; 308 int error; 309 310 sched_lock(); 311 if (!task_valid(task)) { 312 sched_unlock(); 313 return ESRCH; 314 } 315 if (!task_access(task)) { 316 sched_unlock(); 317 return EPERM; 318 } 319 320 if (curtask->flags & TF_SYSTEM) 321 strlcpy(task->name, name, MAXTASKNAME); 322 else { 323 error = copyinstr(name, str, MAXTASKNAME); 324 if (error) { 325 sched_unlock(); 326 return error; 327 } 328 strlcpy(task->name, str, MAXTASKNAME); 329 } 330 sched_unlock(); 331 return 0; 332 } 333 334 /* 335 * Set the capability of the specified task. 336 */ 337 int 338 task_setcap(task_t task, cap_t cap) 339 { 340 341 if (!task_capable(CAP_SETPCAP)) 342 return EPERM; 343 344 sched_lock(); 345 if (!task_valid(task)) { 346 sched_unlock(); 347 return ESRCH; 348 } 349 if (!task_access(task)) { 350 sched_unlock(); 351 return EPERM; 352 } 353 task->capability = cap; 354 sched_unlock(); 355 return 0; 356 } 357 358 /* 359 * task_chkcap - system call to check task capability. 360 */ 361 int 362 task_chkcap(task_t task, cap_t cap) 363 { 364 int error = 0; 365 366 sched_lock(); 367 if (!task_valid(task)) { 368 sched_unlock(); 369 return ESRCH; 370 } 371 if ((task->capability & cap) == 0) { 372 DPRINTF(("Denying capability by %s: task=%s cap=%08x\n", 373 curtask->name, task->name, cap)); 374 if (task->flags & TF_AUDIT) 375 panic("audit failed"); 376 error = EPERM; 377 } 378 sched_unlock(); 379 return error; 380 } 381 382 /* 383 * Check if the current task has specified capability. 384 * Returns true on success, or false on error. 385 */ 386 int 387 task_capable(cap_t cap) 388 { 389 int capable = 1; 390 391 if ((curtask->capability & cap) == 0) { 392 DPRINTF(("Denying capability by kernel: task=%s cap=%08x\n", 393 curtask->name, cap)); 394 if (curtask->flags & TF_AUDIT) 395 panic("audit failed"); 396 capable = 0; 397 } 398 return capable; 399 } 400 401 /* 402 * Return true if the specified task is valid. 403 */ 404 int 405 task_valid(task_t task) 406 { 407 task_t tmp; 408 list_t n; 409 410 for (n = list_first(&task_list); n != &task_list; n = list_next(n)) { 411 tmp = list_entry(n, struct task, link); 412 if (tmp == task) 413 return 1; 414 } 415 return 0; 416 } 417 418 /* 419 * Check if the current task can access the specified task. 420 * Return true on success, or false on error. 421 */ 422 int 423 task_access(task_t task) 424 { 425 426 if (task->flags & TF_SYSTEM) { 427 /* Do not access the kernel task. */ 428 return 0; 429 } else { 430 if (task == curtask || task->parent == curtask || 431 task == curtask->parent || /* XXX: fork on nommu */ 432 task_capable(CAP_TASKCTRL)) 433 return 1; 434 } 435 return 0; 436 } 437 438 int 439 task_info(struct taskinfo *info) 440 { 441 u_long target = info->cookie; 442 u_long i = 0; 443 task_t task; 444 list_t n; 445 446 sched_lock(); 447 n = list_first(&task_list); 448 do { 449 if (i++ == target) { 450 task = list_entry(n, struct task, link); 451 info->cookie = i; 452 info->id = task; 453 info->flags = task->flags; 454 info->suscnt = task->suscnt; 455 info->capability = task->capability; 456 info->vmsize = task->map->total; 457 info->nthreads = task->nthreads; 458 info->active = (task == curtask) ? 1 : 0; 459 strlcpy(info->taskname, task->name, MAXTASKNAME); 460 sched_unlock(); 461 return 0; 462 } 463 n = list_next(n); 464 } while (n != &task_list); 465 sched_unlock(); 466 return ESRCH; 467 } 468 469 /* 470 * Create and setup boot tasks. 471 */ 472 void 473 task_bootstrap(void) 474 { 475 struct module *mod; 476 struct bootinfo *bi; 477 task_t task; 478 thread_t t; 479 void *stack, *sp; 480 int i, error = 0; 481 482 machine_bootinfo(&bi); 483 mod = &bi->tasks[0]; 484 485 for (i = 0; i < bi->nr_tasks; i++) { 486 /* 487 * Create a new task. 488 */ 489 if ((error = task_create(&kernel_task, VM_NEW, &task)) != 0) 490 break; 491 if ((error = vm_load(task->map, mod, &stack)) != 0) 492 break; 493 task_setname(task, mod->name); 494 495 /* 496 * Set the default capability. 497 * We give CAP_SETPCAP to the exec server. 498 */ 499 task->capability = CAPSET_BOOT; 500 if (!strncmp(task->name, "exec", MAXTASKNAME)) 501 task->capability |= CAP_SETPCAP; 502 503 /* 504 * Create and start a new thread. 505 */ 506 if ((error = thread_create(task, &t)) != 0) 507 break; 508 sp = (char *)stack + DFLSTKSZ - (sizeof(int) * 3); 509 error = thread_load(t, (void (*)(void))mod->entry, sp); 510 if (error) 511 break; 512 t->priority = PRI_REALTIME; 513 t->basepri = PRI_REALTIME; 514 thread_resume(t); 515 516 mod++; 517 } 518 if (error) { 519 DPRINTF(("task_bootstrap: error=%d\n", error)); 520 panic("unable to load boot task"); 521 } 522 } 523 524 /* 525 * Initialize task. 526 */ 527 void 528 task_init(void) 529 { 530 531 list_init(&task_list); 532 533 /* 534 * Create a kernel task as first task. 535 */ 536 strlcpy(kernel_task.name, "kernel", MAXTASKNAME); 537 kernel_task.flags = TF_SYSTEM; 538 kernel_task.nthreads = 0; 539 list_init(&kernel_task.threads); 540 list_init(&kernel_task.objects); 541 list_init(&kernel_task.mutexes); 542 list_init(&kernel_task.conds); 543 list_init(&kernel_task.sems); 544 545 list_insert(&task_list, &kernel_task.link); 546 ntasks = 1; 547 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |