Annotation of kernel/kern/syscall_subr.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) 1991,1990,1989,1988,1987 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 <mach_fixpri.h>
                     52: #include <cpus.h>
                     53: 
                     54: #include <mach/boolean.h>
                     55: #include <mach/thread_switch.h>
                     56: #include <ipc/ipc_port.h>
                     57: #include <ipc/ipc_space.h>
                     58: #include <kern/counters.h>
                     59: #include <kern/ipc_kobject.h>
                     60: #include <kern/processor.h>
                     61: #include <kern/sched.h>
                     62: #include <kern/sched_prim.h>
                     63: #include <kern/ipc_sched.h>
                     64: #include <kern/task.h>
                     65: #include <kern/thread.h>
                     66: #include <kern/time_out.h>
                     67: #include <machine/machspl.h>   /* for splsched */
                     68: 
                     69: #if    MACH_FIXPRI
                     70: #include <mach/policy.h>
                     71: #endif MACH_FIXPRI
                     72: 
                     73: 
                     74: 
                     75: /*
                     76:  *     swtch and swtch_pri both attempt to context switch (logic in
                     77:  *     thread_block no-ops the context switch if nothing would happen).
                     78:  *     A boolean is returned that indicates whether there is anything
                     79:  *     else runnable.
                     80:  *
                     81:  *     This boolean can be used by a thread waiting on a
                     82:  *     lock or condition:  If FALSE is returned, the thread is justified
                     83:  *     in becoming a resource hog by continuing to spin because there's
                     84:  *     nothing else useful that the processor could do.  If TRUE is
                     85:  *     returned, the thread should make one more check on the
                     86:  *     lock and then be a good citizen and really suspend.
                     87:  */
                     88: 
                     89: extern void thread_depress_priority();
                     90: extern kern_return_t thread_depress_abort();
                     91: 
                     92: void swtch_continue()
                     93: {
                     94:        register processor_t    myprocessor;
                     95: 
                     96:        myprocessor = current_processor();
                     97:        thread_syscall_return(myprocessor->runq.count > 0 ||
                     98:                              myprocessor->processor_set->runq.count > 0);
                     99:        /*NOTREACHED*/
                    100: }
                    101: 
                    102: boolean_t swtch()
                    103: {
                    104:        register processor_t    myprocessor;
                    105: 
                    106: #if    NCPUS > 1
                    107:        myprocessor = current_processor();
                    108:        if (myprocessor->runq.count == 0 &&
                    109:            myprocessor->processor_set->runq.count == 0)
                    110:                return(FALSE);
                    111: #endif NCPUS > 1
                    112: 
                    113:        counter(c_swtch_block++);
                    114:        thread_block_with_continuation(swtch_continue);
                    115:        myprocessor = current_processor();
                    116:        return(myprocessor->runq.count > 0 ||
                    117:               myprocessor->processor_set->runq.count > 0);
                    118: }
                    119: 
                    120: void swtch_pri_continue()
                    121: {
                    122:        register thread_t       thread = current_thread();
                    123:        register processor_t    myprocessor;
                    124: 
                    125:        if (thread->depress_priority >= 0)
                    126:                (void) thread_depress_abort(thread);
                    127:        myprocessor = current_processor();
                    128:        thread_syscall_return(myprocessor->runq.count > 0 ||
                    129:                              myprocessor->processor_set->runq.count > 0);
                    130:        /*NOTREACHED*/
                    131: }
                    132: 
                    133: boolean_t  swtch_pri(pri)
                    134:        int pri;
                    135: {
                    136:        register thread_t       thread = current_thread();
                    137:        register processor_t    myprocessor;
                    138: 
                    139: #ifdef lint
                    140:        pri++;
                    141: #endif lint
                    142: 
                    143: #if    NCPUS > 1
                    144:        myprocessor = current_processor();
                    145:        if (myprocessor->runq.count == 0 &&
                    146:            myprocessor->processor_set->runq.count == 0)
                    147:                return(FALSE);
                    148: #endif NCPUS > 1
                    149: 
                    150:        /*
                    151:         *      XXX need to think about depression duration.
                    152:         *      XXX currently using min quantum.
                    153:         */
                    154:        thread_depress_priority(thread, min_quantum);
                    155: 
                    156:        counter(c_swtch_pri_block++);
                    157:        thread_block_with_continuation(swtch_pri_continue);
                    158: 
                    159:        if (thread->depress_priority >= 0)
                    160:                (void) thread_depress_abort(thread);
                    161:        myprocessor = current_processor();
                    162:        return(myprocessor->runq.count > 0 ||
                    163:               myprocessor->processor_set->runq.count > 0);
                    164: }
                    165: 
                    166: extern int hz;
                    167: 
                    168: void thread_switch_continue()
                    169: {
                    170:        register thread_t       cur_thread = current_thread();
                    171: 
                    172:        /*
                    173:         *  Restore depressed priority                   
                    174:         */
                    175:        if (cur_thread->depress_priority >= 0)
                    176:                (void) thread_depress_abort(cur_thread);
                    177:        thread_syscall_return(KERN_SUCCESS);
                    178:        /*NOTREACHED*/
                    179: }
                    180: 
                    181: /*
                    182:  *     thread_switch:
                    183:  *
                    184:  *     Context switch.  User may supply thread hint.
                    185:  *
                    186:  *     Fixed priority threads that call this get what they asked for
                    187:  *     even if that violates priority order.
                    188:  */
                    189: kern_return_t thread_switch(thread_name, option, option_time)
                    190: mach_port_t thread_name;
                    191: int option;
                    192: mach_msg_timeout_t option_time;
                    193: {
                    194:     register thread_t          cur_thread = current_thread();
                    195:     register processor_t       myprocessor;
                    196:     kern_return_t              result;
                    197:     ipc_port_t                 port;
                    198: 
                    199:     /*
                    200:      * Process option.
                    201:      */
                    202:     switch (option) {
                    203:        case SWITCH_OPTION_NONE:
                    204:            /*
                    205:             *  Nothing to do.
                    206:             */
                    207:            break;
                    208: 
                    209:        case SWITCH_OPTION_DEPRESS:
                    210:            /*
                    211:             *  Depress priority for given time.
                    212:             */
                    213:            thread_depress_priority(cur_thread, option_time);
                    214:            break;
                    215: 
                    216:        case SWITCH_OPTION_WAIT:
                    217:            thread_will_wait_with_timeout(cur_thread, option_time);
                    218:            break;
                    219: 
                    220:        default:
                    221:            return(KERN_INVALID_ARGUMENT);
                    222:     }
                    223:     
                    224:     /*
                    225:      * Check and act on thread hint if appropriate.
                    226:      */
                    227:     if ((thread_name != 0) &&
                    228:        ((result = ipc_port_translate_send(cur_thread->task->itk_space,
                    229:                                 thread_name, &port)) == KERN_SUCCESS)) {
                    230:            /* port is locked, but it might not be active */
                    231: 
                    232:            /*
                    233:             *  Get corresponding thread.
                    234:             */
                    235:            if (ip_active(port) && (ip_kotype(port) == IKOT_THREAD)) {
                    236:                register thread_t thread;
                    237:                register spl_t s;
                    238: 
                    239:                thread = (thread_t) port->ip_kobject;
                    240:                /*
                    241:                 *      Check if the thread is in the right pset. Then
                    242:                 *      pull it off its run queue.  If it
                    243:                 *      doesn't come, then it's not eligible.
                    244:                 */
                    245:                s = splsched();
                    246:                thread_lock(thread);
                    247:                if ((thread->processor_set == cur_thread->processor_set)
                    248:                    && (rem_runq(thread) != RUN_QUEUE_NULL)) {
                    249:                        /*
                    250:                         *      Hah, got it!!
                    251:                         */
                    252:                        thread_unlock(thread);
                    253:                        (void) splx(s);
                    254:                        ip_unlock(port);
                    255:                        /* XXX thread might disappear on us now? */
                    256: #if    MACH_FIXPRI
                    257:                        if (thread->policy == POLICY_FIXEDPRI) {
                    258:                            myprocessor = current_processor();
                    259:                            myprocessor->quantum = thread->sched_data;
                    260:                            myprocessor->first_quantum = TRUE;
                    261:                        }
                    262: #endif MACH_FIXPRI
                    263:                        counter(c_thread_switch_handoff++);
                    264:                        thread_run(thread_switch_continue, thread);
                    265:                        /*
                    266:                         *  Restore depressed priority                   
                    267:                         */
                    268:                        if (cur_thread->depress_priority >= 0)
                    269:                                (void) thread_depress_abort(cur_thread);
                    270: 
                    271:                        return(KERN_SUCCESS);
                    272:                }
                    273:                thread_unlock(thread);
                    274:                (void) splx(s);
                    275:            }
                    276:            ip_unlock(port);
                    277:     }
                    278:     else if (thread_name != 0 && result == KERN_INVALID_NAME)
                    279:        return (KERN_INVALID_ARGUMENT);
                    280: 
                    281:     /*
                    282:      * No handoff hint supplied, or hint was wrong.  Call thread_block() in
                    283:      * hopes of running something else.  If nothing else is runnable,
                    284:      * thread_block will detect this.  WARNING: thread_switch with no
                    285:      * option will not do anything useful if the thread calling it is the
                    286:      * highest priority thread (can easily happen with a collection
                    287:      * of timesharing threads).
                    288:      */
                    289: #if    NCPUS > 1
                    290:     myprocessor = current_processor();
                    291:     if (myprocessor->processor_set->runq.count > 0 ||
                    292:        myprocessor->runq.count > 0)
                    293: #endif NCPUS > 1
                    294:            thread_block_with_continuation(thread_switch_continue);
                    295: 
                    296:     /*
                    297:      *  Restore depressed priority                      
                    298:      */
                    299:     if (cur_thread->depress_priority >= 0)
                    300:        (void) thread_depress_abort(cur_thread);
                    301:     return(KERN_SUCCESS);
                    302: }
                    303: 
                    304: /*
                    305:  *     thread_depress_priority
                    306:  *
                    307:  *     Depress thread's priority to lowest possible for specified period.
                    308:  *     Intended for use when thread wants a lock but doesn't know which
                    309:  *     other thread is holding it.  As with thread_switch, fixed
                    310:  *     priority threads get exactly what they asked for.  Users access
                    311:  *     this by the SWITCH_OPTION_DEPRESS option to thread_switch.  A Time
                    312:  *      of zero will result in no timeout being scheduled.
                    313:  */
                    314: void
                    315: thread_depress_priority(thread, depress_time)
                    316: register thread_t thread;
                    317: mach_msg_timeout_t depress_time;
                    318: {
                    319:     unsigned int ticks;
                    320:     spl_t      s;
                    321: 
                    322:     /* convert from milliseconds to ticks */
                    323:     ticks = convert_ipc_timeout_to_ticks(depress_time);
                    324: 
                    325:     s = splsched();
                    326:     thread_lock(thread);
                    327: 
                    328:     /*
                    329:      * If thread is already depressed, override previous depression.
                    330:      */
                    331:     reset_timeout_check(&thread->depress_timer);
                    332: 
                    333:     /*
                    334:      * Save current priority, then set priority and
                    335:      * sched_pri to their lowest possible values.
                    336:      */
                    337:     thread->depress_priority = thread->priority;
                    338:     thread->priority = 0;
                    339:     thread->sched_pri = 0;
                    340:     if (ticks != 0)
                    341:        set_timeout(&thread->depress_timer, ticks);
                    342: 
                    343:     thread_unlock(thread);
                    344:     (void) splx(s);
                    345: }      
                    346: 
                    347: /*
                    348:  *     thread_depress_timeout:
                    349:  *
                    350:  *     Timeout routine for priority depression.
                    351:  */
                    352: void
                    353: thread_depress_timeout(thread)
                    354: register thread_t thread;
                    355: {
                    356:     spl_t      s;
                    357: 
                    358:     s = splsched();
                    359:     thread_lock(thread);
                    360: 
                    361:     /*
                    362:      * If we lose a race with thread_depress_abort,
                    363:      * then depress_priority might be -1.
                    364:      */
                    365: 
                    366:     if (thread->depress_priority >= 0) {
                    367:        thread->priority = thread->depress_priority;
                    368:        thread->depress_priority = -1;
                    369:        compute_priority(thread, FALSE);
                    370:     }
                    371: 
                    372:     thread_unlock(thread);
                    373:     (void) splx(s);
                    374: }
                    375: 
                    376: /*
                    377:  *     thread_depress_abort:
                    378:  *
                    379:  *     Prematurely abort priority depression if there is one.
                    380:  */
                    381: kern_return_t
                    382: thread_depress_abort(thread)
                    383: register thread_t      thread;
                    384: {
                    385:     spl_t      s;
                    386: 
                    387:     if (thread == THREAD_NULL)
                    388:        return(KERN_INVALID_ARGUMENT);
                    389: 
                    390:     s = splsched();
                    391:     thread_lock(thread);
                    392: 
                    393:     /*
                    394:      * Only restore priority if thread is depressed.
                    395:      */
                    396:     if (thread->depress_priority >= 0) {
                    397:        reset_timeout_check(&thread->depress_timer);
                    398:        thread->priority = thread->depress_priority;
                    399:        thread->depress_priority = -1;
                    400:        compute_priority(thread, FALSE);
                    401:     }
                    402: 
                    403:     thread_unlock(thread);
                    404:     (void) splx(s);
                    405:     return(KERN_SUCCESS);
                    406: }

unix.superglobalmegacorp.com

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