#include <inc/assert.h>

#include <kern/env.h>
#include <kern/pmap.h>
#include <kern/monitor.h>


// Choose a user environment to run and run it.
void
sched_yield(void)
{
	// Implement simple round-robin scheduling.
	// Search through 'envs' for a runnable environment,
	// in circular fashion starting after the previously running env,
	// and switch to the first such environment found.
	// It's OK to choose the previously running env if no other env
	// is runnable.
	// But never choose envs[0], the idle environment,
	// unless NOTHING else is runnable.

	// LAB 4: Your code here.
	
	uint32_t current;
	uint32_t index;
	
	if (curenv == NULL) {
		current = 0;
	} else {
		current = ENVX(curenv->env_id);
	}

	index = (current + 1) % NENV; //start with the next one	
	while (index != current) {
		
		if (index == 0) {
			index = (index + 1) % NENV;
			continue;
		}
		if (envs[index].env_status == ENV_RUNNABLE) {
			
			break; //we have it in index
		}
		index = (index + 1) % NENV;
		
	} 

	//index points to the next to schedule
	if (index != 0) { // found a runnable process 
		//cprintf("sched: will run env with id %08x \n", envs[index].env_id);
		env_run(&envs[index]);
		return;
	} 
	//the only runnable process is envs[0]"
	cprintf("sched: only env 0 is runnable \n");
	// Run the special idle environment when nothing else is runnable.
	if (envs[0].env_status == ENV_RUNNABLE)
		env_run(&envs[0]);
	else {
		cprintf("Destroyed all environments - nothing more to do!\n");
		while (1)
			monitor(NULL);
	}
}
