123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- /*
- * Mach Operating System
- * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
- * Copyright (c) 1993,1994 The University of Utah and
- * the Computer Systems Laboratory (CSL).
- * All rights reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
- * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
- * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
- * THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- *
- * This file contains routines to check whether an ast is needed.
- *
- * ast_check() - check whether ast is needed for interrupt or context
- * switch. Usually called by clock interrupt handler.
- *
- */
- #include <kern/ast.h>
- #include <kern/counters.h>
- #include <kern/debug.h>
- #include "cpu_number.h"
- #include <kern/queue.h>
- #include <kern/sched.h>
- #include <kern/sched_prim.h>
- #include <kern/thread.h>
- #include <kern/processor.h>
- #include <device/net_io.h>
- #include <machine/machspl.h> /* for splsched */
- #if MACH_FIXPRI
- #include <mach/policy.h>
- #endif /* MACH_FIXPRI */
- volatile ast_t need_ast[NCPUS];
- void
- ast_init(void)
- {
- #ifndef MACHINE_AST
- int i;
- for (i=0; i<NCPUS; i++)
- need_ast[i] = 0;
- #endif /* MACHINE_AST */
- }
- void
- ast_taken(void)
- {
- thread_t self = current_thread();
- ast_t reasons;
- /*
- * Interrupts are still disabled.
- * We must clear need_ast and then enable interrupts.
- */
- reasons = need_ast[cpu_number()];
- need_ast[cpu_number()] = AST_ZILCH;
- (void) spl0();
- /*
- * These actions must not block.
- */
- if (reasons & AST_NETWORK)
- net_ast();
- /*
- * Make darn sure that we don't call thread_halt_self
- * or thread_block from the idle thread.
- */
- if (self != current_processor()->idle_thread) {
- #ifndef MIGRATING_THREADS
- while (thread_should_halt(self))
- thread_halt_self(thread_exception_return);
- #endif
- /*
- * One of the previous actions might well have
- * woken a high-priority thread, so we use
- * csw_needed in addition to AST_BLOCK.
- */
- if ((reasons & AST_BLOCK) ||
- csw_needed(self, current_processor())) {
- counter(c_ast_taken_block++);
- thread_block(thread_exception_return);
- }
- }
- }
- void
- ast_check(void)
- {
- int mycpu = cpu_number();
- processor_t myprocessor;
- thread_t thread = current_thread();
- run_queue_t rq;
- spl_t s = splsched();
- /*
- * Check processor state for ast conditions.
- */
- myprocessor = cpu_to_processor(mycpu);
- switch(myprocessor->state) {
- case PROCESSOR_OFF_LINE:
- case PROCESSOR_IDLE:
- case PROCESSOR_DISPATCHING:
- /*
- * No ast.
- */
- break;
- #if NCPUS > 1
- case PROCESSOR_ASSIGN:
- case PROCESSOR_SHUTDOWN:
- /*
- * Need ast to force action thread onto processor.
- *
- * XXX Should check if action thread is already there.
- */
- ast_on(mycpu, AST_BLOCK);
- break;
- #endif /* NCPUS > 1 */
- case PROCESSOR_RUNNING:
- /*
- * Propagate thread ast to processor. If we already
- * need an ast, don't look for more reasons.
- */
- ast_propagate(thread, mycpu);
- if (ast_needed(mycpu))
- break;
- /*
- * Context switch check. The csw_needed macro isn't
- * used here because the rq->low hint may be wrong,
- * and fixing it here avoids an extra ast.
- * First check the easy cases.
- */
- if (thread->state & TH_SUSP || myprocessor->runq.count > 0) {
- ast_on(mycpu, AST_BLOCK);
- break;
- }
- /*
- * Update lazy evaluated runq->low if only timesharing.
- */
- #if MACH_FIXPRI
- if (myprocessor->processor_set->policies & POLICY_FIXEDPRI) {
- if (csw_needed(thread,myprocessor)) {
- ast_on(mycpu, AST_BLOCK);
- break;
- }
- else {
- /*
- * For fixed priority threads, set first_quantum
- * so entire new quantum is used.
- */
- if (thread->policy == POLICY_FIXEDPRI)
- myprocessor->first_quantum = TRUE;
- }
- }
- else {
- #endif /* MACH_FIXPRI */
- rq = &(myprocessor->processor_set->runq);
- if (!(myprocessor->first_quantum) && (rq->count > 0)) {
- queue_t q;
- /*
- * This is not the first quantum, and there may
- * be something in the processor_set runq.
- * Check whether low hint is accurate.
- */
- q = rq->runq + *(volatile int *)&rq->low;
- if (queue_empty(q)) {
- int i;
- /*
- * Need to recheck and possibly update hint.
- */
- simple_lock(&rq->lock);
- q = rq->runq + rq->low;
- if (rq->count > 0) {
- for (i = rq->low; i < NRQS; i++) {
- if(!(queue_empty(q)))
- break;
- q++;
- }
- rq->low = i;
- }
- simple_unlock(&rq->lock);
- }
- if (rq->low <= thread->sched_pri) {
- ast_on(mycpu, AST_BLOCK);
- break;
- }
- }
- #if MACH_FIXPRI
- }
- #endif /* MACH_FIXPRI */
- break;
- default:
- panic("ast_check: Bad processor state (cpu %d processor %p) state: %d",
- mycpu, myprocessor, myprocessor->state);
- }
- (void) splx(s);
- }
|