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

Annotation of prex-old/sys/kern/sched.c, Revision 1.1.1.1.2.1

1.1       nbrk        1: /*-
1.1.1.1.2.1! nbrk        2:  * Copyright (c) 2005-2008, Kohsuke Ohtani
1.1       nbrk        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:  * sched.c - scheduler
                     32:  */
                     33:
                     34: /**
                     35:  * General design:
                     36:  *
1.1.1.1.2.1! nbrk       37:  * The Prex scheduler is based on the algorithm known as priority
        !            38:  * based multi level queue. Each thread has its own priority
        !            39:  * assigned between 0 and 255. The lower number means higher
        !            40:  * priority like BSD unix.  The scheduler maintains 256 level run
        !            41:  * queues mapped to each priority.  The lowest priority (=255) is
        !            42:  * used only for an idle thread.
1.1       nbrk       43:  *
                     44:  * All threads have two different types of priorities:
                     45:  *
1.1.1.1.2.1! nbrk       46:  *  Base priority:
        !            47:  *      This is a static priority used for priority computation.
        !            48:  *      A user mode program can change this value via system call.
        !            49:  *
        !            50:  *  Current priority:
        !            51:  *      An actual scheduling priority. A kernel may adjust this
        !            52:  *      priority dynamically if it's needed.
1.1       nbrk       53:  *
                     54:  * Each thread has one of the following state.
                     55:  *
                     56:  *  - TH_RUN     Running or ready to run
                     57:  *  - TH_SLEEP   Sleep for some event
                     58:  *  - TH_SUSPEND Suspend count is not 0
                     59:  *  - TH_EXIT    Terminated
                     60:  *
                     61:  * The thread is always preemptive even in the kernel mode.
                     62:  * There are following 4 reasons to switch thread.
                     63:  *
1.1.1.1.2.1! nbrk       64:  * (1) Block
1.1       nbrk       65:  *      Thread is blocked for sleep or suspend.
                     66:  *      It is put on the tail of the run queue when it becomes
                     67:  *      runnable again.
                     68:  *
1.1.1.1.2.1! nbrk       69:  * (2) Preemption
1.1       nbrk       70:  *      If higher priority thread becomes runnable, the current
1.1.1.1.2.1! nbrk       71:  *      thread is put on the _head_ of the run queue.
1.1       nbrk       72:  *
1.1.1.1.2.1! nbrk       73:  * (3) Quantum expiration
1.1       nbrk       74:  *      If the thread consumes its time quantum, it is put on
                     75:  *      the tail of the run queue.
                     76:  *
1.1.1.1.2.1! nbrk       77:  * (4) Yield
        !            78:  *      If the thread releases CPU by itself, it is put on the
        !            79:  *      tail of the run queue.
1.1       nbrk       80:  *
                     81:  * There are following three types of scheduling policies.
                     82:  *
                     83:  *  - SCHED_FIFO   First in-first-out
                     84:  *  - SCHED_RR     Round robin (SCHED_FIFO + timeslice)
                     85:  *  - SCHED_OTHER  Another scheduling (not supported)
                     86:  */
                     87:
                     88: #include <kernel.h>
                     89: #include <queue.h>
                     90: #include <event.h>
                     91: #include <irq.h>
                     92: #include <thread.h>
                     93: #include <timer.h>
                     94: #include <vm.h>
                     95: #include <task.h>
                     96: #include <system.h>
                     97: #include <sched.h>
                     98:
1.1.1.1.2.1! nbrk       99: static struct queue    runq[NPRIO];    /* run queues */
        !           100: static struct queue    wakeq;          /* queue for waking threads */
        !           101: static struct queue    dpcq;           /* DPC queue */
        !           102: static int             top_prio;       /* highest priority in runq */
        !           103: static struct event    dpc_event;      /* event for DPC */
1.1       nbrk      104:
                    105: /*
                    106:  * Search for highest-priority runnable thread.
                    107:  */
                    108: static int
                    109: runq_top(void)
                    110: {
                    111:        int prio;
                    112:
                    113:        for (prio = 0; prio < MIN_PRIO; prio++)
                    114:                if (!queue_empty(&runq[prio]))
                    115:                        break;
                    116:        return prio;
                    117: }
                    118:
                    119: /*
                    120:  * Put a thread on the tail of the run queue.
                    121:  */
                    122: static void
                    123: runq_enqueue(thread_t th)
                    124: {
                    125:
                    126:        enqueue(&runq[th->prio], &th->link);
                    127:        if (th->prio < top_prio) {
                    128:                top_prio = th->prio;
1.1.1.1.2.1! nbrk      129:                cur_thread->resched = 1;
1.1       nbrk      130:        }
                    131: }
                    132:
                    133: /*
                    134:  * Insert a thread to the head of the run queue.
1.1.1.1.2.1! nbrk      135:  * We assume this routine is called while thread switching.
1.1       nbrk      136:  */
                    137: static void
                    138: runq_insert(thread_t th)
                    139: {
                    140:
                    141:        queue_insert(&runq[th->prio], &th->link);
                    142:        if (th->prio < top_prio)
                    143:                top_prio = th->prio;
                    144: }
                    145:
                    146: /*
1.1.1.1.2.1! nbrk      147:  * Pick up and remove the highest-priority thread
        !           148:  * from the run queue.
1.1       nbrk      149:  */
                    150: static thread_t
                    151: runq_dequeue(void)
                    152: {
                    153:        queue_t q;
                    154:        thread_t th;
                    155:
                    156:        q = dequeue(&runq[top_prio]);
                    157:        th = queue_entry(q, struct thread, link);
                    158:        if (queue_empty(&runq[top_prio]))
                    159:                top_prio = runq_top();
                    160:        return th;
                    161: }
                    162:
                    163: /*
                    164:  * Remove the specified thread from the run queue.
                    165:  */
                    166: static void
                    167: runq_remove(thread_t th)
                    168: {
                    169:
                    170:        queue_remove(&th->link);
                    171:        top_prio = runq_top();
                    172: }
                    173:
                    174: /*
                    175:  * Process all pending woken threads.
                    176:  */
                    177: static void
                    178: wakeq_flush(void)
                    179: {
                    180:        queue_t q;
                    181:        thread_t th;
                    182:
                    183:        while (!queue_empty(&wakeq)) {
                    184:                /*
                    185:                 * Set a thread runnable.
                    186:                 */
                    187:                q = dequeue(&wakeq);
                    188:                th = queue_entry(q, struct thread, link);
1.1.1.1.2.1! nbrk      189:                th->slpevt = NULL;
1.1       nbrk      190:                th->state &= ~TH_SLEEP;
                    191:                if (th != cur_thread && th->state == TH_RUN)
                    192:                        runq_enqueue(th);
                    193:        }
                    194: }
                    195:
                    196: /*
1.1.1.1.2.1! nbrk      197:  * sched_switch - this is the scheduler proper:
1.1       nbrk      198:  *
1.1.1.1.2.1! nbrk      199:  * If the scheduling reason is preemption, the current
        !           200:  * thread will remain at the head of the run queue.  So,
        !           201:  * the thread still has right to run first again among
        !           202:  * the same priority threads. For other scheduling reason,
        !           203:  * the current thread is inserted into the tail of the run
        !           204:  * queue.
1.1       nbrk      205:  */
                    206: static void
                    207: sched_switch(void)
                    208: {
                    209:        thread_t prev, next;
                    210:
1.1.1.1.2.1! nbrk      211:        /*
        !           212:         * Move a current thread to the run queue.
        !           213:         */
1.1       nbrk      214:        prev = cur_thread;
                    215:        if (prev->state == TH_RUN) {
                    216:                if (prev->prio > top_prio)
                    217:                        runq_insert(prev);      /* preemption */
                    218:                else
                    219:                        runq_enqueue(prev);
                    220:        }
1.1.1.1.2.1! nbrk      221:        prev->resched = 0;
1.1       nbrk      222:
                    223:        /*
1.1.1.1.2.1! nbrk      224:         * Select the thread to run the CPU next.
1.1       nbrk      225:         */
                    226:        next = runq_dequeue();
                    227:        if (next == prev)
                    228:                return;
                    229:        cur_thread = next;
                    230:
1.1.1.1.2.1! nbrk      231:        /*
        !           232:         * Switch to the new thread.
        !           233:         * You are expected to understand this..
        !           234:         */
1.1       nbrk      235:        if (prev->task != next->task)
                    236:                vm_switch(next->task->map);
1.1.1.1.2.1! nbrk      237:        context_switch(&prev->ctx, &next->ctx);
1.1       nbrk      238: }
                    239:
                    240: /*
1.1.1.1.2.1! nbrk      241:  * sleep_expire - sleep timer is expired:
1.1       nbrk      242:  *
1.1.1.1.2.1! nbrk      243:  * Wake up the thread which is sleeping in sched_tsleep().
        !           244:  */
        !           245: static void
        !           246: sleep_expire(void *arg)
        !           247: {
        !           248:
        !           249:        sched_unsleep((thread_t)arg, SLP_TIMEOUT);
        !           250: }
        !           251:
        !           252: /*
        !           253:  * sched_tsleep - sleep the current thread until a wakeup
        !           254:  * is performed on the specified event.
1.1       nbrk      255:  *
1.1.1.1.2.1! nbrk      256:  * This routine returns a sleep result. If the thread is
        !           257:  * woken by sched_wakeup() or sched_wakeone(), it returns 0.
        !           258:  * Otherwise, it will return the result value which is passed
        !           259:  * by sched_unsleep().  We allow calling sched_sleep() with
        !           260:  * interrupt disabled.
        !           261:  *
        !           262:  * sched_sleep() is also defined as a wrapper macro for
        !           263:  * sched_tsleep() without timeout. Note that all sleep
        !           264:  * requests are interruptible with this kernel.
1.1       nbrk      265:  */
                    266: int
1.1.1.1.2.1! nbrk      267: sched_tsleep(struct event *evt, u_long msec)
1.1       nbrk      268: {
                    269:
                    270:        ASSERT(irq_level == 0);
                    271:        ASSERT(evt);
                    272:
                    273:        sched_lock();
1.1.1.1.2.1! nbrk      274:        irq_lock();
1.1       nbrk      275:
1.1.1.1.2.1! nbrk      276:        cur_thread->slpevt = evt;
1.1       nbrk      277:        cur_thread->state |= TH_SLEEP;
                    278:        enqueue(&evt->sleepq, &cur_thread->link);
                    279:
1.1.1.1.2.1! nbrk      280:        if (msec != 0) {
        !           281:                /*
        !           282:                 * Program timer to wake us up at timeout.
        !           283:                 */
        !           284:                timer_callout(&cur_thread->timeout, msec, &sleep_expire,
        !           285:                              cur_thread);
1.1       nbrk      286:        }
                    287:        wakeq_flush();
                    288:        sched_switch(); /* Sleep here. Zzzz.. */
                    289:
1.1.1.1.2.1! nbrk      290:        irq_unlock();
1.1       nbrk      291:        sched_unlock();
1.1.1.1.2.1! nbrk      292:        return cur_thread->slpret;
1.1       nbrk      293: }
                    294:
                    295: /*
                    296:  * sched_wakeup - wake up all threads sleeping on event.
                    297:  *
                    298:  * A thread can have sleep and suspend state simultaneously.
                    299:  * So, the thread does not always run even if it woke up.
                    300:  *
1.1.1.1.2.1! nbrk      301:  * Since this routine can be called from ISR at interrupt
        !           302:  * level, there may be contention for access to some data.
        !           303:  * Thus, this routine will temporary move the waking thread
        !           304:  * into wakeq, and they will be moved to runq at more safer
        !           305:  * time in wakeq_flush().
        !           306:  *
        !           307:  * The woken thread will be put on the tail of runq
        !           308:  * regardless of its scheduling policy. If woken threads have
        !           309:  * same priority, next running thread is selected by FIFO order.
1.1       nbrk      310:  */
                    311: void
                    312: sched_wakeup(struct event *evt)
                    313: {
                    314:        queue_t q;
                    315:        thread_t th;
                    316:
1.1.1.1.2.1! nbrk      317:        ASSERT(evt);
        !           318:
        !           319:        sched_lock();
1.1       nbrk      320:        irq_lock();
                    321:        while (!queue_empty(&evt->sleepq)) {
                    322:                /*
                    323:                 * Move a sleeping thread to the wake queue.
                    324:                 */
                    325:                q = dequeue(&evt->sleepq);
                    326:                th = queue_entry(q, struct thread, link);
1.1.1.1.2.1! nbrk      327:                th->slpret = 0;
1.1       nbrk      328:                enqueue(&wakeq, q);
                    329:                timer_stop(&th->timeout);
                    330:        }
                    331:        irq_unlock();
1.1.1.1.2.1! nbrk      332:        sched_unlock();
1.1       nbrk      333: }
                    334:
                    335: /*
1.1.1.1.2.1! nbrk      336:  * sched_wakeone - wake up one thread sleeping on event.
1.1       nbrk      337:  *
1.1.1.1.2.1! nbrk      338:  * The highest priority thread is woken among sleeping
        !           339:  * threads. This routine returns the thread ID of the
        !           340:  * woken thread, or NULL if no threads are sleeping.
1.1       nbrk      341:  */
                    342: thread_t
                    343: sched_wakeone(struct event *evt)
                    344: {
                    345:        queue_t head, q;
                    346:        thread_t top, th = NULL;
                    347:
1.1.1.1.2.1! nbrk      348:        sched_lock();
1.1       nbrk      349:        irq_lock();
                    350:        head = &evt->sleepq;
                    351:        if (!queue_empty(head)) {
                    352:                /*
                    353:                 * Select the highet priority thread in
1.1.1.1.2.1! nbrk      354:                 * the sleep queue, and wakeup it.
1.1       nbrk      355:                 */
                    356:                q = queue_first(head);
                    357:                top = queue_entry(q, struct thread, link);
                    358:                while (!queue_end(head, q)) {
                    359:                        th = queue_entry(q, struct thread, link);
                    360:                        if (th->prio < top->prio)
                    361:                                top = th;
                    362:                        q = queue_next(q);
                    363:                }
                    364:                queue_remove(&top->link);
1.1.1.1.2.1! nbrk      365:                top->slpret = 0;
1.1       nbrk      366:                enqueue(&wakeq, &top->link);
                    367:                timer_stop(&top->timeout);
1.1.1.1.2.1! nbrk      368:                th = top;
1.1       nbrk      369:        }
                    370:        irq_unlock();
1.1.1.1.2.1! nbrk      371:        sched_unlock();
1.1       nbrk      372:        return th;
                    373: }
                    374:
                    375: /*
                    376:  * sched_unsleep - cancel sleep.
                    377:  *
1.1.1.1.2.1! nbrk      378:  * sched_unsleep() removes the specified thread from its
        !           379:  * sleep queue. The specified sleep result will be passed
        !           380:  * to the sleeping thread as a return value of sched_tsleep().
1.1       nbrk      381:  */
                    382: void
                    383: sched_unsleep(thread_t th, int result)
                    384: {
1.1.1.1.2.1! nbrk      385:
1.1       nbrk      386:        sched_lock();
                    387:        if (th->state & TH_SLEEP) {
                    388:                irq_lock();
                    389:                queue_remove(&th->link);
1.1.1.1.2.1! nbrk      390:                th->slpret = result;
1.1       nbrk      391:                enqueue(&wakeq, &th->link);
                    392:                timer_stop(&th->timeout);
                    393:                irq_unlock();
                    394:        }
                    395:        sched_unlock();
                    396: }
                    397:
                    398: /*
                    399:  * Yield the current processor to another thread.
                    400:  *
1.1.1.1.2.1! nbrk      401:  * Note that the current thread may run immediately again,
        !           402:  * if no other thread exists in the same priority queue.
1.1       nbrk      403:  */
                    404: void
                    405: sched_yield(void)
                    406: {
                    407:
                    408:        sched_lock();
                    409:
                    410:        if (!queue_empty(&runq[cur_thread->prio]))
1.1.1.1.2.1! nbrk      411:                cur_thread->resched = 1;
1.1       nbrk      412:
                    413:        sched_unlock(); /* Switch current thread here */
                    414: }
                    415:
                    416: /*
                    417:  * Suspend the specified thread.
1.1.1.1.2.1! nbrk      418:  * Called with scheduler locked.
1.1       nbrk      419:  */
                    420: void
                    421: sched_suspend(thread_t th)
                    422: {
                    423:
                    424:        if (th->state == TH_RUN) {
                    425:                if (th == cur_thread)
1.1.1.1.2.1! nbrk      426:                        cur_thread->resched = 1;
1.1       nbrk      427:                else
                    428:                        runq_remove(th);
                    429:        }
                    430:        th->state |= TH_SUSPEND;
                    431: }
                    432:
                    433: /*
                    434:  * Resume the specified thread.
1.1.1.1.2.1! nbrk      435:  * Called with scheduler locked.
1.1       nbrk      436:  */
                    437: void
                    438: sched_resume(thread_t th)
                    439: {
                    440:
                    441:        if (th->state & TH_SUSPEND) {
                    442:                th->state &= ~TH_SUSPEND;
                    443:                if (th->state == TH_RUN)
                    444:                        runq_enqueue(th);
                    445:        }
                    446: }
                    447:
                    448: /*
                    449:  * sched_tick() is called from timer_tick() once every tick.
                    450:  * Check quantum expiration, and mark a rescheduling flag.
                    451:  * We don't need locking in here.
                    452:  */
                    453: void
                    454: sched_tick(void)
                    455: {
                    456:
1.1.1.1.2.1! nbrk      457:        /* Profile running time. */
        !           458:        cur_thread->time++;
1.1       nbrk      459:
                    460:        if (cur_thread->policy == SCHED_RR) {
1.1.1.1.2.1! nbrk      461:                if (--cur_thread->timeleft <= 0) {
        !           462:                        /*
        !           463:                         * The quantum is up.
        !           464:                         * Give the thread another.
        !           465:                         */
        !           466:                        cur_thread->timeleft += QUANTUM;
        !           467:                        cur_thread->resched = 1;
1.1       nbrk      468:                }
                    469:        }
                    470: }
                    471:
                    472: /*
                    473:  * Set up stuff for thread scheduling.
                    474:  */
                    475: void
                    476: sched_start(thread_t th)
                    477: {
                    478:
                    479:        th->state = TH_RUN | TH_SUSPEND;
                    480:        th->policy = SCHED_RR;
                    481:        th->prio = PRIO_USER;
1.1.1.1.2.1! nbrk      482:        th->baseprio = PRIO_USER;
        !           483:        th->timeleft = QUANTUM;
1.1       nbrk      484: }
                    485:
                    486: /*
                    487:  * Stop thread scheduling.
                    488:  */
                    489: void
                    490: sched_stop(thread_t th)
                    491: {
                    492:
                    493:        if (th == cur_thread) {
                    494:                /*
1.1.1.1.2.1! nbrk      495:                 * If specified thread is current thread,
        !           496:                 * the scheduling lock count is force set
        !           497:                 * to 1 to ensure the thread switching in
        !           498:                 * the next sched_unlock().
1.1       nbrk      499:                 */
1.1.1.1.2.1! nbrk      500:                cur_thread->locks = 1;
        !           501:                cur_thread->resched = 1;
1.1       nbrk      502:        } else {
                    503:                if (th->state == TH_RUN)
                    504:                        runq_remove(th);
                    505:                else if (th->state & TH_SLEEP)
                    506:                        queue_remove(&th->link);
                    507:        }
                    508:        timer_stop(&th->timeout);
                    509:        th->state = TH_EXIT;
                    510: }
                    511:
                    512: /*
                    513:  * sched_lock - lock the scheduler.
                    514:  *
1.1.1.1.2.1! nbrk      515:  * The thread switch is disabled during scheduler locked.
        !           516:  * This is mainly used to synchronize the thread execution
        !           517:  * to protect global resources. Even when scheduler is
        !           518:  * locked, an interrupt handler can run. So, we have to
        !           519:  * use irq_lock() to synchronize a global data with ISR.
        !           520:  *
        !           521:  * Since the scheduling lock can be nested any number of
        !           522:  * times, the caller has the responsible to unlock the same
        !           523:  * number of locks.
1.1       nbrk      524:  */
                    525: void
                    526: sched_lock(void)
                    527: {
                    528:
1.1.1.1.2.1! nbrk      529:        cur_thread->locks++;
1.1       nbrk      530: }
                    531:
                    532: /*
                    533:  * sched_unlock - unlock scheduler.
                    534:  *
1.1.1.1.2.1! nbrk      535:  * If nobody locks the scheduler anymore, it checks the
        !           536:  * rescheduling flag and kick scheduler if it's marked.
1.1       nbrk      537:  *
1.1.1.1.2.1! nbrk      538:  * Note that this routine will be always called at the end
        !           539:  * of each interrupt handler.
1.1       nbrk      540:  */
                    541: void
                    542: sched_unlock(void)
                    543: {
                    544:        int s;
                    545:
1.1.1.1.2.1! nbrk      546:        ASSERT(cur_thread->locks > 0);
1.1       nbrk      547:
                    548:        interrupt_save(&s);
                    549:        interrupt_disable();
                    550:
1.1.1.1.2.1! nbrk      551:        if (cur_thread->locks == 1) {
1.1       nbrk      552:                wakeq_flush();
1.1.1.1.2.1! nbrk      553:                while (cur_thread->resched) {
1.1       nbrk      554:
                    555:                        /* Kick scheduler */
                    556:                        sched_switch();
                    557:
                    558:                        /*
                    559:                         * Now we run pending interrupts which fired
                    560:                         * during the thread switch. So, we can catch
                    561:                         * the rescheduling request from such ISRs.
                    562:                         * Otherwise, the reschedule may be deferred
                    563:                         * until _next_ sched_unlock() call.
                    564:                         */
                    565:                        interrupt_restore(s);
                    566:                        interrupt_disable();
                    567:                        wakeq_flush();
                    568:                }
                    569:        }
1.1.1.1.2.1! nbrk      570:        cur_thread->locks--;
1.1       nbrk      571:
                    572:        interrupt_restore(s);
                    573: }
                    574:
                    575: int
                    576: sched_getprio(thread_t th)
                    577: {
                    578:
                    579:        return th->prio;
                    580: }
                    581:
                    582: /*
                    583:  * sched_setprio - set priority of thread.
                    584:  *
1.1.1.1.2.1! nbrk      585:  * The rescheduling flag is set if the priority is
        !           586:  * better than the currently running thread.
1.1       nbrk      587:  * Called with scheduler locked.
                    588:  */
                    589: void
1.1.1.1.2.1! nbrk      590: sched_setprio(thread_t th, int baseprio, int prio)
1.1       nbrk      591: {
                    592:
1.1.1.1.2.1! nbrk      593:        th->baseprio = baseprio;
1.1       nbrk      594:
                    595:        if (th == cur_thread) {
                    596:                /*
                    597:                 * If we change the current thread's priority,
                    598:                 * rescheduling may be happened.
                    599:                 */
                    600:                th->prio = prio;
                    601:                top_prio = runq_top();
                    602:                if (prio != top_prio)
1.1.1.1.2.1! nbrk      603:                        cur_thread->resched = 1;
1.1       nbrk      604:        } else {
                    605:                if (th->state == TH_RUN) {
                    606:                        /*
1.1.1.1.2.1! nbrk      607:                         * Update the thread priority and adjust
        !           608:                         * the run queue position for new priority.
1.1       nbrk      609:                         */
                    610:                        runq_remove(th);
                    611:                        th->prio = prio;
                    612:                        runq_enqueue(th);
                    613:                } else
                    614:                        th->prio = prio;
                    615:        }
                    616: }
                    617:
                    618: int
                    619: sched_getpolicy(thread_t th)
                    620: {
                    621:
                    622:        return th->policy;
                    623: }
                    624:
                    625: int
                    626: sched_setpolicy(thread_t th, int policy)
                    627: {
                    628:        int err = 0;
                    629:
                    630:        switch (policy) {
                    631:        case SCHED_RR:
                    632:        case SCHED_FIFO:
1.1.1.1.2.1! nbrk      633:                th->timeleft = QUANTUM;
1.1       nbrk      634:                th->policy = policy;
                    635:                break;
                    636:        default:
                    637:                err = -1;
                    638:                break;
                    639:        }
                    640:        return err;
                    641: }
                    642:
                    643: /*
1.1.1.1.2.1! nbrk      644:  * Schedule DPC callback.
        !           645:  *
        !           646:  * DPC (Deferred Procedure Call) is used to call the specific
        !           647:  * function at some later time with a DPC priority. It is also
        !           648:  * known as AST or SoftIRQ in other kernels.  DPC is typically
        !           649:  * used by device drivers to do the low-priority jobs without
        !           650:  * degrading real-time performance.
        !           651:  * This routine can be called from ISR.
        !           652:  */
        !           653: void
        !           654: sched_dpc(struct dpc *dpc, void (*func)(void *), void *arg)
        !           655: {
        !           656:        ASSERT(dpc);
        !           657:        ASSERT(func);
        !           658:
        !           659:        irq_lock();
        !           660:        /*
        !           661:         * Insert request to DPC queue.
        !           662:         */
        !           663:        dpc->func = func;
        !           664:        dpc->arg = arg;
        !           665:        if (dpc->state != DPC_PENDING)
        !           666:                enqueue(&dpcq, &dpc->link);
        !           667:        dpc->state = DPC_PENDING;
        !           668:
        !           669:        /* Wake DPC thread */
        !           670:        sched_wakeup(&dpc_event);
        !           671:
        !           672:        irq_unlock();
        !           673: }
        !           674:
        !           675: /*
        !           676:  * DPC thread.
1.1       nbrk      677:  *
1.1.1.1.2.1! nbrk      678:  * This is a kernel thread to process the pending call back
        !           679:  * request within DPC queue. Each DPC routine is called with
        !           680:  * the following conditions.
1.1       nbrk      681:  *  - Interrupt is enabled.
                    682:  *  - Scheduler is unlocked.
                    683:  */
                    684: static void
1.1.1.1.2.1! nbrk      685: dpc_thread(void *arg)
1.1       nbrk      686: {
                    687:        queue_t q;
                    688:        struct dpc *dpc;
                    689:
                    690:        for (;;) {
                    691:                /* Wait until next DPC request. */
                    692:                sched_sleep(&dpc_event);
                    693:
                    694:                while (!queue_empty(&dpcq)) {
                    695:                        q = dequeue(&dpcq);
                    696:                        dpc = queue_entry(q, struct dpc, link);
                    697:                        dpc->state = DPC_FREE;
                    698:
1.1.1.1.2.1! nbrk      699:                        /*
        !           700:                         * Call DPC routine.
        !           701:                         */
1.1       nbrk      702:                        interrupt_enable();
                    703:                        (*dpc->func)(dpc->arg);
                    704:                        interrupt_disable();
                    705:                }
                    706:        }
                    707:        /* NOTREACHED */
                    708: }
                    709:
                    710: /*
                    711:  * Initialize the global scheduler state.
                    712:  */
                    713: void
                    714: sched_init(void)
                    715: {
1.1.1.1.2.1! nbrk      716:        thread_t th;
1.1       nbrk      717:        int i;
                    718:
1.1.1.1.2.1! nbrk      719:        for (i = 0; i < NPRIO; i++)
1.1       nbrk      720:                queue_init(&runq[i]);
                    721:        queue_init(&wakeq);
                    722:        queue_init(&dpcq);
                    723:        event_init(&dpc_event, "dpc");
                    724:        top_prio = PRIO_IDLE;
1.1.1.1.2.1! nbrk      725:        cur_thread->resched = 1;
1.1       nbrk      726:
1.1.1.1.2.1! nbrk      727:        /* Create a DPC thread. */
        !           728:        th = kthread_create(dpc_thread, NULL, PRIO_DPC);
        !           729:        if (th == NULL)
1.1       nbrk      730:                panic("sched_init");
                    731:
1.1.1.1.2.1! nbrk      732:        DPRINTF(("Time slice is %d msec\n", CONFIG_TIME_SLICE));
1.1       nbrk      733: }

CVSweb