2018-10-06 06:52:47 -07:00
|
|
|
#include <inc/assert.h>
|
|
|
|
#include <inc/x86.h>
|
|
|
|
#include <kern/spinlock.h>
|
|
|
|
#include <kern/env.h>
|
|
|
|
#include <kern/pmap.h>
|
|
|
|
#include <kern/monitor.h>
|
|
|
|
|
|
|
|
void sched_halt(void);
|
|
|
|
|
|
|
|
// Choose a user environment to run and run it.
|
|
|
|
void
|
|
|
|
sched_yield(void)
|
|
|
|
{
|
|
|
|
struct Env *idle;
|
|
|
|
|
|
|
|
// Implement simple round-robin scheduling.
|
|
|
|
//
|
|
|
|
// Search through 'envs' for an ENV_RUNNABLE environment in
|
|
|
|
// circular fashion starting just after the env this CPU was
|
|
|
|
// last running. Switch to the first such environment found.
|
|
|
|
//
|
|
|
|
// If no envs are runnable, but the environment previously
|
|
|
|
// running on this CPU is still ENV_RUNNING, it's okay to
|
2018-10-24 17:44:45 -07:00
|
|
|
// choose that environment. Make sure curenv is not null before
|
|
|
|
// dereferencing it.
|
2018-10-06 06:52:47 -07:00
|
|
|
//
|
|
|
|
// Never choose an environment that's currently running on
|
|
|
|
// another CPU (env_status == ENV_RUNNING). If there are
|
|
|
|
// no runnable environments, simply drop through to the code
|
|
|
|
// below to halt the cpu.
|
|
|
|
|
|
|
|
// LAB 4: Your code here.
|
2019-05-05 19:42:15 -07:00
|
|
|
struct Env* next_env = curenv ? curenv + 1 : envs;
|
|
|
|
struct Env* end_env = envs + NENV;
|
|
|
|
struct Env* to_run = NULL;
|
|
|
|
|
|
|
|
for(int i = 0; i < NENV; i++, next_env++) {
|
|
|
|
if(next_env == end_env) next_env = envs;
|
|
|
|
if(next_env->env_status == ENV_RUNNABLE) {
|
|
|
|
to_run = next_env;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!to_run && curenv && curenv->env_status == ENV_RUNNING) {
|
|
|
|
to_run = curenv;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(to_run) env_run(to_run);
|
2018-10-06 06:52:47 -07:00
|
|
|
|
|
|
|
// sched_halt never returns
|
|
|
|
sched_halt();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Halt this CPU when there is nothing to do. Wait until the
|
|
|
|
// timer interrupt wakes it up. This function never returns.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
sched_halt(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// For debugging and testing purposes, if there are no runnable
|
|
|
|
// environments in the system, then drop into the kernel monitor.
|
|
|
|
for (i = 0; i < NENV; i++) {
|
|
|
|
if ((envs[i].env_status == ENV_RUNNABLE ||
|
|
|
|
envs[i].env_status == ENV_RUNNING ||
|
|
|
|
envs[i].env_status == ENV_DYING))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == NENV) {
|
|
|
|
cprintf("No runnable environments in the system!\n");
|
|
|
|
while (1)
|
|
|
|
monitor(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark that no environment is running on this CPU
|
|
|
|
curenv = NULL;
|
|
|
|
lcr3(PADDR(kern_pgdir));
|
|
|
|
|
|
|
|
// Mark that this CPU is in the HALT state, so that when
|
|
|
|
// timer interupts come in, we know we should re-acquire the
|
|
|
|
// big kernel lock
|
|
|
|
xchg(&thiscpu->cpu_status, CPU_HALTED);
|
|
|
|
|
|
|
|
// Release the big kernel lock as if we were "leaving" the kernel
|
|
|
|
unlock_kernel();
|
|
|
|
|
|
|
|
// Reset stack pointer, enable interrupts and then halt.
|
|
|
|
asm volatile (
|
|
|
|
"movl $0, %%ebp\n"
|
|
|
|
"movl %0, %%esp\n"
|
|
|
|
"pushl $0\n"
|
|
|
|
"pushl $0\n"
|
2019-04-01 21:36:31 -07:00
|
|
|
// LAB 4:
|
2018-10-06 06:52:47 -07:00
|
|
|
// Uncomment the following line after completing exercise 13
|
2019-05-05 22:08:12 -07:00
|
|
|
"sti\n"
|
2018-10-06 06:52:47 -07:00
|
|
|
"1:\n"
|
|
|
|
"hlt\n"
|
|
|
|
"jmp 1b\n"
|
|
|
|
: : "a" (thiscpu->cpu_ts.ts_esp0));
|
|
|
|
}
|
|
|
|
|