#include #include #include #include #include extern kern_status_t setup_kernel_task(void); extern kern_status_t setup_idle_task(void); extern kern_status_t task_object_type_init(void); extern kern_status_t thread_object_type_init(void); static cycles_t __default_quantum = 0; kern_status_t sched_init(void) { kern_status_t status = KERN_OK; status = task_object_type_init(); if (status != KERN_OK) { return status; } status = thread_object_type_init(); if (status != KERN_OK) { return status; } status = setup_kernel_task(); if (status != KERN_OK) { return status; } status = setup_idle_task(); if (status != KERN_OK) { return status; } struct thread *this_thread = QUEUE_CONTAINER(struct thread, tr_threads, queue_first(&kernel_task()->t_threads)); struct thread *idle_thread = QUEUE_CONTAINER(struct thread, tr_threads, queue_first(&idle_task()->t_threads)); struct cpu_data *this_cpu = get_this_cpu(); rq_init(&this_cpu->c_rq); this_cpu->c_rq.rq_cur = this_thread; this_cpu->c_rq.rq_idle = idle_thread; put_cpu(this_cpu); start_charge_period(); return status; } void context_switch(struct thread *old, struct thread *new) { if (old->tr_parent->t_pmap != new->tr_parent->t_pmap) { pmap_switch(new->tr_parent->t_pmap); } switch_to(old, new); } void __schedule(void) { ml_int_disable(); struct cpu_data *this_cpu = get_this_cpu(); struct runqueue *rq = &this_cpu->c_rq; unsigned long flags; rq_lock(rq, &flags); struct thread *prev = rq->rq_cur; prev->tr_quantum_cycles = 0; prev->tr_flags &= ~THREAD_F_NEED_RESCHED; enum thread_state prev_state = READ_ONCE(prev->tr_state); if (prev_state == THREAD_READY && prev != rq->rq_idle) { rq_enqueue(rq, prev); } struct thread *next = rq_dequeue(rq); if (!next) { next = rq->rq_idle; } rq->rq_cur = next; rq_unlock(rq, flags); if (prev != next) { context_switch(prev, next); } else { ml_int_enable(); } } void schedule(void) { do { __schedule(); } while (need_resched()); } void start_charge_period(void) { struct thread *self = current_thread(); if (!self) { return; } self->tr_charge_period_start = get_cycles(); } void end_charge_period(void) { preempt_disable(); struct thread *self = current_thread(); if (!self) { return; } cycles_t end = get_cycles(); preempt_enable(); cycles_t charge = cycles_diff(self->tr_charge_period_start, end); self->tr_quantum_cycles += charge; self->tr_total_cycles += charge; if (self->tr_quantum_cycles >= self->tr_quantum_target) { self->tr_flags |= THREAD_F_NEED_RESCHED; } self->tr_charge_period_start = 0; //printk("%llu cycles charged to %s/%u", charge, self->tr_parent->t_name, self->tr_parent->t_id); } cycles_t default_quantum(void) { return __default_quantum; }