|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/sys/kern/thread.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 * thread.c - thread management routines. 32 */ 33 34 #include <kernel.h> 35 #include <kmem.h> 36 #include <task.h> 37 #include <thread.h> 38 #include <ipc.h> 39 #include <sched.h> 40 #include <sync.h> 41 #include <hal.h> 42 43 /* forward declarations */ 44 static thread_t thread_allocate(task_t); 45 static void thread_deallocate(thread_t); 46 47 static struct thread idle_thread; /* idle thread */ 48 static thread_t zombie; /* zombie thread */ 49 static struct list thread_list; /* list of all threads */ 50 51 /* global variable */ 52 thread_t curthread = &idle_thread; /* current thread */ 53 54 /* 55 * Create a new thread. 56 * 57 * The new thread will start from the return address of 58 * thread_create() in user mode. Since a new thread shares 59 * the user mode stack of the caller thread, the caller is 60 * responsible to allocate and set new stack for it. The new 61 * thread is initially set to suspend state, and so, 62 * thread_resume() must be called to start it. 63 */ 64 int 65 thread_create(task_t task, thread_t *tp) 66 { 67 thread_t t; 68 vaddr_t sp; 69 70 sched_lock(); 71 72 if (!task_valid(task)) { 73 sched_unlock(); 74 return ESRCH; 75 } 76 if (!task_access(task)) { 77 sched_unlock(); 78 return EPERM; 79 } 80 if (task->nthreads >= MAXTHREADS) { 81 sched_unlock(); 82 return EAGAIN; 83 } 84 /* 85 * We check the pointer to the return value here. 86 * This will simplify the error recoveries of the 87 * subsequent code. 88 */ 89 if ((curtask->flags & TF_SYSTEM) == 0) { 90 t = NULL; 91 if (copyout(&t, tp, sizeof(t))) { 92 sched_unlock(); 93 return EFAULT; 94 } 95 } 96 /* 97 * Make thread entry for new thread. 98 */ 99 if ((t = thread_allocate(task)) == NULL) { 100 DPRINTF(("Out of text\n")); 101 sched_unlock(); 102 return ENOMEM; 103 } 104 memcpy(t->kstack, curthread->kstack, KSTACKSZ); 105 sp = (vaddr_t)t->kstack + KSTACKSZ; 106 context_set(&t->ctx, CTX_KSTACK, (register_t)sp); 107 context_set(&t->ctx, CTX_KENTRY, (register_t)&syscall_ret); 108 sched_start(t, curthread->basepri, SCHED_RR); 109 t->suscnt = task->suscnt + 1; 110 111 /* 112 * No page fault here: 113 */ 114 if (curtask->flags & TF_SYSTEM) 115 *tp = t; 116 else 117 copyout(&t, tp, sizeof(t)); 118 119 sched_unlock(); 120 return 0; 121 } 122 123 /* 124 * Permanently stop execution of the specified thread. 125 * If given thread is a current thread, this routine 126 * never returns. 127 */ 128 int 129 thread_terminate(thread_t t) 130 { 131 132 sched_lock(); 133 if (!thread_valid(t)) { 134 sched_unlock(); 135 return ESRCH; 136 } 137 if (!task_access(t->task)) { 138 sched_unlock(); 139 return EPERM; 140 } 141 thread_destroy(t); 142 sched_unlock(); 143 return 0; 144 } 145 146 /* 147 * thread_destroy-- the internal version of thread_terminate. 148 */ 149 void 150 thread_destroy(thread_t th) 151 { 152 153 msg_cancel(th); 154 mutex_cancel(th); 155 timer_cancel(th); 156 sched_stop(th); 157 thread_deallocate(th); 158 } 159 160 /* 161 * Load entry/stack address of the user mode context. 162 * 163 * If the entry or stack address is NULL, we keep the 164 * old value for it. 165 */ 166 int 167 thread_load(thread_t t, void (*entry)(void), void *stack) 168 { 169 int s; 170 171 if (entry != NULL && !user_area(entry)) 172 return EINVAL; 173 if (stack != NULL && !user_area(stack)) 174 return EINVAL; 175 176 sched_lock(); 177 178 if (!thread_valid(t)) { 179 sched_unlock(); 180 return ESRCH; 181 } 182 if (!task_access(t->task)) { 183 sched_unlock(); 184 return EPERM; 185 } 186 s = splhigh(); 187 if (entry != NULL) 188 context_set(&t->ctx, CTX_UENTRY, (register_t)entry); 189 if (stack != NULL) 190 context_set(&t->ctx, CTX_USTACK, (register_t)stack); 191 splx(s); 192 193 sched_unlock(); 194 return 0; 195 } 196 197 /* 198 * Return the current thread. 199 */ 200 thread_t 201 thread_self(void) 202 { 203 204 return curthread; 205 } 206 207 /* 208 * Return true if specified thread is valid. 209 */ 210 int 211 thread_valid(thread_t t) 212 { 213 list_t head, n; 214 thread_t tmp; 215 216 head = &thread_list; 217 for (n = list_first(head); n != head; n = list_next(n)) { 218 tmp = list_entry(n, struct thread, link); 219 if (tmp == t) 220 return 1; 221 } 222 return 0; 223 } 224 225 /* 226 * Release a current thread for other thread. 227 */ 228 void 229 thread_yield(void) 230 { 231 232 sched_yield(); 233 } 234 235 /* 236 * Suspend thread. 237 * 238 * A thread can be suspended any number of times. 239 * And, it does not start to run again unless the thread 240 * is resumed by the same count of suspend request. 241 */ 242 int 243 thread_suspend(thread_t t) 244 { 245 246 sched_lock(); 247 if (!thread_valid(t)) { 248 sched_unlock(); 249 return ESRCH; 250 } 251 if (!task_access(t->task)) { 252 sched_unlock(); 253 return EPERM; 254 } 255 if (++t->suscnt == 1) 256 sched_suspend(t); 257 258 sched_unlock(); 259 return 0; 260 } 261 262 /* 263 * Resume thread. 264 * 265 * A thread does not begin to run, unless both thread 266 * suspend count and task suspend count are set to 0. 267 */ 268 int 269 thread_resume(thread_t t) 270 { 271 272 ASSERT(t != curthread); 273 274 sched_lock(); 275 if (!thread_valid(t)) { 276 sched_unlock(); 277 return ESRCH; 278 } 279 if (!task_access(t->task)) { 280 sched_unlock(); 281 return EPERM; 282 } 283 if (t->suscnt == 0) { 284 sched_unlock(); 285 return EINVAL; 286 } 287 t->suscnt--; 288 if (t->suscnt == 0 && t->task->suscnt == 0) 289 sched_resume(t); 290 291 sched_unlock(); 292 return 0; 293 } 294 295 /* 296 * thread_schedparam - get/set scheduling parameter. 297 */ 298 int 299 thread_schedparam(thread_t t, int op, int *param) 300 { 301 int pri, policy; 302 int error = 0; 303 304 sched_lock(); 305 if (!thread_valid(t)) { 306 sched_unlock(); 307 return ESRCH; 308 } 309 if (t->task->flags & TF_SYSTEM) { 310 sched_unlock(); 311 return EINVAL; 312 } 313 /* 314 * A thread can change the scheduling parameters of the 315 * threads in the same task or threads in the child task. 316 */ 317 if (!(t->task == curtask || t->task->parent == curtask) && 318 !task_capable(CAP_NICE)) { 319 sched_unlock(); 320 return EPERM; 321 } 322 323 switch (op) { 324 case SOP_GETPRI: 325 pri = sched_getpri(t); 326 if (copyout(&pri, param, sizeof(pri))) 327 error = EINVAL; 328 break; 329 330 case SOP_SETPRI: 331 if (copyin(param, &pri, sizeof(pri))) { 332 error = EINVAL; 333 break; 334 } 335 /* 336 * Validate the priority range. 337 */ 338 if (pri < 0) 339 pri = 0; 340 else if (pri >= PRI_IDLE) 341 pri = PRI_IDLE - 1; 342 343 /* 344 * If the caller has CAP_NICE capability, it can 345 * change the thread priority to any level. 346 * Otherwise, the caller can not set the priority 347 * to higher above realtime priority. 348 */ 349 if (pri <= PRI_REALTIME && !task_capable(CAP_NICE)) { 350 error = EPERM; 351 break; 352 } 353 /* 354 * If a current priority is inherited for mutex, 355 * we can not change the priority to lower value. 356 * In this case, only the base priority is changed, 357 * and a current priority will be adjusted to 358 * correct value, later. 359 */ 360 if (t->priority != t->basepri && pri > t->priority) 361 pri = t->priority; 362 363 mutex_setpri(t, pri); 364 sched_setpri(t, pri, pri); 365 break; 366 367 case SOP_GETPOLICY: 368 policy = sched_getpolicy(t); 369 if (copyout(&policy, param, sizeof(policy))) 370 error = EINVAL; 371 break; 372 373 case SOP_SETPOLICY: 374 if (copyin(param, &policy, sizeof(policy))) { 375 error = EINVAL; 376 break; 377 } 378 error = sched_setpolicy(t, policy); 379 break; 380 381 default: 382 error = EINVAL; 383 break; 384 } 385 sched_unlock(); 386 return error; 387 } 388 389 /* 390 * Idle thread. 391 * 392 * Put the system into low power mode until we get an 393 * interrupt. Then, we try to release the current thread to 394 * run the thread who was woken by ISR. This routine is 395 * called only once after kernel initialization is completed. 396 */ 397 void 398 thread_idle(void) 399 { 400 401 for (;;) { 402 machine_idle(); 403 sched_yield(); 404 } 405 } 406 407 /* 408 * Allocate a thread. 409 */ 410 static thread_t 411 thread_allocate(task_t task) 412 { 413 struct thread *t; 414 void *stack; 415 416 if ((t = kmem_alloc(sizeof(*t))) == NULL) 417 return NULL; 418 419 if ((stack = kmem_alloc(KSTACKSZ)) == NULL) { 420 kmem_free(t); 421 return NULL; 422 } 423 memset(t, 0, sizeof(*t)); 424 425 t->kstack = stack; 426 t->task = task; 427 list_init(&t->mutexes); 428 list_insert(&thread_list, &t->link); 429 list_insert(&task->threads, &t->task_link); 430 task->nthreads++; 431 432 return t; 433 } 434 435 /* 436 * Deallocate a thread. 437 * 438 * We can not release the context of the "current" thread 439 * because our thread switching always requires the current 440 * context. So, the resource deallocation is deferred until 441 * another thread calls thread_deallocate() later. 442 */ 443 static void 444 thread_deallocate(thread_t t) 445 { 446 447 list_remove(&t->task_link); 448 list_remove(&t->link); 449 t->excbits = 0; 450 t->task->nthreads--; 451 452 if (zombie != NULL) { 453 /* 454 * Deallocate a zombie thread which 455 * was killed in previous request. 456 */ 457 ASSERT(zombie != curthread); 458 kmem_free(zombie->kstack); 459 zombie->kstack = NULL; 460 kmem_free(zombie); 461 zombie = NULL; 462 } 463 if (t == curthread) { 464 /* 465 * Enter zombie state and wait for 466 * somebody to be killed us. 467 */ 468 zombie = t; 469 return; 470 } 471 472 kmem_free(t->kstack); 473 t->kstack = NULL; 474 kmem_free(t); 475 } 476 477 /* 478 * Return thread information. 479 */ 480 int 481 thread_info(struct threadinfo *info) 482 { 483 u_long target = info->cookie; 484 u_long i = 0; 485 thread_t t; 486 list_t n; 487 488 sched_lock(); 489 n = list_last(&thread_list); 490 do { 491 if (i++ == target) { 492 t = list_entry(n, struct thread, link); 493 info->cookie = i; 494 info->id = t; 495 info->state = t->state; 496 info->policy = t->policy; 497 info->priority = t->priority; 498 info->basepri = t->basepri; 499 info->time = t->time; 500 info->suscnt = t->suscnt; 501 info->task = t->task; 502 info->active = (t == curthread) ? 1 : 0; 503 strlcpy(info->taskname, t->task->name, MAXTASKNAME); 504 strlcpy(info->slpevt, t->slpevt ? 505 t->slpevt->name : "-", MAXEVTNAME); 506 sched_unlock(); 507 return 0; 508 } 509 n = list_prev(n); 510 } while (n != &thread_list); 511 sched_unlock(); 512 return ESRCH; 513 } 514 515 /* 516 * Create a thread running in the kernel address space. 517 * 518 * Since we disable an interrupt during thread switching, the 519 * interrupt is still disabled at the entry of the kernel 520 * thread. So, the kernel thread must enable interrupts 521 * immediately when it gets control. 522 * This routine assumes the scheduler is already locked. 523 */ 524 thread_t 525 kthread_create(void (*entry)(void *), void *arg, int pri) 526 { 527 thread_t t; 528 vaddr_t sp; 529 530 ASSERT(curthread->locks > 0); 531 532 /* 533 * If there is not enough core for the new thread, 534 * the caller should just drop to panic(). 535 */ 536 if ((t = thread_allocate(&kernel_task)) == NULL) 537 return NULL; 538 539 memset(t->kstack, 0, KSTACKSZ); 540 sp = (vaddr_t)t->kstack + KSTACKSZ; 541 context_set(&t->ctx, CTX_KSTACK, (register_t)sp); 542 context_set(&t->ctx, CTX_KENTRY, (register_t)entry); 543 context_set(&t->ctx, CTX_KARG, (register_t)arg); 544 sched_start(t, pri, SCHED_FIFO); 545 t->suscnt = 1; 546 sched_resume(t); 547 548 return t; 549 } 550 551 /* 552 * Terminate a kernel thread. 553 */ 554 void 555 kthread_terminate(thread_t t) 556 { 557 ASSERT(t != NULL); 558 ASSERT(t->task->flags & TF_SYSTEM); 559 560 sched_lock(); 561 562 mutex_cancel(t); 563 timer_cancel(t); 564 sched_stop(t); 565 thread_deallocate(t); 566 567 sched_unlock(); 568 } 569 570 /* 571 * The first thread in the system is created here by hand. 572 * This thread will become an idle thread when thread_idle() 573 * is called later in main(). 574 */ 575 void 576 thread_init(void) 577 { 578 void *stack; 579 vaddr_t sp; 580 581 list_init(&thread_list); 582 583 if ((stack = kmem_alloc(KSTACKSZ)) == NULL) 584 panic("thread_init"); 585 586 memset(stack, 0, KSTACKSZ); 587 sp = (vaddr_t)stack + KSTACKSZ; 588 context_set(&idle_thread.ctx, CTX_KSTACK, (register_t)sp); 589 sched_start(&idle_thread, PRI_IDLE, SCHED_FIFO); 590 idle_thread.kstack = stack; 591 idle_thread.task = &kernel_task; 592 idle_thread.state = TS_RUN; 593 idle_thread.locks = 1; 594 list_init(&idle_thread.mutexes); 595 596 list_insert(&thread_list, &idle_thread.link); 597 list_insert(&kernel_task.threads, &idle_thread.task_link); 598 kernel_task.nthreads = 1; 599 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |