#include <cputypes.h>
#include <cpus.h>
#include <platforms.h>
#include <kern/ast.h>
#include <kern/counters.h>
#include <kern/cpu_number.h>
#include <kern/misc_protos.h>
#include <kern/queue.h>
#include <kern/sched_prim.h>
#include <kern/thread.h>
#include <kern/thread_act.h>
#include <kern/thread_swap.h>
#include <kern/processor.h>
#include <kern/spl.h>
#include <mach/policy.h>
volatile ast_t need_ast[NCPUS];
void
ast_init(void)
{
#ifndef MACHINE_AST
register int i;
for (i=0; i<NCPUS; i++) {
need_ast[i] = AST_NONE;
}
#endif
}
void
ast_taken(
ast_t reasons,
boolean_t enable
)
{
register int mycpu;
register processor_t myprocessor;
register thread_t self = current_thread();
boolean_t preempt_trap = (reasons == AST_PREEMPT);
disable_preemption();
mycpu = cpu_number();
reasons &= need_ast[mycpu];
need_ast[mycpu] &= ~reasons;
enable_preemption();
if (self->state & TH_IDLE)
goto enable_and_return;
if ((reasons & AST_URGENT) && wait_queue_assert_possible(self)) {
if (reasons & AST_BLOCK) {
counter(c_ast_taken_block++);
thread_block_reason((void (*)(void))0, AST_BLOCK);
}
reasons &= ~AST_PREEMPT;
if (reasons == 0)
goto enable_and_return;
}
if (preempt_trap)
goto enable_and_return;
ml_set_interrupts_enabled(enable);
#ifdef MACH_BSD
if (reasons & AST_BSD) {
extern void bsd_ast(thread_act_t act);
thread_act_t act = self->top_act;
thread_ast_clear(act, AST_BSD);
bsd_ast(act);
}
if (reasons & AST_BSD_INIT) {
extern void bsdinit_task(void);
thread_ast_clear(self->top_act, AST_BSD_INIT);
bsdinit_task();
}
#endif
if (reasons & AST_APC) {
act_execute_returnhandlers();
}
reasons &= AST_BLOCK;
if (reasons == 0) {
disable_preemption();
myprocessor = current_processor();
if (csw_needed(self, myprocessor))
reasons = AST_BLOCK;
enable_preemption();
}
if ( (reasons & AST_BLOCK) &&
wait_queue_assert_possible(self) ) {
counter(c_ast_taken_block++);
thread_block_reason(thread_exception_return, AST_BLOCK);
}
goto just_return;
enable_and_return:
ml_set_interrupts_enabled(enable);
just_return:
return;
}
void
ast_check(void)
{
register int mycpu;
register processor_t myprocessor;
register thread_t self = current_thread();
spl_t s;
s = splsched();
mycpu = cpu_number();
myprocessor = cpu_to_processor(mycpu);
switch (myprocessor->state) {
case PROCESSOR_OFF_LINE:
case PROCESSOR_IDLE:
case PROCESSOR_DISPATCHING:
break;
case PROCESSOR_ASSIGN:
ast_on(AST_BLOCK);
break;
case PROCESSOR_RUNNING:
case PROCESSOR_SHUTDOWN:
ast_propagate(self->top_act->ast);
if (csw_needed(self, myprocessor))
ast_on(AST_BLOCK);
break;
default:
panic("ast_check: Bad processor state");
}
splx(s);
}
#undef ast_on
#undef ast_off
void
ast_on(ast_t reason)
{
boolean_t enable;
enable = ml_set_interrupts_enabled(FALSE);
ast_on_fast(reason);
(void)ml_set_interrupts_enabled(enable);
}
void
ast_off(ast_t reason)
{
ast_off_fast(reason);
}