Annotation of Gnu-Mach/kern/sched_prim.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * Mach Operating System
        !             3:  * Copyright (c) 1993-1987 Carnegie Mellon University
        !             4:  * All Rights Reserved.
        !             5:  * 
        !             6:  * Permission to use, copy, modify and distribute this software and its
        !             7:  * documentation is hereby granted, provided that both the copyright
        !             8:  * notice and this permission notice appear in all copies of the
        !             9:  * software, derivative works or modified versions, and any portions
        !            10:  * thereof, and that both notices appear in supporting documentation.
        !            11:  * 
        !            12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            15:  * 
        !            16:  * Carnegie Mellon requests users of this software to return to
        !            17:  * 
        !            18:  *  Software Distribution Coordinator  or  [email protected]
        !            19:  *  School of Computer Science
        !            20:  *  Carnegie Mellon University
        !            21:  *  Pittsburgh PA 15213-3890
        !            22:  * 
        !            23:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            24:  * the rights to redistribute these changes.
        !            25:  */
        !            26: /*
        !            27:  *     File:   sched_prim.c
        !            28:  *     Author: Avadis Tevanian, Jr.
        !            29:  *     Date:   1986
        !            30:  *
        !            31:  *     Scheduling primitives
        !            32:  *
        !            33:  */
        !            34: 
        !            35: #include <cpus.h>
        !            36: #include <simple_clock.h>
        !            37: #include <mach_fixpri.h>
        !            38: #include <mach_host.h>
        !            39: #include <hw_footprint.h>
        !            40: #include <fast_tas.h>
        !            41: #include <power_save.h>
        !            42: 
        !            43: #include <mach/machine.h>
        !            44: #include <kern/ast.h>
        !            45: #include <kern/counters.h>
        !            46: #include <kern/cpu_number.h>
        !            47: #include <kern/lock.h>
        !            48: #include <kern/macro_help.h>
        !            49: #include <kern/processor.h>
        !            50: #include <kern/queue.h>
        !            51: #include <kern/sched.h>
        !            52: #include <kern/sched_prim.h>
        !            53: #include <kern/syscall_subr.h>
        !            54: #include <kern/thread.h>
        !            55: #include <kern/thread_swap.h>
        !            56: #include <kern/time_out.h>
        !            57: #include <vm/pmap.h>
        !            58: #include <vm/vm_kern.h>
        !            59: #include <vm/vm_map.h>
        !            60: #include <machine/machspl.h>   /* For def'n of splsched() */
        !            61: 
        !            62: #if    MACH_FIXPRI
        !            63: #include <mach/policy.h>
        !            64: #endif /* MACH_FIXPRI */
        !            65: 
        !            66: 
        !            67: extern int hz;
        !            68: 
        !            69: int            min_quantum;    /* defines max context switch rate */
        !            70: 
        !            71: unsigned       sched_tick;
        !            72: 
        !            73: #if    SIMPLE_CLOCK
        !            74: int            sched_usec;
        !            75: #endif /* SIMPLE_CLOCK */
        !            76: 
        !            77: thread_t       sched_thread_id;
        !            78: 
        !            79: void recompute_priorities(void);       /* forward */
        !            80: void update_priority(thread_t);
        !            81: void set_pri(thread_t, int, boolean_t);
        !            82: void do_thread_scan(void);
        !            83: 
        !            84: thread_t       choose_pset_thread();
        !            85: 
        !            86: timer_elt_data_t recompute_priorities_timer;
        !            87: 
        !            88: #if    DEBUG
        !            89: void checkrq(run_queue_t, char *);
        !            90: void thread_check(thread_t, run_queue_t);
        !            91: #endif
        !            92: 
        !            93: /*
        !            94:  *     State machine
        !            95:  *
        !            96:  * states are combinations of:
        !            97:  *  R  running
        !            98:  *  W  waiting (or on wait queue)
        !            99:  *  S  suspended (or will suspend)
        !           100:  *  N  non-interruptible
        !           101:  *
        !           102:  * init        action 
        !           103:  *     assert_wait thread_block    clear_wait  suspend resume
        !           104:  *
        !           105:  * R   RW,  RWN    R;   setrun     -           RS      -
        !           106:  * RS  RWS, RWNS   S;  wake_active -           -       R
        !           107:  * RN  RWN         RN;  setrun     -           RNS     -
        !           108:  * RNS RWNS        RNS; setrun     -           -       RN
        !           109:  *
        !           110:  * RW              W               R           RWS     -
        !           111:  * RWN             WN              RN          RWNS    -
        !           112:  * RWS             WS; wake_active RS          -       RW
        !           113:  * RWNS                    WNS             RNS         -       RWN
        !           114:  *
        !           115:  * W                               R;   setrun WS      -
        !           116:  * WN                              RN;  setrun WNS     -
        !           117:  * WNS                             RNS; setrun -       WN
        !           118:  *
        !           119:  * S                               -           -       R
        !           120:  * WS                              S           -       W
        !           121:  *
        !           122:  */
        !           123: 
        !           124: /*
        !           125:  *     Waiting protocols and implementation:
        !           126:  *
        !           127:  *     Each thread may be waiting for exactly one event; this event
        !           128:  *     is set using assert_wait().  That thread may be awakened either
        !           129:  *     by performing a thread_wakeup_prim() on its event,
        !           130:  *     or by directly waking that thread up with clear_wait().
        !           131:  *
        !           132:  *     The implementation of wait events uses a hash table.  Each
        !           133:  *     bucket is queue of threads having the same hash function
        !           134:  *     value; the chain for the queue (linked list) is the run queue
        !           135:  *     field.  [It is not possible to be waiting and runnable at the
        !           136:  *     same time.]
        !           137:  *
        !           138:  *     Locks on both the thread and on the hash buckets govern the
        !           139:  *     wait event field and the queue chain field.  Because wakeup
        !           140:  *     operations only have the event as an argument, the event hash
        !           141:  *     bucket must be locked before any thread.
        !           142:  *
        !           143:  *     Scheduling operations may also occur at interrupt level; therefore,
        !           144:  *     interrupts below splsched() must be prevented when holding
        !           145:  *     thread or hash bucket locks.
        !           146:  *
        !           147:  *     The wait event hash table declarations are as follows:
        !           148:  */
        !           149: 
        !           150: #define NUMQUEUES      59
        !           151: 
        !           152: queue_head_t           wait_queue[NUMQUEUES];
        !           153: decl_simple_lock_data(,        wait_lock[NUMQUEUES])
        !           154: 
        !           155: /* NOTE: we want a small positive integer out of this */
        !           156: #define wait_hash(event) \
        !           157:        ((((int)(event) < 0) ? ~(int)(event) : (int)(event)) % NUMQUEUES)
        !           158: 
        !           159: void wait_queue_init(void)
        !           160: {
        !           161:        register int i;
        !           162: 
        !           163:        for (i = 0; i < NUMQUEUES; i++) {
        !           164:                queue_init(&wait_queue[i]);
        !           165:                simple_lock_init(&wait_lock[i]);
        !           166:        }
        !           167: }
        !           168: 
        !           169: void sched_init(void)
        !           170: {
        !           171:        recompute_priorities_timer.fcn = (int (*)())recompute_priorities;
        !           172:        recompute_priorities_timer.param = (char *)0;
        !           173: 
        !           174:        min_quantum = hz / 10;          /* context switch 10 times/second */
        !           175:        wait_queue_init();
        !           176:        pset_sys_bootstrap();           /* initialize processer mgmt. */
        !           177:        queue_init(&action_queue);
        !           178:        simple_lock_init(&action_lock);
        !           179:        sched_tick = 0;
        !           180: #if    SIMPLE_CLOCK
        !           181:        sched_usec = 0;
        !           182: #endif /* SIMPLE_CLOCK */
        !           183:        ast_init();
        !           184: }
        !           185: 
        !           186: /*
        !           187:  *     Thread timeout routine, called when timer expires.
        !           188:  *     Called at splsoftclock.
        !           189:  */
        !           190: void thread_timeout(
        !           191:        thread_t thread)
        !           192: {
        !           193:        assert(thread->timer.set == TELT_UNSET);
        !           194: 
        !           195:        clear_wait(thread, THREAD_TIMED_OUT, FALSE);
        !           196: }
        !           197: 
        !           198: /*
        !           199:  *     thread_set_timeout:
        !           200:  *
        !           201:  *     Set a timer for the current thread, if the thread
        !           202:  *     is ready to wait.  Must be called between assert_wait()
        !           203:  *     and thread_block().
        !           204:  */
        !           205:  
        !           206: void thread_set_timeout(
        !           207:        int     t)      /* timeout interval in ticks */
        !           208: {
        !           209:        register thread_t       thread = current_thread();
        !           210:        register spl_t s;
        !           211: 
        !           212:        s = splsched();
        !           213:        thread_lock(thread);
        !           214:        if ((thread->state & TH_WAIT) != 0) {
        !           215:                set_timeout(&thread->timer, t);
        !           216:        }
        !           217:        thread_unlock(thread);
        !           218:        splx(s);
        !           219: }
        !           220: 
        !           221: /*
        !           222:  * Set up thread timeout element when thread is created.
        !           223:  */
        !           224: void thread_timeout_setup(
        !           225:        register thread_t       thread)
        !           226: {
        !           227:        thread->timer.fcn = (int (*)())thread_timeout;
        !           228:        thread->timer.param = (char *)thread;
        !           229:        thread->depress_timer.fcn = (int (*)())thread_depress_timeout;
        !           230:        thread->depress_timer.param = (char *)thread;
        !           231: }
        !           232: 
        !           233: /*
        !           234:  *     assert_wait:
        !           235:  *
        !           236:  *     Assert that the current thread is about to go to
        !           237:  *     sleep until the specified event occurs.
        !           238:  */
        !           239: void assert_wait(
        !           240:        event_t         event,
        !           241:        boolean_t       interruptible)
        !           242: {
        !           243:        register queue_t        q;
        !           244:        register int            index;
        !           245:        register thread_t       thread;
        !           246: #if    MACH_SLOCKS
        !           247:        register simple_lock_t  lock;
        !           248: #endif /* MACH_SLOCKS */
        !           249:        spl_t                   s;
        !           250: 
        !           251:        thread = current_thread();
        !           252:        if (thread->wait_event != 0) {
        !           253:                panic("assert_wait: already asserted event %#x\n",
        !           254:                      thread->wait_event);
        !           255:        }
        !           256:        s = splsched();
        !           257:        if (event != 0) {
        !           258:                index = wait_hash(event);
        !           259:                q = &wait_queue[index];
        !           260: #if    MACH_SLOCKS
        !           261:                lock = &wait_lock[index];
        !           262: #endif /* MACH_SLOCKS */
        !           263:                simple_lock(lock);
        !           264:                thread_lock(thread);
        !           265:                enqueue_tail(q, (queue_entry_t) thread);
        !           266:                thread->wait_event = event;
        !           267:                if (interruptible)
        !           268:                        thread->state |= TH_WAIT;
        !           269:                else
        !           270:                        thread->state |= TH_WAIT | TH_UNINT;
        !           271:                thread_unlock(thread);
        !           272:                simple_unlock(lock);
        !           273:        }
        !           274:        else {
        !           275:                thread_lock(thread);
        !           276:                if (interruptible)
        !           277:                        thread->state |= TH_WAIT;
        !           278:                else
        !           279:                        thread->state |= TH_WAIT | TH_UNINT;
        !           280:                thread_unlock(thread);
        !           281:        }
        !           282:        splx(s);
        !           283: }
        !           284: 
        !           285: /*
        !           286:  *     clear_wait:
        !           287:  *
        !           288:  *     Clear the wait condition for the specified thread.  Start the thread
        !           289:  *     executing if that is appropriate.
        !           290:  *
        !           291:  *     parameters:
        !           292:  *       thread                thread to awaken
        !           293:  *       result                Wakeup result the thread should see
        !           294:  *       interrupt_only        Don't wake up the thread if it isn't
        !           295:  *                             interruptible.
        !           296:  */
        !           297: void clear_wait(
        !           298:        register thread_t       thread,
        !           299:        int                     result,
        !           300:        boolean_t               interrupt_only)
        !           301: {
        !           302:        register int            index;
        !           303:        register queue_t        q;
        !           304: #if    MACH_SLOCKS
        !           305:        register simple_lock_t  lock;
        !           306: #endif /* MACH_SLOCKS */
        !           307:        register event_t        event;
        !           308:        spl_t                   s;
        !           309: 
        !           310:        s = splsched();
        !           311:        thread_lock(thread);
        !           312:        if (interrupt_only && (thread->state & TH_UNINT)) {
        !           313:                /*
        !           314:                 *      can`t interrupt thread
        !           315:                 */
        !           316:                thread_unlock(thread);
        !           317:                splx(s);
        !           318:                return;
        !           319:        }
        !           320: 
        !           321:        event = thread->wait_event;
        !           322:        if (event != 0) {
        !           323:                thread_unlock(thread);
        !           324:                index = wait_hash(event);
        !           325:                q = &wait_queue[index];
        !           326: #if    MACH_SLOCKS
        !           327:                lock = &wait_lock[index];
        !           328: #endif /* MACH_SLOCKS */
        !           329:                simple_lock(lock);
        !           330:                /*
        !           331:                 *      If the thread is still waiting on that event,
        !           332:                 *      then remove it from the list.  If it is waiting
        !           333:                 *      on a different event, or no event at all, then
        !           334:                 *      someone else did our job for us.
        !           335:                 */
        !           336:                thread_lock(thread);
        !           337:                if (thread->wait_event == event) {
        !           338:                        remqueue(q, (queue_entry_t)thread);
        !           339:                        thread->wait_event = 0;
        !           340:                        event = 0;              /* cause to run below */
        !           341:                }
        !           342:                simple_unlock(lock);
        !           343:        }
        !           344:        if (event == 0) {
        !           345:                register int    state = thread->state;
        !           346: 
        !           347:                reset_timeout_check(&thread->timer);
        !           348: 
        !           349:                switch (state & TH_SCHED_STATE) {
        !           350:                    case          TH_WAIT | TH_SUSP | TH_UNINT:
        !           351:                    case          TH_WAIT           | TH_UNINT:
        !           352:                    case          TH_WAIT:
        !           353:                        /*
        !           354:                         *      Sleeping and not suspendable - put
        !           355:                         *      on run queue.
        !           356:                         */
        !           357:                        thread->state = (state &~ TH_WAIT) | TH_RUN;
        !           358:                        thread->wait_result = result;
        !           359:                        thread_setrun(thread, TRUE);
        !           360:                        break;
        !           361: 
        !           362:                    case          TH_WAIT | TH_SUSP:
        !           363:                    case TH_RUN | TH_WAIT:
        !           364:                    case TH_RUN | TH_WAIT | TH_SUSP:
        !           365:                    case TH_RUN | TH_WAIT           | TH_UNINT:
        !           366:                    case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
        !           367:                        /*
        !           368:                         *      Either already running, or suspended.
        !           369:                         */
        !           370:                        thread->state = state &~ TH_WAIT;
        !           371:                        thread->wait_result = result;
        !           372:                        break;
        !           373: 
        !           374:                    default:
        !           375:                        /*
        !           376:                         *      Not waiting.
        !           377:                         */
        !           378:                        break;
        !           379:                }
        !           380:        }
        !           381:        thread_unlock(thread);
        !           382:        splx(s);
        !           383: }
        !           384: 
        !           385: /*
        !           386:  *     thread_wakeup_prim:
        !           387:  *
        !           388:  *     Common routine for thread_wakeup, thread_wakeup_with_result,
        !           389:  *     and thread_wakeup_one.
        !           390:  *
        !           391:  */
        !           392: void thread_wakeup_prim(
        !           393:        event_t         event,
        !           394:        boolean_t       one_thread,
        !           395:        int             result)
        !           396: {
        !           397:        register queue_t        q;
        !           398:        register int            index;
        !           399:        register thread_t       thread, next_th;
        !           400: #if    MACH_SLOCKS
        !           401:        register simple_lock_t  lock;
        !           402: #endif  /* MACH_SLOCKS */
        !           403:        spl_t                   s;
        !           404:        register int            state;
        !           405: 
        !           406:        index = wait_hash(event);
        !           407:        q = &wait_queue[index];
        !           408:        s = splsched();
        !           409: #if    MACH_SLOCKS
        !           410:        lock = &wait_lock[index];
        !           411: #endif /* MACH_SLOCKS */
        !           412:        simple_lock(lock);
        !           413:        thread = (thread_t) queue_first(q);
        !           414:        while (!queue_end(q, (queue_entry_t)thread)) {
        !           415:                next_th = (thread_t) queue_next((queue_t) thread);
        !           416: 
        !           417:                if (thread->wait_event == event) {
        !           418:                        thread_lock(thread);
        !           419:                        remqueue(q, (queue_entry_t) thread);
        !           420:                        thread->wait_event = 0;
        !           421:                        reset_timeout_check(&thread->timer);
        !           422: 
        !           423:                        state = thread->state;
        !           424:                        switch (state & TH_SCHED_STATE) {
        !           425: 
        !           426:                            case          TH_WAIT | TH_SUSP | TH_UNINT:
        !           427:                            case          TH_WAIT           | TH_UNINT:
        !           428:                            case          TH_WAIT:
        !           429:                                /*
        !           430:                                 *      Sleeping and not suspendable - put
        !           431:                                 *      on run queue.
        !           432:                                 */
        !           433:                                thread->state = (state &~ TH_WAIT) | TH_RUN;
        !           434:                                thread->wait_result = result;
        !           435:                                thread_setrun(thread, TRUE);
        !           436:                                break;
        !           437: 
        !           438:                            case          TH_WAIT | TH_SUSP:
        !           439:                            case TH_RUN | TH_WAIT:
        !           440:                            case TH_RUN | TH_WAIT | TH_SUSP:
        !           441:                            case TH_RUN | TH_WAIT           | TH_UNINT:
        !           442:                            case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
        !           443:                                /*
        !           444:                                 *      Either already running, or suspended.
        !           445:                                 */
        !           446:                                thread->state = state &~ TH_WAIT;
        !           447:                                thread->wait_result = result;
        !           448:                                break;
        !           449: 
        !           450:                            default:
        !           451:                                panic("thread_wakeup");
        !           452:                                break;
        !           453:                        }
        !           454:                        thread_unlock(thread);
        !           455:                        if (one_thread)
        !           456:                                break;
        !           457:                }
        !           458:                thread = next_th;
        !           459:        }
        !           460:        simple_unlock(lock);
        !           461:        splx(s);
        !           462: }
        !           463: 
        !           464: /*
        !           465:  *     thread_sleep:
        !           466:  *
        !           467:  *     Cause the current thread to wait until the specified event
        !           468:  *     occurs.  The specified lock is unlocked before releasing
        !           469:  *     the cpu.  (This is a convenient way to sleep without manually
        !           470:  *     calling assert_wait).
        !           471:  */
        !           472: void thread_sleep(
        !           473:        event_t         event,
        !           474:        simple_lock_t   lock,
        !           475:        boolean_t       interruptible)
        !           476: {
        !           477:        assert_wait(event, interruptible);      /* assert event */
        !           478:        simple_unlock(lock);                    /* release the lock */
        !           479:        thread_block((void (*)()) 0);           /* block ourselves */
        !           480: }
        !           481: 
        !           482: /*
        !           483:  *     thread_bind:
        !           484:  *
        !           485:  *     Force a thread to execute on the specified processor.
        !           486:  *     If the thread is currently executing, it may wait until its
        !           487:  *     time slice is up before switching onto the specified processor.
        !           488:  *
        !           489:  *     A processor of PROCESSOR_NULL causes the thread to be unbound.
        !           490:  *     xxx - DO NOT export this to users.
        !           491:  */
        !           492: void thread_bind(
        !           493:        register thread_t       thread,
        !           494:        processor_t             processor)
        !           495: {
        !           496:        spl_t           s;
        !           497: 
        !           498:        s = splsched();
        !           499:        thread_lock(thread);
        !           500:        thread->bound_processor = processor;
        !           501:        thread_unlock(thread);
        !           502:        (void) splx(s);
        !           503: }
        !           504: 
        !           505: /*
        !           506:  *     Select a thread for this processor (the current processor) to run.
        !           507:  *     May select the current thread.
        !           508:  *     Assumes splsched.
        !           509:  */
        !           510: 
        !           511: thread_t thread_select(
        !           512:        register processor_t myprocessor)
        !           513: {
        !           514:        register thread_t thread;
        !           515: 
        !           516:        myprocessor->first_quantum = TRUE;
        !           517:        /*
        !           518:         *      Check for obvious simple case; local runq is
        !           519:         *      empty and global runq has entry at hint.
        !           520:         */
        !           521:        if (myprocessor->runq.count > 0) {
        !           522:                thread = choose_thread(myprocessor);
        !           523:                myprocessor->quantum = min_quantum;
        !           524:        }
        !           525:        else {
        !           526:                register processor_set_t pset;
        !           527: 
        !           528: #if    MACH_HOST
        !           529:                pset = myprocessor->processor_set;
        !           530: #else  /* MACH_HOST */
        !           531:                pset = &default_pset;
        !           532: #endif /* MACH_HOST */
        !           533:                simple_lock(&pset->runq.lock);
        !           534: #if    DEBUG
        !           535:                checkrq(&pset->runq, "thread_select");
        !           536: #endif /* DEBUG */
        !           537:                if (pset->runq.count == 0) {
        !           538:                        /*
        !           539:                         *      Nothing else runnable.  Return if this
        !           540:                         *      thread is still runnable on this processor.
        !           541:                         *      Check for priority update if required.
        !           542:                         */
        !           543:                        thread = current_thread();
        !           544:                        if ((thread->state == TH_RUN) &&
        !           545: #if    MACH_HOST
        !           546:                            (thread->processor_set == pset) &&
        !           547: #endif /* MACH_HOST */
        !           548:                            ((thread->bound_processor == PROCESSOR_NULL) ||
        !           549:                             (thread->bound_processor == myprocessor))) {
        !           550: 
        !           551:                                simple_unlock(&pset->runq.lock);
        !           552:                                thread_lock(thread);
        !           553:                                if (thread->sched_stamp != sched_tick)
        !           554:                                    update_priority(thread);
        !           555:                                thread_unlock(thread);
        !           556:                        }
        !           557:                        else {
        !           558:                                thread = choose_pset_thread(myprocessor, pset);
        !           559:                        }
        !           560:                }
        !           561:                else {
        !           562:                        register queue_t        q;
        !           563: 
        !           564:                        /*
        !           565:                         *      If there is a thread at hint, grab it,
        !           566:                         *      else call choose_pset_thread.
        !           567:                         */
        !           568:                        q = pset->runq.runq + pset->runq.low;
        !           569: 
        !           570:                        if (queue_empty(q)) {
        !           571:                                pset->runq.low++;
        !           572:                                thread = choose_pset_thread(myprocessor, pset);
        !           573:                        }
        !           574:                        else {
        !           575:                                thread = (thread_t) dequeue_head(q);
        !           576:                                thread->runq = RUN_QUEUE_NULL;
        !           577:                                pset->runq.count--;
        !           578: #if    MACH_FIXPRI
        !           579:                                /*
        !           580:                                 *      Cannot lazy evaluate pset->runq.low for
        !           581:                                 *      fixed priority policy
        !           582:                                 */
        !           583:                                if ((pset->runq.count > 0) &&
        !           584:                                    (pset->policies & POLICY_FIXEDPRI)) {
        !           585:                                            while (queue_empty(q)) {
        !           586:                                                pset->runq.low++;
        !           587:                                                q++;
        !           588:                                            }
        !           589:                                }
        !           590: #endif /* MACH_FIXPRI */
        !           591: #if    DEBUG
        !           592:                                checkrq(&pset->runq, "thread_select: after");
        !           593: #endif /* DEBUG */
        !           594:                                simple_unlock(&pset->runq.lock);
        !           595:                        }
        !           596:                }
        !           597: 
        !           598: #if    MACH_FIXPRI
        !           599:                if (thread->policy == POLICY_TIMESHARE) {
        !           600: #endif /* MACH_FIXPRI */
        !           601:                        myprocessor->quantum = pset->set_quantum;
        !           602: #if    MACH_FIXPRI
        !           603:                }
        !           604:                else {
        !           605:                        /*
        !           606:                         *      POLICY_FIXEDPRI
        !           607:                         */
        !           608:                        myprocessor->quantum = thread->sched_data;
        !           609:                }
        !           610: #endif /* MACH_FIXPRI */
        !           611:        }
        !           612: 
        !           613:        return thread;
        !           614: }
        !           615: 
        !           616: /*
        !           617:  *     Stop running the current thread and start running the new thread.
        !           618:  *     If continuation is non-zero, and the current thread is blocked,
        !           619:  *     then it will resume by executing continuation on a new stack.
        !           620:  *     Returns TRUE if the hand-off succeeds.
        !           621:  *     Assumes splsched.
        !           622:  */
        !           623: 
        !           624: boolean_t thread_invoke(
        !           625:        register thread_t old_thread,
        !           626:        continuation_t    continuation,
        !           627:        register thread_t new_thread)
        !           628: {
        !           629:        /*
        !           630:         *      Check for invoking the same thread.
        !           631:         */
        !           632:        if (old_thread == new_thread) {
        !           633:            /*
        !           634:             *  Mark thread interruptible.
        !           635:             *  Run continuation if there is one.
        !           636:             */
        !           637:            thread_lock(new_thread);
        !           638:            new_thread->state &= ~TH_UNINT;
        !           639:            thread_unlock(new_thread);
        !           640: 
        !           641:            if (continuation != (void (*)()) 0) {
        !           642:                (void) spl0();
        !           643:                call_continuation(continuation);
        !           644:                /*NOTREACHED*/
        !           645:            }
        !           646:            return TRUE;
        !           647:        }
        !           648: 
        !           649:        /*
        !           650:         *      Check for stack-handoff.
        !           651:         */
        !           652:        thread_lock(new_thread);
        !           653:        if ((old_thread->stack_privilege != current_stack()) &&
        !           654:            (continuation != (void (*)()) 0))
        !           655:        {
        !           656:            switch (new_thread->state & TH_SWAP_STATE) {
        !           657:                case TH_SWAPPED:
        !           658: 
        !           659:                    new_thread->state &= ~(TH_SWAPPED | TH_UNINT);
        !           660:                    thread_unlock(new_thread);
        !           661: 
        !           662: #if    NCPUS > 1
        !           663:                    new_thread->last_processor = current_processor();
        !           664: #endif /* NCPUS > 1 */
        !           665: 
        !           666:                    /*
        !           667:                     *  Set up ast context of new thread and
        !           668:                     *  switch to its timer.
        !           669:                     */
        !           670:                    ast_context(new_thread, cpu_number());
        !           671:                    timer_switch(&new_thread->system_timer);
        !           672: 
        !           673:                    stack_handoff(old_thread, new_thread);
        !           674: 
        !           675:                    /*
        !           676:                     *  We can dispatch the old thread now.
        !           677:                     *  This is like thread_dispatch, except
        !           678:                     *  that the old thread is left swapped
        !           679:                     *  *without* freeing its stack.
        !           680:                     *  This path is also much more frequent
        !           681:                     *  than actual calls to thread_dispatch.
        !           682:                     */
        !           683: 
        !           684:                    thread_lock(old_thread);
        !           685:                    old_thread->swap_func = continuation;
        !           686: 
        !           687:                    switch (old_thread->state) {
        !           688:                        case TH_RUN           | TH_SUSP:
        !           689:                        case TH_RUN           | TH_SUSP | TH_HALTED:
        !           690:                        case TH_RUN | TH_WAIT | TH_SUSP:
        !           691:                            /*
        !           692:                             *  Suspend the thread
        !           693:                             */
        !           694:                            old_thread->state = (old_thread->state & ~TH_RUN)
        !           695:                                                | TH_SWAPPED;
        !           696:                            if (old_thread->wake_active) {
        !           697:                                old_thread->wake_active = FALSE;
        !           698:                                thread_unlock(old_thread);
        !           699:                                thread_wakeup((event_t)&old_thread->wake_active);
        !           700: 
        !           701:                                goto after_old_thread;
        !           702:                            }
        !           703:                            break;
        !           704: 
        !           705:                        case TH_RUN           | TH_SUSP | TH_UNINT:
        !           706:                        case TH_RUN                     | TH_UNINT:
        !           707:                        case TH_RUN:
        !           708:                            /*
        !           709:                             *  We can`t suspend the thread yet,
        !           710:                             *  or it`s still running.
        !           711:                             *  Put back on a run queue.
        !           712:                             */
        !           713:                            old_thread->state |= TH_SWAPPED;
        !           714:                            thread_setrun(old_thread, FALSE);
        !           715:                            break;
        !           716: 
        !           717:                        case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
        !           718:                        case TH_RUN | TH_WAIT           | TH_UNINT:
        !           719:                        case TH_RUN | TH_WAIT:
        !           720:                            /*
        !           721:                             *  Waiting, and not suspendable.
        !           722:                             */
        !           723:                            old_thread->state = (old_thread->state & ~TH_RUN)
        !           724:                                                | TH_SWAPPED;
        !           725:                            break;
        !           726: 
        !           727:                        case TH_RUN | TH_IDLE:
        !           728:                            /*
        !           729:                             *  Drop idle thread -- it is already in
        !           730:                             *  idle_thread_array.
        !           731:                             */
        !           732:                            old_thread->state = TH_RUN | TH_IDLE | TH_SWAPPED;
        !           733:                            break;
        !           734: 
        !           735:                        default:
        !           736:                            panic("thread_invoke");
        !           737:                    }
        !           738:                    thread_unlock(old_thread);
        !           739:                after_old_thread:
        !           740: 
        !           741:                    /*
        !           742:                     *  call_continuation calls the continuation
        !           743:                     *  after resetting the current stack pointer
        !           744:                     *  to recover stack space.  If we called
        !           745:                     *  the continuation directly, we would risk
        !           746:                     *  running out of stack.
        !           747:                     */
        !           748: 
        !           749:                    counter_always(c_thread_invoke_hits++);
        !           750:                    (void) spl0();
        !           751:                    call_continuation(new_thread->swap_func);
        !           752:                    /*NOTREACHED*/
        !           753:                    return TRUE; /* help for the compiler */
        !           754: 
        !           755:                case TH_SW_COMING_IN:
        !           756:                    /*
        !           757:                     *  Waiting for a stack
        !           758:                     */
        !           759:                    thread_swapin(new_thread);
        !           760:                    thread_unlock(new_thread);
        !           761:                    counter_always(c_thread_invoke_misses++);
        !           762:                    return FALSE;
        !           763: 
        !           764:                case 0:
        !           765:                    /*
        !           766:                     *  Already has a stack - can`t handoff.
        !           767:                     */
        !           768:                    break;
        !           769:            }
        !           770:        }
        !           771: 
        !           772:        else {
        !           773:            /*
        !           774:             *  Check that the thread is swapped-in.
        !           775:             */
        !           776:            if (new_thread->state & TH_SWAPPED) {
        !           777:                if ((new_thread->state & TH_SW_COMING_IN) ||
        !           778:                    !stack_alloc_try(new_thread, thread_continue))
        !           779:                {
        !           780:                    thread_swapin(new_thread);
        !           781:                    thread_unlock(new_thread);
        !           782:                    counter_always(c_thread_invoke_misses++);
        !           783:                    return FALSE;
        !           784:                }
        !           785:            }
        !           786:        }
        !           787: 
        !           788:        new_thread->state &= ~(TH_SWAPPED | TH_UNINT);
        !           789:        thread_unlock(new_thread);
        !           790: 
        !           791:        /*
        !           792:         *      Thread is now interruptible.
        !           793:         */
        !           794: #if    NCPUS > 1
        !           795:        new_thread->last_processor = current_processor();
        !           796: #endif /* NCPUS > 1 */
        !           797: 
        !           798:        /*
        !           799:         *      Set up ast context of new thread and switch to its timer.
        !           800:         */
        !           801:        ast_context(new_thread, cpu_number());
        !           802:        timer_switch(&new_thread->system_timer);
        !           803: 
        !           804:        /*
        !           805:         *      switch_context is machine-dependent.  It does the
        !           806:         *      machine-dependent components of a context-switch, like
        !           807:         *      changing address spaces.  It updates active_threads.
        !           808:         *      It returns only if a continuation is not supplied.
        !           809:         */
        !           810:        counter_always(c_thread_invoke_csw++);
        !           811:        old_thread = switch_context(old_thread, continuation, new_thread);
        !           812: 
        !           813:        /*
        !           814:         *      We're back.  Now old_thread is the thread that resumed
        !           815:         *      us, and we have to dispatch it.
        !           816:         */
        !           817:        thread_dispatch(old_thread);
        !           818: 
        !           819:        return TRUE;
        !           820: }
        !           821: 
        !           822: /*
        !           823:  *     thread_continue:
        !           824:  *
        !           825:  *     Called when the current thread is given a new stack.
        !           826:  *     Called at splsched.
        !           827:  */
        !           828: void thread_continue(
        !           829:        register thread_t old_thread)
        !           830: {
        !           831:        register continuation_t continuation = current_thread()->swap_func;
        !           832: 
        !           833:        /*
        !           834:         *      We must dispatch the old thread and then
        !           835:         *      call the current thread's continuation.
        !           836:         *      There might not be an old thread, if we are
        !           837:         *      the first thread to run on this processor.
        !           838:         */
        !           839: 
        !           840:        if (old_thread != THREAD_NULL)
        !           841:                thread_dispatch(old_thread);
        !           842:        (void) spl0();
        !           843:        (*continuation)();
        !           844:        /*NOTREACHED*/
        !           845: }
        !           846: 
        !           847: 
        !           848: /*
        !           849:  *     thread_block:
        !           850:  *
        !           851:  *     Block the current thread.  If the thread is runnable
        !           852:  *     then someone must have woken it up between its request
        !           853:  *     to sleep and now.  In this case, it goes back on a
        !           854:  *     run queue.
        !           855:  *
        !           856:  *     If a continuation is specified, then thread_block will
        !           857:  *     attempt to discard the thread's kernel stack.  When the
        !           858:  *     thread resumes, it will execute the continuation function
        !           859:  *     on a new kernel stack.
        !           860:  */
        !           861: 
        !           862: void thread_block(
        !           863:        continuation_t  continuation)
        !           864: {
        !           865:        register thread_t thread = current_thread();
        !           866:        register processor_t myprocessor = cpu_to_processor(cpu_number());
        !           867:        register thread_t new_thread;
        !           868:        spl_t s;
        !           869: 
        !           870:        check_simple_locks();
        !           871: 
        !           872:        s = splsched();
        !           873: 
        !           874: #if    FAST_TAS
        !           875:        {
        !           876:                extern void recover_ras();
        !           877: 
        !           878:                if (csw_needed(thread, myprocessor))
        !           879:                        recover_ras(thread);
        !           880:        }
        !           881: #endif /* FAST_TAS */
        !           882:        
        !           883:        ast_off(cpu_number(), AST_BLOCK);
        !           884: 
        !           885:        do
        !           886:                new_thread = thread_select(myprocessor);
        !           887:        while (!thread_invoke(thread, continuation, new_thread));
        !           888: 
        !           889:        splx(s);
        !           890: }
        !           891: 
        !           892: /*
        !           893:  *     thread_run:
        !           894:  *
        !           895:  *     Switch directly from the current thread to a specified
        !           896:  *     thread.  Both the current and new threads must be
        !           897:  *     runnable.
        !           898:  *
        !           899:  *     If a continuation is specified, then thread_block will
        !           900:  *     attempt to discard the current thread's kernel stack.  When the
        !           901:  *     thread resumes, it will execute the continuation function
        !           902:  *     on a new kernel stack.
        !           903:  */
        !           904: void thread_run(
        !           905:        continuation_t          continuation,
        !           906:        register thread_t       new_thread)
        !           907: {
        !           908:        register thread_t thread = current_thread();
        !           909:        register processor_t myprocessor = cpu_to_processor(cpu_number());
        !           910:        spl_t s;
        !           911: 
        !           912:        check_simple_locks();
        !           913: 
        !           914:        s = splsched();
        !           915: 
        !           916:        while (!thread_invoke(thread, continuation, new_thread))
        !           917:                new_thread = thread_select(myprocessor);
        !           918: 
        !           919:        splx(s);
        !           920: }
        !           921: 
        !           922: /*
        !           923:  *     Dispatches a running thread that is not on a runq.
        !           924:  *     Called at splsched.
        !           925:  */
        !           926: 
        !           927: void thread_dispatch(
        !           928:        register thread_t       thread)
        !           929: {
        !           930:        /*
        !           931:         *      If we are discarding the thread's stack, we must do it
        !           932:         *      before the thread has a chance to run.
        !           933:         */
        !           934: 
        !           935:        thread_lock(thread);
        !           936: 
        !           937:        if (thread->swap_func != (void (*)()) 0) {
        !           938:                assert((thread->state & TH_SWAP_STATE) == 0);
        !           939:                thread->state |= TH_SWAPPED;
        !           940:                stack_free(thread);
        !           941:        }
        !           942: 
        !           943:        switch (thread->state &~ TH_SWAP_STATE) {
        !           944:            case TH_RUN           | TH_SUSP:
        !           945:            case TH_RUN           | TH_SUSP | TH_HALTED:
        !           946:            case TH_RUN | TH_WAIT | TH_SUSP:
        !           947:                /*
        !           948:                 *      Suspend the thread
        !           949:                 */
        !           950:                thread->state &= ~TH_RUN;
        !           951:                if (thread->wake_active) {
        !           952:                    thread->wake_active = FALSE;
        !           953:                    thread_unlock(thread);
        !           954:                    thread_wakeup((event_t)&thread->wake_active);
        !           955:                    return;
        !           956:                }
        !           957:                break;
        !           958: 
        !           959:            case TH_RUN           | TH_SUSP | TH_UNINT:
        !           960:            case TH_RUN                     | TH_UNINT:
        !           961:            case TH_RUN:
        !           962:                /*
        !           963:                 *      No reason to stop.  Put back on a run queue.
        !           964:                 */
        !           965:                thread_setrun(thread, FALSE);
        !           966:                break;
        !           967: 
        !           968:            case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
        !           969:            case TH_RUN | TH_WAIT           | TH_UNINT:
        !           970:            case TH_RUN | TH_WAIT:
        !           971:                /*
        !           972:                 *      Waiting, and not suspended.
        !           973:                 */
        !           974:                thread->state &= ~TH_RUN;
        !           975:                break;
        !           976: 
        !           977:            case TH_RUN | TH_IDLE:
        !           978:                /*
        !           979:                 *      Drop idle thread -- it is already in
        !           980:                 *      idle_thread_array.
        !           981:                 */
        !           982:                break;
        !           983: 
        !           984:            default:
        !           985:                panic("thread_dispatch");
        !           986:        }
        !           987:        thread_unlock(thread);
        !           988: }
        !           989: 
        !           990: 
        !           991: /*
        !           992:  *     Define shifts for simulating (5/8)**n
        !           993:  */
        !           994: 
        !           995: shift_data_t   wait_shift[32] = {
        !           996:        {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7},
        !           997:        {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13},
        !           998:        {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18},
        !           999:        {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}};
        !          1000: 
        !          1001: /*
        !          1002:  *     do_priority_computation:
        !          1003:  *
        !          1004:  *     Calculate new priority for thread based on its base priority plus
        !          1005:  *     accumulated usage.  PRI_SHIFT and PRI_SHIFT_2 convert from
        !          1006:  *     usage to priorities.  SCHED_SHIFT converts for the scaling
        !          1007:  *     of the sched_usage field by SCHED_SCALE.  This scaling comes
        !          1008:  *     from the multiplication by sched_load (thread_timer_delta)
        !          1009:  *     in sched.h.  sched_load is calculated as a scaled overload
        !          1010:  *     factor in compute_mach_factor (mach_factor.c).
        !          1011:  */
        !          1012: 
        !          1013: #ifdef PRI_SHIFT_2
        !          1014: #if    PRI_SHIFT_2 > 0
        !          1015: #define do_priority_computation(th, pri)                               \
        !          1016:        MACRO_BEGIN                                                     \
        !          1017:        (pri) = (th)->priority  /* start with base priority */          \
        !          1018:            + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT))          \
        !          1019:            + ((th)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT));       \
        !          1020:        if ((pri) > 31) (pri) = 31;                                     \
        !          1021:        MACRO_END
        !          1022: #else  /* PRI_SHIFT_2 */
        !          1023: #define do_priority_computation(th, pri)                               \
        !          1024:        MACRO_BEGIN                                                     \
        !          1025:        (pri) = (th)->priority  /* start with base priority */          \
        !          1026:            + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT))          \
        !          1027:            - ((th)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2));       \
        !          1028:        if ((pri) > 31) (pri) = 31;                                     \
        !          1029:        MACRO_END
        !          1030: #endif /* PRI_SHIFT_2 */
        !          1031: #else  /* defined(PRI_SHIFT_2) */
        !          1032: #define do_priority_computation(th, pri)                               \
        !          1033:        MACRO_BEGIN                                                     \
        !          1034:        (pri) = (th)->priority  /* start with base priority */          \
        !          1035:            + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT));         \
        !          1036:        if ((pri) > 31) (pri) = 31;                                     \
        !          1037:        MACRO_END
        !          1038: #endif /* defined(PRI_SHIFT_2) */
        !          1039: 
        !          1040: /*
        !          1041:  *     compute_priority:
        !          1042:  *
        !          1043:  *     Compute the effective priority of the specified thread.
        !          1044:  *     The effective priority computation is as follows:
        !          1045:  *
        !          1046:  *     Take the base priority for this thread and add
        !          1047:  *     to it an increment derived from its cpu_usage.
        !          1048:  *
        !          1049:  *     The thread *must* be locked by the caller. 
        !          1050:  */
        !          1051: 
        !          1052: void compute_priority(
        !          1053:        register thread_t       thread,
        !          1054:        boolean_t               resched)
        !          1055: {
        !          1056:        register int    pri;
        !          1057: 
        !          1058: #if    MACH_FIXPRI
        !          1059:        if (thread->policy == POLICY_TIMESHARE) {
        !          1060: #endif /* MACH_FIXPRI */
        !          1061:            do_priority_computation(thread, pri);
        !          1062:            if (thread->depress_priority < 0)
        !          1063:                set_pri(thread, pri, resched);
        !          1064:            else
        !          1065:                thread->depress_priority = pri;
        !          1066: #if    MACH_FIXPRI
        !          1067:        }
        !          1068:        else {
        !          1069:            set_pri(thread, thread->priority, resched);
        !          1070:        }
        !          1071: #endif /* MACH_FIXPRI */
        !          1072: }
        !          1073: 
        !          1074: /*
        !          1075:  *     compute_my_priority:
        !          1076:  *
        !          1077:  *     Version of compute priority for current thread or thread
        !          1078:  *     being manipulated by scheduler (going on or off a runq).
        !          1079:  *     Only used for priority updates.  Policy or priority changes
        !          1080:  *     must call compute_priority above.  Caller must have thread
        !          1081:  *     locked and know it is timesharing and not depressed.
        !          1082:  */
        !          1083: 
        !          1084: void compute_my_priority(
        !          1085:        register thread_t       thread)
        !          1086: {
        !          1087:        register int temp_pri;
        !          1088: 
        !          1089:        do_priority_computation(thread,temp_pri);
        !          1090:        thread->sched_pri = temp_pri;
        !          1091: }
        !          1092: 
        !          1093: /*
        !          1094:  *     recompute_priorities:
        !          1095:  *
        !          1096:  *     Update the priorities of all threads periodically.
        !          1097:  */
        !          1098: void recompute_priorities(void)
        !          1099: {
        !          1100: #if    SIMPLE_CLOCK
        !          1101:        int     new_usec;
        !          1102: #endif /* SIMPLE_CLOCK */
        !          1103: 
        !          1104:        sched_tick++;           /* age usage one more time */
        !          1105:        set_timeout(&recompute_priorities_timer, hz);
        !          1106: #if    SIMPLE_CLOCK
        !          1107:        /*
        !          1108:         *      Compensate for clock drift.  sched_usec is an
        !          1109:         *      exponential average of the number of microseconds in
        !          1110:         *      a second.  It decays in the same fashion as cpu_usage.
        !          1111:         */
        !          1112:        new_usec = sched_usec_elapsed();
        !          1113:        sched_usec = (5*sched_usec + 3*new_usec)/8;
        !          1114: #endif /* SIMPLE_CLOCK */
        !          1115:        /*
        !          1116:         *      Wakeup scheduler thread.
        !          1117:         */
        !          1118:        if (sched_thread_id != THREAD_NULL) {
        !          1119:                clear_wait(sched_thread_id, THREAD_AWAKENED, FALSE);
        !          1120:        }
        !          1121: }
        !          1122: 
        !          1123: /*
        !          1124:  *     update_priority
        !          1125:  *
        !          1126:  *     Cause the priority computation of a thread that has been 
        !          1127:  *     sleeping or suspended to "catch up" with the system.  Thread
        !          1128:  *     *MUST* be locked by caller.  If thread is running, then this
        !          1129:  *     can only be called by the thread on itself.
        !          1130:  */
        !          1131: void update_priority(
        !          1132:        register thread_t       thread)
        !          1133: {
        !          1134:        register unsigned int   ticks;
        !          1135:        register shift_t        shiftp;
        !          1136:        register int            temp_pri;
        !          1137: 
        !          1138:        ticks = sched_tick - thread->sched_stamp;
        !          1139: 
        !          1140:        assert(ticks != 0);
        !          1141: 
        !          1142:        /*
        !          1143:         *      If asleep for more than 30 seconds forget all
        !          1144:         *      cpu_usage, else catch up on missed aging.
        !          1145:         *      5/8 ** n is approximated by the two shifts
        !          1146:         *      in the wait_shift array.
        !          1147:         */
        !          1148:        thread->sched_stamp += ticks;
        !          1149:        thread_timer_delta(thread);
        !          1150:        if (ticks >  30) {
        !          1151:                thread->cpu_usage = 0;
        !          1152:                thread->sched_usage = 0;
        !          1153:        }
        !          1154:        else {
        !          1155:                thread->cpu_usage += thread->cpu_delta;
        !          1156:                thread->sched_usage += thread->sched_delta;
        !          1157:                shiftp = &wait_shift[ticks];
        !          1158:                if (shiftp->shift2 > 0) {
        !          1159:                    thread->cpu_usage =
        !          1160:                        (thread->cpu_usage >> shiftp->shift1) +
        !          1161:                        (thread->cpu_usage >> shiftp->shift2);
        !          1162:                    thread->sched_usage =
        !          1163:                        (thread->sched_usage >> shiftp->shift1) +
        !          1164:                        (thread->sched_usage >> shiftp->shift2);
        !          1165:                }
        !          1166:                else {
        !          1167:                    thread->cpu_usage =
        !          1168:                        (thread->cpu_usage >> shiftp->shift1) -
        !          1169:                        (thread->cpu_usage >> -(shiftp->shift2));
        !          1170:                    thread->sched_usage =
        !          1171:                        (thread->sched_usage >> shiftp->shift1) -
        !          1172:                        (thread->sched_usage >> -(shiftp->shift2));
        !          1173:                }
        !          1174:        }
        !          1175:        thread->cpu_delta = 0;
        !          1176:        thread->sched_delta = 0;
        !          1177:        /*
        !          1178:         *      Recompute priority if appropriate.
        !          1179:         */
        !          1180:        if (
        !          1181: #if    MACH_FIXPRI
        !          1182:            (thread->policy == POLICY_TIMESHARE) &&
        !          1183: #endif /* MACH_FIXPRI */
        !          1184:            (thread->depress_priority < 0)) {
        !          1185:                do_priority_computation(thread, temp_pri);
        !          1186:                thread->sched_pri = temp_pri;
        !          1187:        }
        !          1188: }
        !          1189: 
        !          1190: /*
        !          1191:  *     run_queue_enqueue macro for thread_setrun().
        !          1192:  */
        !          1193: #if    DEBUG
        !          1194: #define run_queue_enqueue(rq, th)                                      \
        !          1195:        MACRO_BEGIN                                                     \
        !          1196:            register unsigned int       whichq;                         \
        !          1197:                                                                        \
        !          1198:            whichq = (th)->sched_pri;                                   \
        !          1199:            if (whichq >= NRQS) {                                       \
        !          1200:        printf("thread_setrun: pri too high (%d)\n", (th)->sched_pri);  \
        !          1201:                whichq = NRQS - 1;                                      \
        !          1202:            }                                                           \
        !          1203:                                                                        \
        !          1204:            simple_lock(&(rq)->lock);   /* lock the run queue */        \
        !          1205:            checkrq((rq), "thread_setrun: before adding thread");       \
        !          1206:            enqueue_tail(&(rq)->runq[whichq], (queue_entry_t) (th));    \
        !          1207:                                                                        \
        !          1208:            if (whichq < (rq)->low || (rq)->count == 0)                 \
        !          1209:                 (rq)->low = whichq;    /* minimize */                  \
        !          1210:                                                                        \
        !          1211:            (rq)->count++;                                              \
        !          1212:            (th)->runq = (rq);                                          \
        !          1213:            thread_check((th), (rq));                                   \
        !          1214:            checkrq((rq), "thread_setrun: after adding thread");        \
        !          1215:            simple_unlock(&(rq)->lock);                                 \
        !          1216:        MACRO_END
        !          1217: #else  /* DEBUG */
        !          1218: #define run_queue_enqueue(rq, th)                                      \
        !          1219:        MACRO_BEGIN                                                     \
        !          1220:            register unsigned int       whichq;                         \
        !          1221:                                                                        \
        !          1222:            whichq = (th)->sched_pri;                                   \
        !          1223:            if (whichq >= NRQS) {                                       \
        !          1224:        printf("thread_setrun: pri too high (%d)\n", (th)->sched_pri);  \
        !          1225:                whichq = NRQS - 1;                                      \
        !          1226:            }                                                           \
        !          1227:                                                                        \
        !          1228:            simple_lock(&(rq)->lock);   /* lock the run queue */        \
        !          1229:            enqueue_tail(&(rq)->runq[whichq], (queue_entry_t) (th));    \
        !          1230:                                                                        \
        !          1231:            if (whichq < (rq)->low || (rq)->count == 0)                 \
        !          1232:                 (rq)->low = whichq;    /* minimize */                  \
        !          1233:                                                                        \
        !          1234:            (rq)->count++;                                              \
        !          1235:            (th)->runq = (rq);                                          \
        !          1236:            simple_unlock(&(rq)->lock);                                 \
        !          1237:        MACRO_END
        !          1238: #endif /* DEBUG */
        !          1239: /*
        !          1240:  *     thread_setrun:
        !          1241:  *
        !          1242:  *     Make thread runnable; dispatch directly onto an idle processor
        !          1243:  *     if possible.  Else put on appropriate run queue (processor
        !          1244:  *     if bound, else processor set.  Caller must have lock on thread.
        !          1245:  *     This is always called at splsched.
        !          1246:  */
        !          1247: 
        !          1248: void thread_setrun(
        !          1249:        register thread_t       th,
        !          1250:        boolean_t               may_preempt)
        !          1251: {
        !          1252:        register processor_t    processor;
        !          1253:        register run_queue_t    rq;
        !          1254: #if    NCPUS > 1
        !          1255:        register processor_set_t        pset;
        !          1256: #endif /* NCPUS > 1 */
        !          1257: 
        !          1258:        /*
        !          1259:         *      Update priority if needed.
        !          1260:         */
        !          1261:        if (th->sched_stamp != sched_tick) {
        !          1262:                update_priority(th);
        !          1263:        }
        !          1264: 
        !          1265:        assert(th->runq == RUN_QUEUE_NULL);
        !          1266: 
        !          1267: #if    NCPUS > 1
        !          1268:        /*
        !          1269:         *      Try to dispatch the thread directly onto an idle processor.
        !          1270:         */
        !          1271:        if ((processor = th->bound_processor) == PROCESSOR_NULL) {
        !          1272:            /*
        !          1273:             *  Not bound, any processor in the processor set is ok.
        !          1274:             */
        !          1275:            pset = th->processor_set;
        !          1276: #if    HW_FOOTPRINT
        !          1277:            /*
        !          1278:             *  But first check the last processor it ran on.
        !          1279:             */
        !          1280:            processor = th->last_processor;
        !          1281:            if (processor->state == PROCESSOR_IDLE) {
        !          1282:                    simple_lock(&processor->lock);
        !          1283:                    simple_lock(&pset->idle_lock);
        !          1284:                    if ((processor->state == PROCESSOR_IDLE)
        !          1285: #if    MACH_HOST
        !          1286:                        && (processor->processor_set == pset)
        !          1287: #endif /* MACH_HOST */
        !          1288:                        ) {
        !          1289:                            queue_remove(&pset->idle_queue, processor,
        !          1290:                                processor_t, processor_queue);
        !          1291:                            pset->idle_count--;
        !          1292:                            processor->next_thread = th;
        !          1293:                            processor->state = PROCESSOR_DISPATCHING;
        !          1294:                            simple_unlock(&pset->idle_lock);
        !          1295:                            simple_unlock(&processor->lock);
        !          1296:                            return;
        !          1297:                    }
        !          1298:                    simple_unlock(&pset->idle_lock);
        !          1299:                    simple_unlock(&processor->lock);
        !          1300:            }
        !          1301: #endif /* HW_FOOTPRINT */
        !          1302: 
        !          1303:            if (pset->idle_count > 0) {
        !          1304:                simple_lock(&pset->idle_lock);
        !          1305:                if (pset->idle_count > 0) {
        !          1306:                    processor = (processor_t) queue_first(&pset->idle_queue);
        !          1307:                    queue_remove(&(pset->idle_queue), processor, processor_t,
        !          1308:                                processor_queue);
        !          1309:                    pset->idle_count--;
        !          1310:                    processor->next_thread = th;
        !          1311:                    processor->state = PROCESSOR_DISPATCHING;
        !          1312:                    simple_unlock(&pset->idle_lock);
        !          1313:                    return;
        !          1314:                }
        !          1315:                simple_unlock(&pset->idle_lock);
        !          1316:            }
        !          1317:            rq = &(pset->runq);
        !          1318:            run_queue_enqueue(rq,th);
        !          1319:            /*
        !          1320:             * Preempt check
        !          1321:             */
        !          1322:            if (may_preempt &&
        !          1323: #if    MACH_HOST
        !          1324:                (pset == current_processor()->processor_set) &&
        !          1325: #endif /* MACH_HOST */
        !          1326:                (current_thread()->sched_pri > th->sched_pri)) {
        !          1327:                        /*
        !          1328:                         *      Turn off first_quantum to allow csw.
        !          1329:                         */
        !          1330:                        current_processor()->first_quantum = FALSE;
        !          1331:                        ast_on(cpu_number(), AST_BLOCK);
        !          1332:            }
        !          1333:        }
        !          1334:        else {
        !          1335:            /*
        !          1336:             *  Bound, can only run on bound processor.  Have to lock
        !          1337:             *  processor here because it may not be the current one.
        !          1338:             */
        !          1339:            if (processor->state == PROCESSOR_IDLE) {
        !          1340:                simple_lock(&processor->lock);
        !          1341:                pset = processor->processor_set;
        !          1342:                simple_lock(&pset->idle_lock);
        !          1343:                if (processor->state == PROCESSOR_IDLE) {
        !          1344:                    queue_remove(&pset->idle_queue, processor,
        !          1345:                        processor_t, processor_queue);
        !          1346:                    pset->idle_count--;
        !          1347:                    processor->next_thread = th;
        !          1348:                    processor->state = PROCESSOR_DISPATCHING;
        !          1349:                    simple_unlock(&pset->idle_lock);
        !          1350:                    simple_unlock(&processor->lock);
        !          1351:                    return;
        !          1352:                }
        !          1353:                simple_unlock(&pset->idle_lock);
        !          1354:                simple_unlock(&processor->lock);
        !          1355:            }
        !          1356:            rq = &(processor->runq);
        !          1357:            run_queue_enqueue(rq,th);
        !          1358: 
        !          1359:            /*
        !          1360:             *  Cause ast on processor if processor is on line.
        !          1361:             *
        !          1362:             *  XXX Don't do this remotely to master because this will
        !          1363:             *  XXX send an interprocessor interrupt, and that's too
        !          1364:             *  XXX expensive for all the unparallelized U*x code.
        !          1365:             */
        !          1366:            if (processor == current_processor()) {
        !          1367:                ast_on(cpu_number(), AST_BLOCK);
        !          1368:            }
        !          1369:            else if ((processor != master_processor) &&
        !          1370:                     (processor->state != PROCESSOR_OFF_LINE)) {
        !          1371:                        cause_ast_check(processor);
        !          1372:            }
        !          1373:        }
        !          1374: #else  /* NCPUS > 1 */
        !          1375:        /*
        !          1376:         *      XXX should replace queue with a boolean in this case.
        !          1377:         */
        !          1378:        if (default_pset.idle_count > 0) {
        !          1379:            processor = (processor_t) queue_first(&default_pset.idle_queue);
        !          1380:            queue_remove(&default_pset.idle_queue, processor,
        !          1381:                processor_t, processor_queue);
        !          1382:            default_pset.idle_count--;
        !          1383:            processor->next_thread = th;
        !          1384:            processor->state = PROCESSOR_DISPATCHING;
        !          1385:            return;
        !          1386:        }
        !          1387:        if (th->bound_processor == PROCESSOR_NULL) {
        !          1388:                rq = &(default_pset.runq);
        !          1389:        }
        !          1390:        else {
        !          1391:                rq = &(master_processor->runq);
        !          1392:                ast_on(cpu_number(), AST_BLOCK);
        !          1393:        }
        !          1394:        run_queue_enqueue(rq,th);
        !          1395: 
        !          1396:        /*
        !          1397:         * Preempt check
        !          1398:         */
        !          1399:        if (may_preempt && (current_thread()->sched_pri > th->sched_pri)) {
        !          1400:                /*
        !          1401:                 *      Turn off first_quantum to allow context switch.
        !          1402:                 */
        !          1403:                current_processor()->first_quantum = FALSE;
        !          1404:                ast_on(cpu_number(), AST_BLOCK);
        !          1405:        }
        !          1406: #endif /* NCPUS > 1 */
        !          1407: }
        !          1408: 
        !          1409: /*
        !          1410:  *     set_pri:
        !          1411:  *
        !          1412:  *     Set the priority of the specified thread to the specified
        !          1413:  *     priority.  This may cause the thread to change queues.
        !          1414:  *
        !          1415:  *     The thread *must* be locked by the caller.
        !          1416:  */
        !          1417: 
        !          1418: void set_pri(
        !          1419:        thread_t        th,
        !          1420:        int             pri,
        !          1421:        boolean_t       resched)
        !          1422: {
        !          1423:        register struct run_queue       *rq;
        !          1424: 
        !          1425:        rq = rem_runq(th);
        !          1426:        th->sched_pri = pri;
        !          1427:        if (rq != RUN_QUEUE_NULL) {
        !          1428:            if (resched)
        !          1429:                thread_setrun(th, TRUE);
        !          1430:            else
        !          1431:                run_queue_enqueue(rq, th);
        !          1432:        }
        !          1433: }
        !          1434: 
        !          1435: /*
        !          1436:  *     rem_runq:
        !          1437:  *
        !          1438:  *     Remove a thread from its run queue.
        !          1439:  *     The run queue that the process was on is returned
        !          1440:  *     (or RUN_QUEUE_NULL if not on a run queue).  Thread *must* be locked
        !          1441:  *     before calling this routine.  Unusual locking protocol on runq
        !          1442:  *     field in thread structure makes this code interesting; see thread.h.
        !          1443:  */
        !          1444: 
        !          1445: struct run_queue *rem_runq(
        !          1446:        thread_t                th)
        !          1447: {
        !          1448:        register struct run_queue       *rq;
        !          1449: 
        !          1450:        rq = th->runq;
        !          1451:        /*
        !          1452:         *      If rq is RUN_QUEUE_NULL, the thread will stay out of the
        !          1453:         *      run_queues because the caller locked the thread.  Otherwise
        !          1454:         *      the thread is on a runq, but could leave.
        !          1455:         */
        !          1456:        if (rq != RUN_QUEUE_NULL) {
        !          1457:                simple_lock(&rq->lock);
        !          1458: #if    DEBUG
        !          1459:                checkrq(rq, "rem_runq: at entry");
        !          1460: #endif /* DEBUG */
        !          1461:                if (rq == th->runq) {
        !          1462:                        /*
        !          1463:                         *      Thread is in a runq and we have a lock on
        !          1464:                         *      that runq.
        !          1465:                         */
        !          1466: #if    DEBUG
        !          1467:                        checkrq(rq, "rem_runq: before removing thread");
        !          1468:                        thread_check(th, rq);
        !          1469: #endif /* DEBUG */
        !          1470:                        remqueue(&rq->runq[0], (queue_entry_t) th);
        !          1471:                        rq->count--;
        !          1472: #if    DEBUG
        !          1473:                        checkrq(rq, "rem_runq: after removing thread");
        !          1474: #endif /* DEBUG */
        !          1475:                        th->runq = RUN_QUEUE_NULL;
        !          1476:                        simple_unlock(&rq->lock);
        !          1477:                }
        !          1478:                else {
        !          1479:                        /*
        !          1480:                         *      The thread left the runq before we could
        !          1481:                         *      lock the runq.  It is not on a runq now, and
        !          1482:                         *      can't move again because this routine's
        !          1483:                         *      caller locked the thread.
        !          1484:                         */
        !          1485:                        simple_unlock(&rq->lock);
        !          1486:                        rq = RUN_QUEUE_NULL;
        !          1487:                }
        !          1488:        }
        !          1489: 
        !          1490:        return rq;
        !          1491: }
        !          1492: 
        !          1493: 
        !          1494: /*
        !          1495:  *     choose_thread:
        !          1496:  *
        !          1497:  *     Choose a thread to execute.  The thread chosen is removed
        !          1498:  *     from its run queue.  Note that this requires only that the runq
        !          1499:  *     lock be held.
        !          1500:  *
        !          1501:  *     Strategy:
        !          1502:  *             Check processor runq first; if anything found, run it.
        !          1503:  *             Else check pset runq; if nothing found, return idle thread.
        !          1504:  *
        !          1505:  *     Second line of strategy is implemented by choose_pset_thread.
        !          1506:  *     This is only called on processor startup and when thread_block
        !          1507:  *     thinks there's something in the processor runq.
        !          1508:  */
        !          1509: 
        !          1510: thread_t choose_thread(
        !          1511:        processor_t myprocessor)
        !          1512: {
        !          1513:        thread_t th;
        !          1514:        register queue_t q;
        !          1515:        register run_queue_t runq;
        !          1516:        register int i;
        !          1517:        register processor_set_t pset;
        !          1518: 
        !          1519:        runq = &myprocessor->runq;
        !          1520: 
        !          1521:        simple_lock(&runq->lock);
        !          1522:        if (runq->count > 0) {
        !          1523:            q = runq->runq + runq->low;
        !          1524:            for (i = runq->low; i < NRQS ; i++, q++) {
        !          1525:                if (!queue_empty(q)) {
        !          1526:                    th = (thread_t) dequeue_head(q);
        !          1527:                    th->runq = RUN_QUEUE_NULL;
        !          1528:                    runq->count--;
        !          1529:                    runq->low = i;
        !          1530:                    simple_unlock(&runq->lock);
        !          1531:                    return th;
        !          1532:                }
        !          1533:            }
        !          1534:            panic("choose_thread");
        !          1535:            /*NOTREACHED*/
        !          1536:        }
        !          1537:        simple_unlock(&runq->lock);
        !          1538: 
        !          1539:        pset = myprocessor->processor_set;
        !          1540: 
        !          1541:        simple_lock(&pset->runq.lock);
        !          1542:        return choose_pset_thread(myprocessor,pset);
        !          1543: }
        !          1544: 
        !          1545: /*
        !          1546:  *     choose_pset_thread:  choose a thread from processor_set runq or
        !          1547:  *             set processor idle and choose its idle thread.
        !          1548:  *
        !          1549:  *     Caller must be at splsched and have a lock on the runq.  This
        !          1550:  *     lock is released by this routine.  myprocessor is always the current
        !          1551:  *     processor, and pset must be its processor set.
        !          1552:  *     This routine chooses and removes a thread from the runq if there
        !          1553:  *     is one (and returns it), else it sets the processor idle and
        !          1554:  *     returns its idle thread.
        !          1555:  */
        !          1556: 
        !          1557: thread_t choose_pset_thread(
        !          1558:        register processor_t    myprocessor,
        !          1559:        processor_set_t         pset)
        !          1560: {
        !          1561:        register run_queue_t runq;
        !          1562:        register thread_t th;
        !          1563:        register queue_t q;
        !          1564:        register int i;
        !          1565: 
        !          1566:        runq = &pset->runq;
        !          1567: 
        !          1568:        if (runq->count > 0) {
        !          1569:            q = runq->runq + runq->low;
        !          1570:            for (i = runq->low; i < NRQS ; i++, q++) {
        !          1571:                if (!queue_empty(q)) {
        !          1572:                    th = (thread_t) dequeue_head(q);
        !          1573:                    th->runq = RUN_QUEUE_NULL;
        !          1574:                    runq->count--;
        !          1575:                    /*
        !          1576:                     *  For POLICY_FIXEDPRI, runq->low must be
        !          1577:                     *  accurate!
        !          1578:                     */
        !          1579: #if    MACH_FIXPRI
        !          1580:                    if ((runq->count > 0) &&
        !          1581:                        (pset->policies & POLICY_FIXEDPRI)) {
        !          1582:                            while (queue_empty(q)) {
        !          1583:                                q++;
        !          1584:                                i++;
        !          1585:                            }
        !          1586:                    }
        !          1587: #endif /* MACH_FIXPRI */
        !          1588:                    runq->low = i;
        !          1589: #if    DEBUG
        !          1590:                    checkrq(runq, "choose_pset_thread");
        !          1591: #endif /* DEBUG */
        !          1592:                    simple_unlock(&runq->lock);
        !          1593:                    return th;
        !          1594:                }
        !          1595:            }
        !          1596:            panic("choose_pset_thread");
        !          1597:            /*NOTREACHED*/
        !          1598:        }
        !          1599:        simple_unlock(&runq->lock);
        !          1600: 
        !          1601:        /*
        !          1602:         *      Nothing is runnable, so set this processor idle if it
        !          1603:         *      was running.  If it was in an assignment or shutdown,
        !          1604:         *      leave it alone.  Return its idle thread.
        !          1605:         */
        !          1606:        simple_lock(&pset->idle_lock);
        !          1607:        if (myprocessor->state == PROCESSOR_RUNNING) {
        !          1608:            myprocessor->state = PROCESSOR_IDLE;
        !          1609:            /*
        !          1610:             *  XXX Until it goes away, put master on end of queue, others
        !          1611:             *  XXX on front so master gets used last.
        !          1612:             */
        !          1613:            if (myprocessor == master_processor) {
        !          1614:                queue_enter(&(pset->idle_queue), myprocessor,
        !          1615:                        processor_t, processor_queue);
        !          1616:            }
        !          1617:            else {
        !          1618:                queue_enter_first(&(pset->idle_queue), myprocessor,
        !          1619:                        processor_t, processor_queue);
        !          1620:            }
        !          1621: 
        !          1622:            pset->idle_count++;
        !          1623:        }
        !          1624:        simple_unlock(&pset->idle_lock);
        !          1625: 
        !          1626:        return myprocessor->idle_thread;
        !          1627: }
        !          1628: 
        !          1629: /*
        !          1630:  *     no_dispatch_count counts number of times processors go non-idle
        !          1631:  *     without being dispatched.  This should be very rare.
        !          1632:  */
        !          1633: int    no_dispatch_count = 0;
        !          1634: 
        !          1635: /*
        !          1636:  *     This is the idle thread, which just looks for other threads
        !          1637:  *     to execute.
        !          1638:  */
        !          1639: 
        !          1640: void idle_thread_continue(void)
        !          1641: {
        !          1642:        register processor_t myprocessor;
        !          1643:        register volatile thread_t *threadp;
        !          1644:        register volatile int *gcount;
        !          1645:        register volatile int *lcount;
        !          1646:        register thread_t new_thread;
        !          1647:        register int state;
        !          1648:        int mycpu;
        !          1649:        spl_t s;
        !          1650: 
        !          1651:        mycpu = cpu_number();
        !          1652:        myprocessor = current_processor();
        !          1653:        threadp = (volatile thread_t *) &myprocessor->next_thread;
        !          1654:        lcount = (volatile int *) &myprocessor->runq.count;
        !          1655: 
        !          1656:        while (TRUE) {
        !          1657: #ifdef MARK_CPU_IDLE
        !          1658:                MARK_CPU_IDLE(mycpu);
        !          1659: #endif /* MARK_CPU_IDLE */
        !          1660: 
        !          1661: #if    MACH_HOST
        !          1662:                gcount = (volatile int *)
        !          1663:                                &myprocessor->processor_set->runq.count;
        !          1664: #else  /* MACH_HOST */
        !          1665:                gcount = (volatile int *) &default_pset.runq.count;
        !          1666: #endif /* MACH_HOST */
        !          1667: 
        !          1668: /*
        !          1669:  *     This cpu will be dispatched (by thread_setrun) by setting next_thread
        !          1670:  *     to the value of the thread to run next.  Also check runq counts.
        !          1671:  */
        !          1672:                while ((*threadp == (volatile thread_t)THREAD_NULL) &&
        !          1673:                       (*gcount == 0) && (*lcount == 0)) {
        !          1674: 
        !          1675:                        /* check for ASTs while we wait */
        !          1676: 
        !          1677:                        if (need_ast[mycpu] &~ AST_SCHEDULING) {
        !          1678:                                (void) splsched();
        !          1679:                                /* don't allow scheduling ASTs */
        !          1680:                                need_ast[mycpu] &= ~AST_SCHEDULING;
        !          1681:                                ast_taken();
        !          1682:                                /* back at spl0 */
        !          1683:                        }
        !          1684:                        
        !          1685:                        /*
        !          1686:                         * machine_idle is a machine dependent function,
        !          1687:                         * to conserve power.
        !          1688:                         */
        !          1689: #if    POWER_SAVE
        !          1690:                        machine_idle(mycpu);
        !          1691: #endif /* POWER_SAVE */
        !          1692:                }
        !          1693: 
        !          1694: #ifdef MARK_CPU_ACTIVE
        !          1695:                MARK_CPU_ACTIVE(mycpu);
        !          1696: #endif /* MARK_CPU_ACTIVE */
        !          1697: 
        !          1698:                s = splsched();
        !          1699: 
        !          1700:                /*
        !          1701:                 *      This is not a switch statement to avoid the
        !          1702:                 *      bounds checking code in the common case.
        !          1703:                 */
        !          1704: retry:
        !          1705:                state = myprocessor->state;
        !          1706:                if (state == PROCESSOR_DISPATCHING) {
        !          1707:                        /*
        !          1708:                         *      Commmon case -- cpu dispatched.
        !          1709:                         */
        !          1710:                        new_thread = (thread_t) *threadp;
        !          1711:                        *threadp = (volatile thread_t) THREAD_NULL;
        !          1712:                        myprocessor->state = PROCESSOR_RUNNING;
        !          1713:                        /*
        !          1714:                         *      set up quantum for new thread.
        !          1715:                         */
        !          1716: #if    MACH_FIXPRI
        !          1717:                        if (new_thread->policy == POLICY_TIMESHARE) {
        !          1718: #endif /* MACH_FIXPRI */
        !          1719:                                /*
        !          1720:                                 *  Just use set quantum.  No point in
        !          1721:                                 *  checking for shorter local runq quantum;
        !          1722:                                 *  csw_needed will handle correctly.
        !          1723:                                 */
        !          1724: #if    MACH_HOST
        !          1725:                                myprocessor->quantum = new_thread->
        !          1726:                                        processor_set->set_quantum;
        !          1727: #else  /* MACH_HOST */
        !          1728:                                myprocessor->quantum =
        !          1729:                                        default_pset.set_quantum;
        !          1730: #endif /* MACH_HOST */
        !          1731: 
        !          1732: #if    MACH_FIXPRI
        !          1733:                        }
        !          1734:                        else {
        !          1735:                                /*
        !          1736:                                 *      POLICY_FIXEDPRI
        !          1737:                                 */
        !          1738:                                myprocessor->quantum = new_thread->sched_data;
        !          1739:                        }
        !          1740: #endif /* MACH_FIXPRI */
        !          1741:                        myprocessor->first_quantum = TRUE;
        !          1742:                        counter(c_idle_thread_handoff++);
        !          1743:                        thread_run(idle_thread_continue, new_thread);
        !          1744:                }
        !          1745:                else if (state == PROCESSOR_IDLE) {
        !          1746:                        register processor_set_t pset;
        !          1747: 
        !          1748:                        pset = myprocessor->processor_set;
        !          1749:                        simple_lock(&pset->idle_lock);
        !          1750:                        if (myprocessor->state != PROCESSOR_IDLE) {
        !          1751:                                /*
        !          1752:                                 *      Something happened, try again.
        !          1753:                                 */
        !          1754:                                simple_unlock(&pset->idle_lock);
        !          1755:                                goto retry;
        !          1756:                        }
        !          1757:                        /*
        !          1758:                         *      Processor was not dispatched (Rare).
        !          1759:                         *      Set it running again.
        !          1760:                         */
        !          1761:                        no_dispatch_count++;
        !          1762:                        pset->idle_count--;
        !          1763:                        queue_remove(&pset->idle_queue, myprocessor,
        !          1764:                                processor_t, processor_queue);
        !          1765:                        myprocessor->state = PROCESSOR_RUNNING;
        !          1766:                        simple_unlock(&pset->idle_lock);
        !          1767:                        counter(c_idle_thread_block++);
        !          1768:                        thread_block(idle_thread_continue);
        !          1769:                }
        !          1770:                else if ((state == PROCESSOR_ASSIGN) ||
        !          1771:                         (state == PROCESSOR_SHUTDOWN)) {
        !          1772:                        /*
        !          1773:                         *      Changing processor sets, or going off-line.
        !          1774:                         *      Release next_thread if there is one.  Actual
        !          1775:                         *      thread to run is on a runq.
        !          1776:                         */
        !          1777:                        if ((new_thread = (thread_t)*threadp)!= THREAD_NULL) {
        !          1778:                                *threadp = (volatile thread_t) THREAD_NULL;
        !          1779:                                thread_setrun(new_thread, FALSE);
        !          1780:                        }
        !          1781: 
        !          1782:                        counter(c_idle_thread_block++);
        !          1783:                        thread_block(idle_thread_continue);
        !          1784:                }
        !          1785:                else {
        !          1786:                        printf(" Bad processor state %d (Cpu %d)\n",
        !          1787:                                cpu_state(mycpu), mycpu);
        !          1788:                        panic("idle_thread");
        !          1789:                }
        !          1790: 
        !          1791:                (void) splx(s);
        !          1792:        }
        !          1793: }
        !          1794: 
        !          1795: void idle_thread(void)
        !          1796: {
        !          1797:        register thread_t self = current_thread();
        !          1798:        spl_t s;
        !          1799: 
        !          1800:        stack_privilege(self);
        !          1801: 
        !          1802:        s = splsched();
        !          1803:        self->priority = 31;
        !          1804:        self->sched_pri = 31;
        !          1805: 
        !          1806:        /*
        !          1807:         *      Set the idle flag to indicate that this is an idle thread,
        !          1808:         *      enter ourselves in the idle array, and thread_block() to get
        !          1809:         *      out of the run queues (and set the processor idle when we
        !          1810:         *      run next time).
        !          1811:         */
        !          1812:        thread_lock(self);
        !          1813:        self->state |= TH_IDLE;
        !          1814:        thread_unlock(self);
        !          1815:        current_processor()->idle_thread = self;
        !          1816:        (void) splx(s);
        !          1817: 
        !          1818:        counter(c_idle_thread_block++);
        !          1819:        thread_block(idle_thread_continue);
        !          1820:        idle_thread_continue();
        !          1821:        /*NOTREACHED*/
        !          1822: }
        !          1823: 
        !          1824: /*
        !          1825:  *     sched_thread: scheduler thread.
        !          1826:  *
        !          1827:  *     This thread handles periodic calculations in the scheduler that
        !          1828:  *     we don't want to do at interrupt level.  This allows us to
        !          1829:  *     avoid blocking.
        !          1830:  */
        !          1831: void sched_thread_continue(void)
        !          1832: {
        !          1833:     while (TRUE) {
        !          1834:        (void) compute_mach_factor();
        !          1835: 
        !          1836:        /*
        !          1837:         *      Check for stuck threads.  This can't be done off of
        !          1838:         *      the callout queue because it requires operations that
        !          1839:         *      can't be used from interrupt level.
        !          1840:         */
        !          1841:        if (sched_tick & 1)
        !          1842:                do_thread_scan();
        !          1843: 
        !          1844:        assert_wait((event_t) 0, FALSE);
        !          1845:        counter(c_sched_thread_block++);
        !          1846:        thread_block(sched_thread_continue);
        !          1847:     }
        !          1848: }
        !          1849: 
        !          1850: void sched_thread(void)
        !          1851: {
        !          1852:     sched_thread_id = current_thread();
        !          1853: 
        !          1854:     /*
        !          1855:      * Sleep on event 0, recompute_priorities() will awaken
        !          1856:      * us by calling clear_wait().
        !          1857:      */
        !          1858:     assert_wait((event_t) 0, FALSE);
        !          1859:     counter(c_sched_thread_block++);
        !          1860:     thread_block(sched_thread_continue);
        !          1861:     sched_thread_continue();
        !          1862:     /*NOTREACHED*/
        !          1863: }
        !          1864: 
        !          1865: #define        MAX_STUCK_THREADS       16
        !          1866: 
        !          1867: /*
        !          1868:  *     do_thread_scan: scan for stuck threads.  A thread is stuck if
        !          1869:  *     it is runnable but its priority is so low that it has not
        !          1870:  *     run for several seconds.  Its priority should be higher, but
        !          1871:  *     won't be until it runs and calls update_priority.  The scanner
        !          1872:  *     finds these threads and does the updates.
        !          1873:  *
        !          1874:  *     Scanner runs in two passes.  Pass one squirrels likely
        !          1875:  *     thread ids away in an array, and removes them from the run queue.
        !          1876:  *     Pass two does the priority updates.  This is necessary because
        !          1877:  *     the run queue lock is required for the candidate scan, but
        !          1878:  *     cannot be held during updates [set_pri will deadlock].
        !          1879:  *
        !          1880:  *     Array length should be enough so that restart isn't necessary,
        !          1881:  *     but restart logic is included.  Does not scan processor runqs.
        !          1882:  *
        !          1883:  */
        !          1884: 
        !          1885: boolean_t do_thread_scan_debug = FALSE;
        !          1886: 
        !          1887: thread_t               stuck_threads[MAX_STUCK_THREADS];
        !          1888: int                    stuck_count = 0;
        !          1889: 
        !          1890: /*
        !          1891:  *     do_runq_scan is the guts of pass 1.  It scans a runq for
        !          1892:  *     stuck threads.  A boolean is returned indicating whether
        !          1893:  *     it ran out of space.
        !          1894:  */
        !          1895: 
        !          1896: boolean_t
        !          1897: do_runq_scan(
        !          1898:        run_queue_t     runq)
        !          1899: {
        !          1900:        register spl_t          s;
        !          1901:        register queue_t        q;
        !          1902:        register thread_t       thread;
        !          1903:        register int            count;
        !          1904: 
        !          1905:        s = splsched();
        !          1906:        simple_lock(&runq->lock);
        !          1907:        if((count = runq->count) > 0) {
        !          1908:            q = runq->runq + runq->low;
        !          1909:            while (count > 0) {
        !          1910:                thread = (thread_t) queue_first(q);
        !          1911:                while (!queue_end(q, (queue_entry_t) thread)) {
        !          1912:                    /*
        !          1913:                     *  Get the next thread now, since we may
        !          1914:                     *  remove this thread from the run queue.
        !          1915:                     */
        !          1916:                    thread_t next = (thread_t) queue_next(&thread->links);
        !          1917: 
        !          1918:                    if ((thread->state & TH_SCHED_STATE) == TH_RUN &&
        !          1919:                        sched_tick - thread->sched_stamp > 1) {
        !          1920:                            /*
        !          1921:                             *  Stuck, save its id for later.
        !          1922:                             */
        !          1923:                            if (stuck_count == MAX_STUCK_THREADS) {
        !          1924:                                /*
        !          1925:                                 *      !@#$% No more room.
        !          1926:                                 */
        !          1927:                                simple_unlock(&runq->lock);
        !          1928:                                splx(s);
        !          1929:                                return TRUE;
        !          1930:                            }
        !          1931:                            /*
        !          1932:                             *  We can`t take the thread_lock here,
        !          1933:                             *  since we already have the runq lock.
        !          1934:                             *  So we can`t grab a reference to the
        !          1935:                             *  thread.  However, a thread that is
        !          1936:                             *  in RUN state cannot be deallocated
        !          1937:                             *  until it stops running.  If it isn`t
        !          1938:                             *  on the runq, then thread_halt cannot
        !          1939:                             *  see it.  So we remove the thread
        !          1940:                             *  from the runq to make it safe.
        !          1941:                             */
        !          1942:                            remqueue(q, (queue_entry_t) thread);
        !          1943:                            runq->count--;
        !          1944:                            thread->runq = RUN_QUEUE_NULL;
        !          1945: 
        !          1946:                            stuck_threads[stuck_count++] = thread;
        !          1947: if (do_thread_scan_debug)
        !          1948:     printf("do_runq_scan: adding thread %#x\n", thread);
        !          1949:                    }
        !          1950:                    count--;
        !          1951:                    thread = next;
        !          1952:                }
        !          1953:                q++;
        !          1954:            }
        !          1955:        }
        !          1956:        simple_unlock(&runq->lock);
        !          1957:        splx(s);
        !          1958: 
        !          1959:        return FALSE;
        !          1960: }
        !          1961: 
        !          1962: void do_thread_scan(void)
        !          1963: {
        !          1964:        register spl_t          s;
        !          1965:        register boolean_t      restart_needed = 0;
        !          1966:        register thread_t       thread;
        !          1967: #if    MACH_HOST
        !          1968:        register processor_set_t        pset;
        !          1969: #endif /* MACH_HOST */
        !          1970: 
        !          1971:        do {
        !          1972: #if    MACH_HOST
        !          1973:            simple_lock(&all_psets_lock);
        !          1974:            queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
        !          1975:                if (restart_needed = do_runq_scan(&pset->runq))
        !          1976:                        break;
        !          1977:            }
        !          1978:            simple_unlock(&all_psets_lock);
        !          1979: #else  /* MACH_HOST */
        !          1980:            restart_needed = do_runq_scan(&default_pset.runq);
        !          1981: #endif /* MACH_HOST */
        !          1982:            if (!restart_needed)
        !          1983:                restart_needed = do_runq_scan(&master_processor->runq);
        !          1984: 
        !          1985:            /*
        !          1986:             *  Ok, we now have a collection of candidates -- fix them.
        !          1987:             */
        !          1988: 
        !          1989:            while (stuck_count > 0) {
        !          1990:                thread = stuck_threads[--stuck_count];
        !          1991:                stuck_threads[stuck_count] = THREAD_NULL;
        !          1992:                s = splsched();
        !          1993:                thread_lock(thread);
        !          1994:                if ((thread->state & TH_SCHED_STATE) == TH_RUN) {
        !          1995:                        /*
        !          1996:                         *      Do the priority update.  Call
        !          1997:                         *      thread_setrun because thread is
        !          1998:                         *      off the run queues.
        !          1999:                         */
        !          2000:                        update_priority(thread);
        !          2001:                        thread_setrun(thread, TRUE);
        !          2002:                }
        !          2003:                thread_unlock(thread);
        !          2004:                splx(s);
        !          2005:            }
        !          2006:        } while (restart_needed);
        !          2007: }
        !          2008:                
        !          2009: #if    DEBUG
        !          2010: void checkrq(
        !          2011:        run_queue_t     rq,
        !          2012:        char            *msg)
        !          2013: {
        !          2014:        register queue_t        q1;
        !          2015:        register int            i, j;
        !          2016:        register queue_entry_t  e;
        !          2017:        register int            low;
        !          2018: 
        !          2019:        low = -1;
        !          2020:        j = 0;
        !          2021:        q1 = rq->runq;
        !          2022:        for (i = 0; i < NRQS; i++) {
        !          2023:            if (q1->next == q1) {
        !          2024:                if (q1->prev != q1)
        !          2025:                    panic("checkrq: empty at %s", msg);
        !          2026:            }
        !          2027:            else {
        !          2028:                if (low == -1)
        !          2029:                    low = i;
        !          2030:                
        !          2031:                for (e = q1->next; e != q1; e = e->next) {
        !          2032:                    j++;
        !          2033:                    if (e->next->prev != e)
        !          2034:                        panic("checkrq-2 at %s", msg);
        !          2035:                    if (e->prev->next != e)
        !          2036:                        panic("checkrq-3 at %s", msg);
        !          2037:                }
        !          2038:            }
        !          2039:            q1++;
        !          2040:        }
        !          2041:        if (j != rq->count)
        !          2042:            panic("checkrq: count wrong at %s", msg);
        !          2043:        if (rq->count != 0 && low < rq->low)
        !          2044:            panic("checkrq: low wrong at %s", msg);
        !          2045: }
        !          2046: 
        !          2047: void thread_check(
        !          2048:        register thread_t       th,
        !          2049:        register run_queue_t    rq)
        !          2050: {
        !          2051:        register unsigned int   whichq;
        !          2052: 
        !          2053:        whichq = th->sched_pri;
        !          2054:        if (whichq >= NRQS) {
        !          2055:                printf("thread_check: priority too high\n");
        !          2056:                whichq = NRQS-1;
        !          2057:        }
        !          2058:        if ((th->links.next == &rq->runq[whichq]) &&
        !          2059:                (rq->runq[whichq].prev != (queue_entry_t)th))
        !          2060:                        panic("thread_check");
        !          2061: }
        !          2062: #endif /* DEBUG */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.