[BACK]Return to thread.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / kern

Annotation of prex-old/sys/kern/thread.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:  * 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 <system.h>
                     42:
                     43: struct thread idle_thread;
                     44: thread_t cur_thread = &idle_thread;
                     45: static thread_t zombie;
                     46:
                     47: /*
                     48:  * Allocate a new thread and attach kernel stack for it.
                     49:  * Returns thread pointer on success, or NULL on failure.
                     50:  */
                     51: static thread_t
                     52: thread_alloc(void)
                     53: {
                     54:        thread_t th;
                     55:        void *stack;
                     56:
                     57:        if ((th = kmem_alloc(sizeof(struct thread))) == NULL)
                     58:                return NULL;
                     59:        memset(th, 0, sizeof(struct thread));
                     60:
                     61:        if ((stack = kmem_alloc(KSTACK_SIZE)) == NULL) {
                     62:                kmem_free(th);
                     63:                return NULL;
                     64:        }
                     65:        th->kstack = stack;
                     66:        th->magic = THREAD_MAGIC;
                     67:        list_init(&th->mutexes);
                     68:        return th;
                     69: }
                     70:
                     71: static void
                     72: thread_free(thread_t th)
                     73: {
                     74:
                     75:        kmem_free(th->kstack);
                     76:        kmem_free(th);
                     77: }
                     78:
                     79: /*
                     80:  * Create a new thread within the specified task.
                     81:  *
                     82:  * The context of a current thread will be copied to the new thread.
                     83:  * The new thread will start from the return address of thread_create()
                     84:  * call in user mode code. Since a new thread will share the user
                     85:  * mode stack with a current thread, user mode applications are
                     86:  * responsible to allocate stack for it. The new thread is initially
                     87:  * set to suspend state, and so, thread_resume() must be called to
                     88:  * start it.
                     89:  *
                     90:  * The following scheduling parameters are reset to default values
                     91:  * in the created thread.
                     92:  *  - Thread State
                     93:  *  - Scheduling Policy
                     94:  *  - Scheduling Priority
                     95:  */
                     96: int
                     97: thread_create(task_t task, thread_t *thp)
                     98: {
                     99:        thread_t th;
                    100:        int err = 0;
                    101:
                    102:        sched_lock();
                    103:        if (!task_valid(task)) {
                    104:                err = ESRCH;
                    105:                goto out;
                    106:        }
                    107:        if (!task_access(task)) {
                    108:                err = EPERM;
                    109:                goto out;
                    110:        }
                    111:        if ((th = thread_alloc()) == NULL) {
                    112:                err = ENOMEM;
                    113:                goto out;
                    114:        }
                    115:        /*
                    116:         * At first, we copy a new thread id as return value.
                    117:         * This is done here to simplify all error recoveries
                    118:         * of the subsequent code.
                    119:         */
                    120:        if (cur_task() == &kern_task)
                    121:                *thp = th;
                    122:        else {
                    123:                if (umem_copyout(&th, thp, sizeof(thread_t))) {
                    124:                        thread_free(th);
                    125:                        err = EFAULT;
                    126:                        goto out;
                    127:                }
                    128:        }
                    129:        /*
                    130:         * Initialize thread state.
                    131:         */
                    132:        th->task = task;
                    133:        th->suspend_count = task->suspend_count + 1;
                    134:        memcpy(th->kstack, cur_thread->kstack, KSTACK_SIZE);
                    135:        context_init(&th->context, (u_long)th->kstack + KSTACK_SIZE);
                    136:        list_insert(&task->threads, &th->task_link);
                    137:        sched_start(th);
                    138:  out:
                    139:        sched_unlock();
                    140:        return err;
                    141: }
                    142:
                    143: /*
                    144:  * Permanently stop execution of the specified thread.
                    145:  * If given thread is a current thread, this routine never returns.
                    146:  */
                    147: int
                    148: thread_terminate(thread_t th)
                    149: {
                    150:        int err;
                    151:
                    152:        sched_lock();
                    153:        if (!thread_valid(th)) {
                    154:                err = ESRCH;
                    155:        } else if (!task_access(th->task)) {
                    156:                err = EPERM;
                    157:        } else {
                    158:                err = thread_kill(th);
                    159:        }
                    160:        sched_unlock();
                    161:        return err;
                    162: }
                    163:
                    164: /*
                    165:  * Kill a thread regardless of the current task state.
                    166:  *
                    167:  * This may be used to terminate a kernel thread under the non-context
                    168:  * condition. For example, a device driver may terminate its interrupt
                    169:  * thread even if a current task does not have the capability to
                    170:  * terminate it.
                    171:  */
                    172: int
                    173: thread_kill(thread_t th)
                    174: {
                    175:        /*
                    176:         * Clean up thread state.
                    177:         */
                    178:        msg_cleanup(th);
                    179:        timer_cleanup(th);
                    180:        mutex_cleanup(th);
                    181:        list_remove(&th->task_link);
                    182:        sched_stop(th);
                    183:        th->exc_bitmap = 0;
                    184:        th->magic = 0;
                    185:
                    186:        /*
                    187:         * We can not release the context of the "current" thread
                    188:         * because our thread switching always requires the current
                    189:         * context. So, the resource deallocation is deferred until
                    190:         * another thread calls thread_kill().
                    191:         */
                    192:        if (zombie != NULL) {
                    193:                /*
                    194:                 * Deallocate a zombie thread which was killed
                    195:                 * in previous request.
                    196:                 */
                    197:                ASSERT(zombie != cur_thread);
                    198:                thread_free(zombie);
                    199:                zombie = NULL;
                    200:        }
                    201:        if (th == cur_thread) {
                    202:                /*
                    203:                 * If the current thread is being terminated,
                    204:                 * enter zombie state and wait for sombody
                    205:                 * to be killed us.
                    206:                 */
                    207:                zombie = th;
                    208:        } else
                    209:                thread_free(th);
                    210:        return 0;
                    211: }
                    212:
                    213: /*
                    214:  * Load entry/stack address of the user mode context.
                    215:  *
                    216:  * The entry and stack address can be set to NULL.
                    217:  * If it is NULL, old state is just kept.
                    218:  */
                    219: int
                    220: thread_load(thread_t th, void (*entry)(void), void *stack)
                    221: {
                    222:        int err = 0;
                    223:
                    224:        if ((entry != NULL && !user_area(entry)) ||
                    225:            (stack != NULL && !user_area(stack)))
                    226:                return EINVAL;
                    227:
                    228:        sched_lock();
                    229:        if (!thread_valid(th)) {
                    230:                err = ESRCH;
                    231:        } else if (!task_access(th->task)) {
                    232:                err = EPERM;
                    233:        } else {
                    234:                if (entry != NULL)
                    235:                        context_set(&th->context, CTX_UENTRY, (u_long)entry);
                    236:                if (stack != NULL)
                    237:                        context_set(&th->context, CTX_USTACK, (u_long)stack);
                    238:        }
                    239:        sched_unlock();
                    240:        return 0;
                    241: }
                    242:
                    243: thread_t
                    244: thread_self(void)
                    245: {
                    246:
                    247:        return cur_thread;
                    248: }
                    249:
                    250: /*
                    251:  * Release current thread for other thread.
                    252:  */
                    253: void
                    254: thread_yield(void)
                    255: {
                    256:
                    257:        sched_yield();
                    258: }
                    259:
                    260: /*
                    261:  * Suspend thread.
                    262:  *
                    263:  * A thread can be suspended any number of times. And, it does
                    264:  * not start to run again unless the thread is resumed by the
                    265:  * same count of suspend request.
                    266:  */
                    267: int
                    268: thread_suspend(thread_t th)
                    269: {
                    270:        int err = 0;
                    271:
                    272:        sched_lock();
                    273:        if (!thread_valid(th)) {
                    274:                err = ESRCH;
                    275:        } else if (!task_access(th->task)) {
                    276:                err = EPERM;
                    277:        } else {
                    278:                if (++th->suspend_count == 1)
                    279:                        sched_suspend(th);
                    280:        }
                    281:        sched_unlock();
                    282:        return 0;
                    283: }
                    284:
                    285: /*
                    286:  * Resume thread.
                    287:  *
                    288:  * A thread does not begin to run, unless both thread
                    289:  * suspend count and task suspend count are set to 0.
                    290:  */
                    291: int
                    292: thread_resume(thread_t th)
                    293: {
                    294:        int err = 0;
                    295:
                    296:        ASSERT(th != cur_thread);
                    297:
                    298:        sched_lock();
                    299:        if (!thread_valid(th)) {
                    300:                err = ESRCH;
                    301:        } else if (!task_access(th->task)) {
                    302:                err= EPERM;
                    303:        } else if (th->suspend_count == 0) {
                    304:                err = EINVAL;
                    305:        } else {
                    306:                th->suspend_count--;
                    307:                if (th->suspend_count == 0 && th->task->suspend_count == 0)
                    308:                        sched_resume(th);
                    309:        }
                    310:        sched_unlock();
                    311:        return err;
                    312: }
                    313:
                    314: /*
                    315:  * thread_schedparam - get/set scheduling parameter.
                    316:  * @th:    target thread
                    317:  * @op:    operation ID
                    318:  * @param: pointer to parameter
                    319:  *
                    320:  * If the caller has CAP_NICE capability, all operations are allowed.
                    321:  * Otherwise, the caller can change the parameter for the threads in
                    322:  * the same task, and it can not set the priority to higher value.
                    323:  */
                    324: int
                    325: thread_schedparam(thread_t th, int op, int *param)
                    326: {
                    327:        int prio, policy, err = 0;
                    328:        int capable = 0;
                    329:
                    330:        sched_lock();
                    331:        if (!thread_valid(th)) {
                    332:                sched_unlock();
                    333:                return ESRCH;
                    334:        }
                    335:        if (task_capable(CAP_NICE))
                    336:                capable = 1;
                    337:
                    338:        if (th->task != cur_task() && !capable) {
                    339:                sched_unlock();
                    340:                return EPERM;
                    341:        }
                    342:        if ((th->task == &kern_task) &&
                    343:            (op == OP_SETPRIO || op == OP_SETPOLICY)) {
                    344:                sched_unlock();
                    345:                return EPERM;
                    346:        }
                    347:        switch (op) {
                    348:        case OP_GETPRIO:
                    349:                prio = sched_getprio(th);
                    350:                err = umem_copyout(&prio, param, sizeof(int));
                    351:                break;
                    352:        case OP_SETPRIO:
                    353:                if ((err = umem_copyin(param, &prio, sizeof(int))))
                    354:                        break;
                    355:                if (prio < 0)
                    356:                        prio = 0;
                    357:                else if (prio >= PRIO_IDLE)
                    358:                        prio = PRIO_IDLE - 1;
                    359:
                    360:                if (prio < th->prio && !capable) {
                    361:                        err = EPERM;
                    362:                        break;
                    363:                }
                    364:                /*
                    365:                 * If a current priority is inherited for mutex,
                    366:                 * we can not change the priority to lower value.
                    367:                 * In this case, only the base priority is changed,
                    368:                 * and a current priority will be adjusted to correct
                    369:                 * value, later.
                    370:                 */
                    371:                if (th->prio != th->base_prio && prio > th->prio)
                    372:                        prio = th->prio;
                    373:
                    374:                mutex_setprio(th, prio);
                    375:                sched_setprio(th, prio, prio);
                    376:                break;
                    377:        case OP_GETPOLICY:
                    378:                policy = sched_getpolicy(th);
                    379:                err = umem_copyout(&policy, param, sizeof(int));
                    380:                break;
                    381:        case OP_SETPOLICY:
                    382:                if ((err = umem_copyin(param, &policy, sizeof(int))))
                    383:                        break;
                    384:                if (sched_setpolicy(th, policy))
                    385:                        err = EINVAL;
                    386:                break;
                    387:        default:
                    388:                err = EINVAL;
                    389:                break;
                    390:        }
                    391:        sched_unlock();
                    392:        return err;
                    393: }
                    394:
                    395: /*
                    396:  * Idle thread.
                    397:  *
                    398:  * This routine is called only once after kernel initialization
                    399:  * is completed. An idle thread has the role of cutting down the power
                    400:  * consumption of a system. An idle thread has FIFO scheduling policy
                    401:  * because it does not have time quantum.
                    402:  */
                    403: void
                    404: thread_idle(void)
                    405: {
                    406:
                    407:        for (;;) {
                    408:                machine_idle();
                    409:                sched_yield();
                    410:        }
                    411:        /* NOTREACHED */
                    412: }
                    413:
                    414: /*
                    415:  * Create a thread running in the kernel address space.
                    416:  *
                    417:  * A kernel thread does not have user mode context, and its
                    418:  * scheduling policy is set to SCHED_FIFO. kernel_thread() returns
                    419:  * thread ID on success, or NULL on failure. We assume scheduler
                    420:  * is already locked.
                    421:  *
                    422:  * Important: Since sched_switch() will disable interrupts in CPU,
                    423:  * the interrupt is always disabled at the entry point of the kernel
                    424:  * thread. So, the kernel thread must enable the interrupt first when
                    425:  * it gets control.
                    426:  */
                    427: thread_t
                    428: kernel_thread(int prio, void (*entry)(u_long), u_long arg)
                    429: {
                    430:        thread_t th;
                    431:
                    432:        if ((th = thread_alloc()) == NULL)
                    433:                return NULL;
                    434:
                    435:        th->task = &kern_task;
                    436:        memset(th->kstack, 0, KSTACK_SIZE);
                    437:        context_init(&th->context, (u_long)th->kstack + KSTACK_SIZE);
                    438:        context_set(&th->context, CTX_KENTRY, (u_long)entry);
                    439:        context_set(&th->context, CTX_KARG, arg);
                    440:        list_insert(&kern_task.threads, &th->task_link);
                    441:
                    442:        sched_start(th);
                    443:        sched_setpolicy(th, SCHED_FIFO);
                    444:        sched_setprio(th, prio, prio);
                    445:        sched_resume(th);
                    446:        return th;
                    447: }
                    448:
                    449: /*
                    450:  * Return thread information for ps command.
                    451:  */
                    452: int
                    453: thread_info(struct info_thread *info)
                    454: {
                    455:        u_long index, target = info->cookie;
                    456:        list_t i, j;
                    457:        thread_t th;
                    458:        task_t task;
                    459:
                    460:        sched_lock();
                    461:        index = 0;
                    462:        i = &kern_task.link;
                    463:        do {
                    464:                task = list_entry(i, struct task, link);
                    465:                j = &task->threads;
                    466:                j = list_first(j);
                    467:                do {
                    468:                        th = list_entry(j, struct thread, task_link);
                    469:                        if (index++ == target)
                    470:                                goto found;
                    471:                        j = list_next(j);
                    472:                } while (j != &task->threads);
                    473:                i = list_next(i);
                    474:        } while (i != &kern_task.link);
                    475:
                    476:        sched_unlock();
                    477:        return ESRCH;
                    478:  found:
                    479:        info->state = th->state;
                    480:        info->policy = th->policy;
                    481:        info->prio = th->prio;
                    482:        info->base_prio = th->base_prio;
                    483:        info->suspend_count = th->suspend_count;
                    484:        info->total_ticks = th->total_ticks;
                    485:        info->id = th;
                    486:        info->task = th->task;
                    487:        strlcpy(info->task_name, task->name, MAXTASKNAME);
                    488:        strlcpy(info->sleep_event,
                    489:                th->sleep_event ? th->sleep_event->name : "-", 12);
                    490:
                    491:        sched_unlock();
                    492:        return 0;
                    493: }
                    494:
                    495: #if defined(DEBUG) && defined(CONFIG_KDUMP)
                    496: void
                    497: thread_dump(void)
                    498: {
                    499:        static const char state[][4] = \
                    500:                { "RUN", "SLP", "SUS", "S&S", "EXT" };
                    501:        static const char pol[][5] = { "FIFO", "RR  " };
                    502:        list_t i, j;
                    503:        thread_t th;
                    504:        task_t task;
                    505:
                    506:        printk("Thread dump:\n");
                    507:        printk(" mod thread   task     stat pol  prio base ticks    "
                    508:               "susp sleep event\n");
                    509:        printk(" --- -------- -------- ---- ---- ---- ---- -------- "
                    510:               "---- ------------\n");
                    511:
                    512:        i = &kern_task.link;
                    513:        do {
                    514:                task = list_entry(i, struct task, link);
                    515:                j = &task->threads;
                    516:                j = list_first(j);
                    517:                do {
                    518:                        th = list_entry(j, struct thread, task_link);
                    519:                        printk(" %s %08x %8s %s%c %s  %3d  %3d %8d %4d %s\n",
                    520:                               (task == &kern_task) ? "Knl" : "Usr", th,
                    521:                               task->name, state[th->state],
                    522:                               (th == cur_thread) ? '*' : ' ',
                    523:                               pol[th->policy], th->prio, th->base_prio,
                    524:                               th->total_ticks, th->suspend_count,
                    525:                               th->sleep_event ? th->sleep_event->name : "-");
                    526:                        j = list_next(j);
                    527:                } while (j != &task->threads);
                    528:                i = list_next(i);
                    529:        } while (i != &kern_task.link);
                    530: }
                    531: #endif
                    532:
                    533: /*
                    534:  * The first thread in system is created here by hand. This thread
                    535:  * will become an idle thread when thread_idle() is called later.
                    536:  */
                    537: void
                    538: thread_init(void)
                    539: {
                    540:        void *stack;
                    541:
                    542:        if ((stack = kmem_alloc(KSTACK_SIZE)) == NULL)
                    543:                panic("thread_init");
                    544:
                    545:        memset(stack, 0, KSTACK_SIZE);
                    546:        idle_thread.kstack = stack;
                    547:        idle_thread.magic = THREAD_MAGIC;
                    548:        idle_thread.task = &kern_task;
                    549:        idle_thread.state = TH_RUN;
                    550:        idle_thread.policy = SCHED_FIFO;
                    551:        idle_thread.prio = PRIO_IDLE;
                    552:        idle_thread.base_prio = PRIO_IDLE;
                    553:        idle_thread.lock_count = 1;
                    554:
                    555:        context_init(&idle_thread.context, (u_long)stack + KSTACK_SIZE);
                    556:        list_insert(&kern_task.threads, &idle_thread.task_link);
                    557: }

CVSweb