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(); #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); } } }
/* * Called at splsched. */ void ast_taken( ast_t reasons, boolean_t enable ) { register thread_t self = current_thread(); register int mycpu = cpu_number(); boolean_t preempt_trap = (reasons == AST_PREEMPTION); reasons &= need_ast[mycpu]; need_ast[mycpu] &= ~reasons; /* * Handle ASTs for all threads * except idle processor threads. */ if (!(self->state & TH_IDLE)) { /* * Check for urgent preemption. */ if ( (reasons & AST_URGENT) && wait_queue_assert_possible(self) ) { if (reasons & AST_PREEMPT) { counter(c_ast_taken_block++); thread_block_reason(THREAD_CONTINUE_NULL, AST_PREEMPT | AST_URGENT); } reasons &= ~AST_PREEMPTION; } /* * The kernel preempt traps * skip all other ASTs. */ if (!preempt_trap) { ml_set_interrupts_enabled(enable); #ifdef MACH_BSD /* * Handle BSD hook. */ 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 /* * Thread APC hook. */ if (reasons & AST_APC) act_execute_returnhandlers(); ml_set_interrupts_enabled(FALSE); /* * Check for preemption. */ if (reasons & AST_PREEMPT) { processor_t myprocessor = current_processor(); if (csw_needed(self, myprocessor)) reasons = AST_PREEMPT; else reasons = AST_NONE; } if ( (reasons & AST_PREEMPT) && wait_queue_assert_possible(self) ) { counter(c_ast_taken_block++); thread_block_reason(thread_exception_return, AST_PREEMPT); } } } ml_set_interrupts_enabled(enable); }
void ast_check(void) { register int mycpu; register processor_t myprocessor; register thread_t thread = current_thread(); spl_t s = splsched(); mp_disable_preemption(); mycpu = cpu_number(); /* * 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: case PROCESSOR_VIDLE: /* * Propagate thread ast to processor. If we already * need an ast, don't look for more reasons. */ ast_propagate(current_act(), mycpu); if (ast_needed(mycpu)) break; /* * Context switch check. */ if (csw_needed(thread, myprocessor)) { ast_on(mycpu, (myprocessor->first_quantum ? AST_BLOCK : AST_QUANTUM)); } break; default: panic("ast_check: Bad processor state"); } mp_enable_preemption(); splx(s); }
void ast_taken( boolean_t preemption, ast_t mask, spl_t old_spl #if FAST_IDLE ,int thread_type #endif /* FAST_IDLE */ ) { register thread_t self = current_thread(); register processor_t mypr; register ast_t reasons; register int mycpu; thread_act_t act = self->top_act; /* * Interrupts are still disabled. * We must clear need_ast and then enable interrupts. */ extern void log_thread_action(thread_t, char *); #if 0 log_thread_action (current_thread(), "ast_taken"); #endif mp_disable_preemption(); mycpu = cpu_number(); reasons = need_ast[mycpu] & mask; need_ast[mycpu] &= ~reasons; mp_enable_preemption(); splx(old_spl); /* * These actions must not block. */ #if MCMSG if (reasons & AST_MCMSG) mcmsg_ast(); #endif /* MCMSG */ if (reasons & AST_NETWORK) net_ast(); #if MCMSG_ENG if (reasons & AST_RPCREQ) rpc_engine_request_intr(); if (reasons & AST_RPCREPLY) rpc_engine_reply_intr(); if (reasons & AST_RPCDEPART) rpc_engine_depart_intr(); if (reasons & AST_RDMASEND) rdma_engine_send_intr(); if (reasons & AST_RDMARECV) rdma_engine_recv_intr(); if (reasons & AST_RDMATXF) rdma_engine_send_fault_intr(); if (reasons & AST_RDMARXF) rdma_engine_recv_fault_intr(); #endif /* MCMSG_ENG */ #if PARAGON860 && MCMSG_ENG if (reasons & AST_SCAN_INPUT) scan_input_ast(); #endif /* PARAGON860 */ #if DIPC if (reasons & AST_DIPC) dipc_ast(); #endif /* DIPC */ /* * Make darn sure that we don't call thread_halt_self * or thread_block from the idle thread. */ /* XXX - this isn't currently right for the HALT case... */ mp_disable_preemption(); mypr = current_processor(); if (self == mypr->idle_thread) { #if NCPUS == 1 if (reasons & AST_URGENT) { if (!preemption) panic("ast_taken: AST_URGENT for idle_thr w/o preemption"); } #endif mp_enable_preemption(); return; } mp_enable_preemption(); #if FAST_IDLE if (thread_type != NO_IDLE_THREAD) return; #endif /* FAST_IDLE */ #if TASK_SWAPPER /* must be before AST_APC */ if (reasons & AST_SWAPOUT) { spl_t s; swapout_ast(); s = splsched(); mp_disable_preemption(); mycpu = cpu_number(); if (need_ast[mycpu] & AST_APC) { /* generated in swapout_ast() to get suspended */ reasons |= AST_APC; /* process now ... */ need_ast[mycpu] &= ~AST_APC; /* ... and not later */ } mp_enable_preemption(); splx(s); } #endif /* TASK_SWAPPER */ /* migration APC hook */ if (reasons & AST_APC) { act_execute_returnhandlers(); return; /* auto-retry will catch anything new */ } /* * thread_block needs to know if the thread's quantum * expired so the thread can be put on the tail of * run queue. One of the previous actions might well * have woken a high-priority thread, so we also use * csw_needed check. */ { void (*safept)(void) = (void (*)(void))SAFE_EXCEPTION_RETURN; if (reasons &= AST_PREEMPT) { if (preemption) safept = (void (*)(void)) 0; } else { mp_disable_preemption(); mypr = current_processor(); if (csw_needed(self, mypr)) { reasons = (mypr->first_quantum ? AST_BLOCK : AST_QUANTUM); } mp_enable_preemption(); } if (reasons) { counter(c_ast_taken_block++); thread_block_reason(safept, reasons); } } }
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 %08x) state: %d", mycpu, myprocessor, myprocessor->state); } (void) splx(s); }