#include <kern/thread.h>
#include <kern/processor.h>
#include <machine/machparam.h>
-#include <kern/sf.h>
-#include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
-/*** ??? Should this file be MK SP-specific? Or is it more general purpose? ***/
-
-
-
-/*
- * USAGE_THRESHOLD is the amount by which usage must change to
- * cause a priority shift that moves a thread between run queues.
- */
-
-#ifdef PRI_SHIFT_2
-#if PRI_SHIFT_2 > 0
-#define USAGE_THRESHOLD (((1 << PRI_SHIFT) + (1 << PRI_SHIFT_2)) << (2 + SCHED_SHIFT))
-#else /* PRI_SHIFT_2 > 0 */
-#define USAGE_THRESHOLD (((1 << PRI_SHIFT) - (1 << -(PRI_SHIFT_2))) << (2 + SCHED_SHIFT))
-#endif /* PRI_SHIFT_2 > 0 */
-#else /* PRI_SHIFT_2 */
-#define USAGE_THRESHOLD (1 << (PRI_SHIFT + 2 + SCHED_SHIFT))
-#endif /* PRI_SHIFT_2 */
/*
- * thread_quantum_update:
+ * thread_quantum_expire:
*
* Recalculate the quantum and priority for a thread.
- * The number of ticks that has elapsed since we were last called
- * is passed as "nticks."
*/
void
-thread_quantum_update(
- register int mycpu,
- register thread_t thread,
- int nticks,
- int state)
+thread_quantum_expire(
+ timer_call_param_t p0,
+ timer_call_param_t p1)
{
- register int quantum;
- register processor_t myprocessor;
+ register processor_t myprocessor = p0;
+ register thread_t thread = p1;
register processor_set_t pset;
spl_t s;
- myprocessor = cpu_to_processor(mycpu);
pset = myprocessor->processor_set;
/*
- * Account for thread's utilization of these ticks.
- * This assumes that there is *always* a current thread.
- * When the processor is idle, it should be the idle thread.
+ * Update set_quanta for timesharing.
*/
+ pset->set_quanta = pset->machine_quanta[
+ (pset->runq.count > pset->processor_count) ?
+ pset->processor_count : pset->runq.count];
+
+ s = splsched();
+ thread_lock(thread);
/*
- * Update set_quantum and calculate the current quantum.
+ * Check for failsafe trip.
*/
- pset->set_quantum = pset->machine_quantum[
- (pset->runq.count > pset->processor_count) ?
- pset->processor_count : pset->runq.count];
+ if (!(thread->sched_mode & TH_MODE_TIMESHARE)) {
+ extern uint64_t max_unsafe_computation;
+ uint64_t new_computation;
+
+ new_computation = myprocessor->quantum_end;
+ new_computation -= thread->computation_epoch;
+ if (new_computation + thread->metered_computation >
+ max_unsafe_computation) {
+ extern uint32_t sched_safe_duration;
+
+ if (thread->sched_mode & TH_MODE_REALTIME) {
+ if (thread->depress_priority < 0)
+ thread->priority = MINPRI;
+ else
+ thread->depress_priority = MINPRI;
+
+ thread->safe_mode |= TH_MODE_REALTIME;
+ thread->sched_mode &= ~TH_MODE_REALTIME;
+ }
- if (myprocessor->runq.count != 0)
- quantum = min_quantum;
- else
- quantum = pset->set_quantum;
+ thread->safe_release = sched_tick + sched_safe_duration;
+ thread->sched_mode |= (TH_MODE_FAILSAFE|TH_MODE_TIMESHARE);
+ }
+ }
/*
* Now recompute the priority of the thread if appropriate.
*/
+ if (thread->sched_stamp != sched_tick)
+ update_priority(thread);
+ else
+ if ( (thread->sched_mode & TH_MODE_TIMESHARE) &&
+ thread->depress_priority < 0 ) {
+ thread_timer_delta(thread);
+ thread->sched_usage += thread->sched_delta;
+ thread->sched_delta = 0;
+ compute_my_priority(thread);
+ }
- {
- s = splsched();
- thread_lock(thread);
-
- if (!(thread->policy & (POLICY_TIMESHARE|POLICY_RR|POLICY_FIFO))) {
- thread_unlock(thread);
- splx(s);
- return;
- }
-
- if (thread->state&TH_IDLE) {
- /* Don't try to time-slice idle threads */
- myprocessor->first_quantum = TRUE;
- if (thread->sched_stamp != sched_tick)
- update_priority(thread);
- thread_unlock(thread);
- splx(s);
- ast_check();
- return;
- }
-
- myprocessor->quantum -= nticks;
- /*
- * Runtime quantum adjustment. Use quantum_adj_index
- * to avoid synchronizing quantum expirations.
- */
- if ( quantum != myprocessor->last_quantum &&
- pset->processor_count > 1 ) {
- myprocessor->last_quantum = quantum;
- simple_lock(&pset->quantum_adj_lock);
- quantum = min_quantum + (pset->quantum_adj_index *
- (quantum - min_quantum)) /
- (pset->processor_count - 1);
- if (++(pset->quantum_adj_index) >= pset->processor_count)
- pset->quantum_adj_index = 0;
- simple_unlock(&pset->quantum_adj_lock);
- }
- if (myprocessor->quantum <= 0) {
- if (thread->sched_stamp != sched_tick)
- update_priority(thread);
- else
- if ( thread->policy == POLICY_TIMESHARE &&
- thread->depress_priority < 0 ) {
- thread_timer_delta(thread);
- thread->sched_usage += thread->sched_delta;
- thread->sched_delta = 0;
- compute_my_priority(thread);
- }
+ /*
+ * This quantum is up, give this thread another.
+ */
+ if (first_quantum(myprocessor))
+ myprocessor->slice_quanta--;
- /*
- * This quantum is up, give this thread another.
- */
- myprocessor->first_quantum = FALSE;
- if (thread->policy == POLICY_TIMESHARE)
- myprocessor->quantum += quantum;
- else
- myprocessor->quantum += min_quantum;
- }
- /*
- * Recompute priority if appropriate.
- */
- else {
- if (thread->sched_stamp != sched_tick)
- update_priority(thread);
- else
- if ( thread->policy == POLICY_TIMESHARE &&
- thread->depress_priority < 0 ) {
- thread_timer_delta(thread);
- if (thread->sched_delta >= USAGE_THRESHOLD) {
- thread->sched_usage += thread->sched_delta;
- thread->sched_delta = 0;
- compute_my_priority(thread);
- }
- }
- }
+ thread->current_quantum = (thread->sched_mode & TH_MODE_REALTIME)?
+ thread->realtime.computation: std_quantum;
+ myprocessor->quantum_end += thread->current_quantum;
+ timer_call_enter1(&myprocessor->quantum_timer,
+ thread, myprocessor->quantum_end);
- thread_unlock(thread);
- splx(s);
+ thread_unlock(thread);
+ splx(s);
- /*
- * Check for and schedule ast if needed.
- */
- ast_check();
- }
+ /*
+ * Check for and schedule ast if needed.
+ */
+ ast_check();
}