/* * Called at splsched. */ void ast_check( processor_t processor) { thread_t thread = processor->active_thread; if (processor->state == PROCESSOR_RUNNING || processor->state == PROCESSOR_SHUTDOWN) { ast_t preempt; /* * Propagate thread ast to processor. */ pal_ast_check(thread); ast_propagate(thread->ast); /* * Context switch check. */ thread_lock(thread); processor->current_pri = thread->sched_pri; processor->current_thmode = thread->sched_mode; processor->current_sfi_class = thread->sfi_class = sfi_thread_classify(thread); if ((preempt = csw_check(processor, AST_NONE)) != AST_NONE) ast_on(preempt); thread_unlock(thread); } }
/* * Called at splsched. */ void ast_check( processor_t processor) { register thread_t self = processor->active_thread; processor->current_pri = self->sched_pri; if (processor->state == PROCESSOR_RUNNING) { register ast_t preempt; processor_running: /* * Propagate thread ast to processor. */ ast_propagate(self->top_act->ast); /* * Context switch check. */ 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; }
/* * Handle preemption IPI or IPI in response to setting an AST flag * Triggered by cause_ast_check * Called at splsched */ void ast_check(processor_t processor) { if (processor->state != PROCESSOR_RUNNING && processor->state != PROCESSOR_SHUTDOWN) return; thread_t thread = processor->active_thread; assert(thread == current_thread()); thread_lock(thread); /* * Propagate thread ast to processor. * (handles IPI in response to setting AST flag) */ ast_propagate(thread); boolean_t needs_callout = false; processor->current_pri = thread->sched_pri; processor->current_sfi_class = thread->sfi_class = sfi_thread_classify(thread); processor->current_recommended_pset_type = recommended_pset_type(thread); perfcontrol_class_t thread_class = thread_get_perfcontrol_class(thread); if (thread_class != processor->current_perfctl_class) { /* We updated the perfctl class of this thread from another core. * Since we dont do CLPC callouts from another core, do a callout * here to let CLPC know that the currently running thread has a new * class. */ needs_callout = true; } processor->current_perfctl_class = thread_class; ast_t preempt; if ((preempt = csw_check(processor, AST_NONE)) != AST_NONE) ast_on(preempt); thread_unlock(thread); if (needs_callout) { machine_switch_perfcontrol_state_update(PERFCONTROL_ATTR_UPDATE, mach_approximate_time(), 0, thread); } }
/* * The scheduler is too messy for my old little brain */ void simpler_thread_setrun( thread_t th, boolean_t may_preempt) { register struct run_queue *rq; register int whichq; /* * XXX should replace queue with a boolean in this case. */ if (default_pset.idle_count > 0) { processor_t processor; processor = (processor_t) queue_first(&default_pset.idle_queue); queue_remove(&default_pset.idle_queue, processor, processor_t, processor_queue); default_pset.idle_count--; processor->next_thread = th; processor->state = PROCESSOR_DISPATCHING; return; } rq = &(master_processor->runq); ast_on(cpu_number(), AST_BLOCK); whichq = (th)->sched_pri; simple_lock(&(rq)->lock); /* lock the run queue */ enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th)); if (whichq < (rq)->low || (rq)->count == 0) (rq)->low = whichq; /* minimize */ (rq)->count++; #ifdef MIGRATING_THREADS (th)->shuttle.runq = (rq); #else (th)->runq = (rq); #endif simple_unlock(&(rq)->lock); /* * Turn off first_quantum to allow context switch. */ current_processor()->first_quantum = FALSE; }
void thread_poll_yield( thread_t self) { spl_t s; assert(self == current_thread()); s = splsched(); if (self->sched_mode == TH_MODE_FIXED) { uint64_t total_computation, abstime; abstime = mach_absolute_time(); total_computation = abstime - self->computation_epoch; total_computation += self->computation_metered; if (total_computation >= max_poll_computation) { processor_t myprocessor = current_processor(); ast_t preempt; thread_lock(self); if (!(self->sched_flags & TH_SFLAG_DEPRESSED_MASK)) { self->sched_pri = DEPRESSPRI; myprocessor->current_pri = self->sched_pri; } self->computation_epoch = abstime; self->computation_metered = 0; self->sched_flags |= TH_SFLAG_POLLDEPRESS; abstime += (total_computation >> sched_poll_yield_shift); if (!timer_call_enter(&self->depress_timer, abstime, TIMER_CALL_USER_CRITICAL)) self->depress_timer_active++; if ((preempt = csw_check(myprocessor, AST_NONE)) != AST_NONE) ast_on(preempt); thread_unlock(self); }
void ast_dtrace_on(void) { ast_on(AST_DTRACE); }
/* * Propagate ASTs set on a thread to the current processor * Called at splsched */ void ast_propagate(thread_t thread) { ast_on(thread->ast); }
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_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); }