Annotation of kernel/kern/ipc_sched.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1993, 1992,1991,1990 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: 
                     51: #include <cpus.h>
                     52: #include <mach_host.h>
                     53: 
                     54: #include <mach/message.h>
                     55: #include <kern/counters.h>
                     56: #include <kern/cpu_number.h>
                     57: #include <kern/lock.h>
                     58: #include <kern/thread.h>
                     59: #include <kern/sched_prim.h>
                     60: #include <kern/processor.h>
                     61: #include <kern/time_out.h>
                     62: #include <kern/thread_swap.h>
                     63: #include <kern/ipc_sched.h>
                     64: #include <machine/machspl.h>   /* for splsched/splx */
                     65: #include <machine/pmap.h>
                     66: 
                     67: #import <kern/assert.h>
                     68: 
                     69: 
                     70: /*
                     71:  *     These functions really belong in kern/sched_prim.c.
                     72:  */
                     73: 
                     74: /*
                     75:  *     Routine:        thread_go
                     76:  *     Purpose:
                     77:  *             Start a thread running.
                     78:  *     Conditions:
                     79:  *             IPC locks may be held.
                     80:  */
                     81: 
                     82: void
                     83: thread_go(
                     84:        thread_t thread)
                     85: {
                     86:        int     state;
                     87:        spl_t   s;
                     88: 
                     89:        s = splsched();
                     90:        thread_lock(thread);
                     91: 
                     92:        reset_timeout_check(&thread->timer);
                     93: 
                     94:        state = thread->state;
                     95:        switch (state & TH_SCHED_STATE) {
                     96: 
                     97:            case TH_WAIT | TH_SUSP | TH_UNINT:
                     98:            case TH_WAIT           | TH_UNINT:
                     99:            case TH_WAIT:
                    100:                /*
                    101:                 *      Sleeping and not suspendable - put
                    102:                 *      on run queue.
                    103:                 */
                    104:                thread->state = (state &~ TH_WAIT) | TH_RUN;
                    105:                thread->wait_result = THREAD_AWAKENED;
                    106:                thread_setrun(thread, TRUE);
                    107:                break;
                    108: 
                    109:            case          TH_WAIT | TH_SUSP:
                    110:            case TH_RUN | TH_WAIT:
                    111:            case TH_RUN | TH_WAIT | TH_SUSP:
                    112:            case TH_RUN | TH_WAIT           | TH_UNINT:
                    113:            case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
                    114:                /*
                    115:                 *      Either already running, or suspended.
                    116:                 */
                    117:                thread->state = state & ~TH_WAIT;
                    118:                thread->wait_result = THREAD_AWAKENED;
                    119:                break;
                    120: 
                    121:            default:
                    122:                /*
                    123:                 *      Not waiting.
                    124:                 */
                    125:                break;
                    126:        }
                    127: 
                    128:        thread_unlock(thread);
                    129:        splx(s);
                    130: }
                    131: 
                    132: /*
                    133:  *     Routine:        thread_go_and_switch
                    134:  *     Purpose:
                    135:  *             Start a thread running.
                    136:  *     Conditions:
                    137:  *             No IPC locks held.
                    138:  */
                    139: 
                    140: void
                    141: thread_go_and_switch(
                    142:        continuation_t continuation,
                    143:        thread_t thread)
                    144: {
                    145:        int     state;
                    146:        spl_t   s;
                    147: 
                    148:        s = splsched();
                    149:        thread_lock(thread);
                    150: 
                    151:        reset_timeout_check(&thread->timer);
                    152: 
                    153:        state = thread->state;
                    154:        switch (state & TH_SCHED_STATE) {
                    155: 
                    156:            case TH_WAIT | TH_SUSP | TH_UNINT:
                    157:            case TH_WAIT           | TH_UNINT:
                    158:            case TH_WAIT:
                    159:                /*
                    160:                 *      Sleeping and not suspendable - put
                    161:                 *      on run queue.
                    162:                 */
                    163:                thread->state = (state &~ TH_WAIT) | TH_RUN;
                    164:                thread->wait_result = THREAD_AWAKENED;
                    165:                if ((thread->processor_set->idle_count > 0) ||
                    166:                    (thread->processor_set !=
                    167:                     current_thread()->processor_set)) {
                    168:                        /*
                    169:                         *      Other cpus can/must run thread.
                    170:                         *      Put it on the run queues.
                    171:                         */
                    172:                        thread_setrun(thread, TRUE);
                    173:                        break;
                    174:                }
                    175:                else {
                    176:                    /*
                    177:                     *  Switch immediately to new thread.
                    178:                     */
                    179:                    thread_unlock(thread);
                    180:                    thread_run(continuation, thread);
                    181:                    splx(s);
                    182:                    return;
                    183:                }
                    184:                break;
                    185: 
                    186:            case          TH_WAIT | TH_SUSP:
                    187:            case TH_RUN | TH_WAIT:
                    188:            case TH_RUN | TH_WAIT | TH_SUSP:
                    189:            case TH_RUN | TH_WAIT           | TH_UNINT:
                    190:            case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
                    191:                /*
                    192:                 *      Either already running, or suspended.
                    193:                 */
                    194:                thread->state = state & ~TH_WAIT;
                    195:                thread->wait_result = THREAD_AWAKENED;
                    196:                break;
                    197: 
                    198:            default:
                    199:                /*
                    200:                 *      Not waiting.
                    201:                 */
                    202:                break;
                    203:        }
                    204: 
                    205:        thread_unlock(thread);
                    206:        if (continuation != (void (*)()) 0) {
                    207:            (void) spl0();
                    208:            call_continuation(continuation);
                    209:        }
                    210:        splx(s);
                    211: }
                    212: 
                    213: /*
                    214:  *     Routine:        thread_will_wait
                    215:  *     Purpose:
                    216:  *             Assert that the thread intends to block.
                    217:  */
                    218: 
                    219: void
                    220: thread_will_wait(
                    221:        thread_t thread)
                    222: {
                    223:        spl_t   s;
                    224: 
                    225:        s = splsched();
                    226:        thread_lock(thread);
                    227: 
                    228:        assert(thread->wait_result = -1);       /* for later assertions */
                    229:        thread->state |= TH_WAIT;
                    230: 
                    231:        thread_unlock(thread);
                    232:        splx(s);
                    233: }
                    234: 
                    235: /*
                    236:  *     Routine:        thread_will_wait_with_timeout
                    237:  *     Purpose:
                    238:  *             Assert that the thread intends to block,
                    239:  *             with a timeout.
                    240:  */
                    241: 
                    242: void
                    243: thread_will_wait_with_timeout(
                    244:        thread_t thread,
                    245:        mach_msg_timeout_t msecs)
                    246: {
                    247:        natural_t ticks = convert_ipc_timeout_to_ticks(msecs);
                    248:        spl_t   s;
                    249: 
                    250:        s = splsched();
                    251:        thread_lock(thread);
                    252: 
                    253:        assert(thread->wait_result = -1);       /* for later assertions */
                    254:        thread->state |= TH_WAIT;
                    255: 
                    256:        if (ticks != 0 || msecs == 0)
                    257:                set_timeout(&thread->timer, ticks);
                    258: 
                    259:        thread_unlock(thread);
                    260:        splx(s);
                    261: }
                    262: 
                    263: #if    MACH_HOST
                    264: #define check_processor_set(thread)    \
                    265:            (current_processor()->processor_set == (thread)->processor_set)
                    266: #else  /* MACH_HOST */
                    267: #define        check_processor_set(thread)     TRUE
                    268: #endif /* MACH_HOST */
                    269: 
                    270: #if    NCPUS > 1
                    271: #define        check_bound_processor(thread) \
                    272:            ((thread)->bound_processor == PROCESSOR_NULL || \
                    273:             (thread)->bound_processor == current_processor())
                    274: #else  /* NCPUS > 1 */
                    275: #define        check_bound_processor(thread)   TRUE
                    276: #endif /* NCPUS > 1 */
                    277: 
                    278: /*
                    279:  *     Routine:        thread_handoff
                    280:  *     Purpose:
                    281:  *             Switch to a new thread (new), leaving the current
                    282:  *             thread (old) blocked.  If successful, moves the
                    283:  *             kernel stack from old to new and returns as the
                    284:  *             new thread.  An explicit continuation for the old thread
                    285:  *             must be supplied.
                    286:  *
                    287:  *             NOTE:  Although we wakeup new, we don't set new->wait_result.
                    288:  *     Returns:
                    289:  *             TRUE if the handoff happened.
                    290:  */
                    291: 
                    292: boolean_t
                    293: thread_handoff(
                    294:        register thread_t old,
                    295:        register continuation_t continuation,
                    296:        register thread_t new)
                    297: {
                    298:        spl_t   s;
                    299: 
                    300:        assert(current_thread() == old);
                    301: 
                    302:        /*
                    303:         *      XXX Dubious things here:
                    304:         *      I don't check the idle_count on the processor set.
                    305:         *      No scheduling priority or policy checks.
                    306:         *      I assume the new thread is interruptible.
                    307:         */
                    308: 
                    309:        s = splsched();
                    310:        thread_lock(new);
                    311: 
                    312:        /*
                    313:         *      The first thing we must do is check the state
                    314:         *      of the threads, to ensure we can handoff.
                    315:         *      This check uses current_processor()->processor_set,
                    316:         *      which we can read without locking.
                    317:         */
                    318: 
                    319:        if ((old->stack_privilege == current_stack()) ||
                    320:            (new->state != (TH_WAIT|TH_SWAPPED)) ||
                    321:             !check_processor_set(new) ||
                    322:             !check_bound_processor(new)) {
                    323:                thread_unlock(new);
                    324:                (void) splx(s);
                    325: 
                    326:                counter_always(c_thread_handoff_misses++);
                    327:                return FALSE;
                    328:        }
                    329: 
                    330:        reset_timeout_check(&new->timer);
                    331: 
                    332:        new->state = TH_RUN;
                    333:        thread_unlock(new);
                    334: 
                    335: #if    NCPUS > 1
                    336:        new->last_processor = current_processor();
                    337: #endif /* NCPUS > 1 */
                    338: 
                    339:        ast_context(new, cpu_number());
                    340:        timer_switch(&new->system_timer);
                    341: 
                    342:        /*
                    343:         *      stack_handoff is machine-dependent.  It does the
                    344:         *      machine-dependent components of a context-switch, like
                    345:         *      changing address spaces.  It updates active_threads.
                    346:         */
                    347: 
                    348:        stack_handoff(old, new);
                    349: 
                    350:        /*
                    351:         *      Now we must dispose of the old thread.
                    352:         *      This is like thread_continue, except
                    353:         *      that the old thread isn't waiting yet.
                    354:         */
                    355: 
                    356:        thread_lock(old);
                    357:        old->swap_func = continuation;
                    358:        assert(old->wait_result = -1);          /* for later assertions */
                    359: 
                    360:        if (old->state == TH_RUN) {
                    361:                /*
                    362:                 *      This is our fast path.
                    363:                 */
                    364: 
                    365:                old->state = TH_WAIT|TH_SWAPPED;
                    366:        }
                    367:        else if (old->state == (TH_RUN|TH_SUSP)) {
                    368:                /*
                    369:                 *      Somebody is trying to suspend the thread.
                    370:                 */
                    371: 
                    372:                old->state = TH_WAIT|TH_SUSP|TH_SWAPPED;
                    373:                if (old->wake_active) {
                    374:                        /*
                    375:                         *      Someone wants to know when the thread
                    376:                         *      really stops.
                    377:                         */
                    378:                        old->wake_active = FALSE;
                    379:                        thread_unlock(old);
                    380:                        thread_wakeup((event_t)&old->wake_active);
                    381:                        goto after_old_thread;
                    382:                }
                    383:        } else
                    384:                panic("thread_handoff");
                    385: 
                    386:        thread_unlock(old);
                    387:     after_old_thread:
                    388:        (void) splx(s);
                    389: 
                    390:        counter_always(c_thread_handoff_hits++);
                    391:        return TRUE;
                    392: }

unix.superglobalmegacorp.com

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