#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);
}
#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(
processor_t processor)
{
register thread_t self = processor->cpu_data->active_thread;
processor->current_pri = self->sched_pri;
if (processor->state == PROCESSOR_RUNNING) {
register ast_t preempt;
processor_running:
ast_propagate(self->top_act->ast);
if ((preempt = csw_check(self, processor)) != AST_NONE)
ast_on(preempt);
}
else
if ( processor->state == PROCESSOR_DISPATCHING ||
processor->state == PROCESSOR_IDLE ) {
return;
}
else
if (processor->state == PROCESSOR_SHUTDOWN)
goto processor_running;
else
if (processor->state == PROCESSOR_ASSIGN)
ast_on(AST_BLOCK);
}