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

CVSweb