Newer
Older
ubixos-old / src / sys / kernel / sched.c
#include <ubixos/kpanic.h>
#include <ubixos/spinlock.h>
#include <ubixos/sched.h>
#include <ubixos/vitals.h>
#include <vfs/mount.h>
#include <lib/kmalloc.h>
#include <lib/kprintf.h>
#include <vmm/vmm.h>
#include <sys/gdt.h>
#include <sys/idt.h>
#include <isa/8259.h>
#include <string.h>
#include <assert.h>
#include <ubixos/spinlock.h>


static kTask_t *taskList = NULL;
static uInt32  nextID    = -1;

kTask_t *_current = NULL;
kTask_t *_usedMath = NULL;

static spinLock_t schedulerSpinLock = SPIN_LOCK_INITIALIZER;
static spinLock_t nextIDSpinLock = SPIN_LOCK_INITIALIZER;

void LoadTaskState(uInt16 selector)
{
   //asm ("ltr %0": : "m" (selector));
   return;
}

uInt16 StoreTaskState()
{
   uInt16 selector = 0x0;
   //asm volatile("str %0": : "r" (selector));
   return selector;
}

void Switch(uInt16 selector)
{
   asm ("lcall %0": : "m" (selector));
}

uInt16 kernel = 1;

void SendTaskToProcessor(kTask_t *task, kProcessor *cpu)
{
        uInt32 memAddr   = 0x0;
        _current = task;

        memAddr = (uInt32)&(task->tss);
        ubixGDT[4].descriptor.baseLow  = (memAddr & 0xFFFF);
        ubixGDT[4].descriptor.baseMed  = ((memAddr >> 16) & 0xFF);
        ubixGDT[4].descriptor.baseHigh = (memAddr >> 24);
        ubixGDT[4].descriptor.access   = '\x89';

        /* enable interrupts, particularly the timer interrupt */
        //irqEnable(0x0);

	//kernel = StoreTaskState();
	//LoadTaskState(kernel);
	//Switch(kernel);
        asm("ljmp $0x20,$0\n");
        kprintf("WOOT!!\n");
        while (1);

        /* no interrupts can occur at the dispatch level */
        irqDisable(0x0);
        return;
}

/************************************************************************

Function: int sched_init()

Description: This function is used to enable the kernel scheduler

Notes:

02/20/2004 - Approved for quality

08/07/2005 - begun rewrite as non-reentrant (Stephen A. Hodges)

************************************************************************/


int sched_init()
{
	taskList = (kTask_t *)kmalloc(sizeof(kTask_t));
	if(taskList == 0x0)
		kpanic("Unable to create task list");
   
	taskList->id = nextID++;
	//_current = NULL;
	taskList->first = NULL;
	taskList->last = NULL;
	taskList->next = NULL;
	taskList->prev = NULL;
	/* Print out information on scheduler */
	kprintf("sched0 - Address: [0x%X]\n", taskList);
        
	/* Return so we know everything went well */
	return(0x0); 
}


void sched()
{
  kTask_t *tmpTask = NULL;
  kTask_t *delTask = NULL;
  kProcessor *cpu = NULL;

  /* no interrupts can occur at the dispatch level */
  irqDisable(0x0);

  /* block reentrant schedule calls (there should be none anyways) */
  spinLock(&schedulerSpinLock);

  while(1)
  {

	/* traverse the task queue */
	for (tmpTask = taskList->first ;tmpTask != NULL ; tmpTask = tmpTask->next)
	{
		switch(tmpTask->state)
		{
		case READY:
			tmpTask->state = RUNNING;
                        kprintf("sending task to CPU\n");
			SendTaskToProcessor(tmpTask, cpu);
			tmpTask->state = WAIT;
			break;
		case WAIT:
			/* TODO: Sort priority list */
			tmpTask->state = READY;
			break;
		case FORK:
			tmpTask->state = NEW;
			break;
		case NEW:
			/* TODO: Add to wait list   */
			tmpTask->state = WAIT;
			break;
		case RUNNING:
			break;
		case IDLE:
			SendTaskToProcessor(tmpTask, cpu);
			break;
                case DEAD:
                        delTask = tmpTask;

                        if (delTask->prev != 0x0)
                                delTask->prev->next = delTask->next;
                        if (tmpTask->next != 0x0)
                                delTask->next->prev = delTask->prev;
                        if (taskList == delTask)
                                taskList = delTask->next;
                        vmmFreeProcessPages(delTask->id);
                        if (delTask->imageFd != 0x0)
                                fclose(delTask->imageFd);
                        kfree(delTask);
                        break;
		default:
			kpanic("Unknown task state [%d] for task [%d]!\n", tmpTask->state, tmpTask->id);
			break;
		}
	}

	/* finished all tasks */
    }	
	       
    return;
}

kTask_t *schedNewTask()
{
  kTask_t *tmpTask  = (kTask_t *)kmalloc(sizeof(kTask_t));

  if (tmpTask == NULL)
  {
	kprintf("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n");
	return NULL;
  }

 if(taskList->first == NULL)
 {
	taskList->first = tmpTask;
	taskList->last = tmpTask;
  }

  memset(tmpTask,0x0,sizeof(kTask_t)); 
  /* Filling in tasks attrs */
  tmpTask->usedMath   = 0x0;
  tmpTask->state      = NEW;

  tmpTask->id         = nextID++;
  taskList->last->next = tmpTask;
  tmpTask->next  = NULL;
  tmpTask->prev  = taskList->last;
  taskList->last = tmpTask;
  
  return(tmpTask);
  }


kTask_t * 
schedFindTask(uInt32 id) 
{
        kTask_t *tmpTask = 0x0; 

  spinLock(&schedulerSpinLock);
        for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) {
                if (tmpTask->id == id)
                        return(tmpTask);
        }
  spinUnlock(&schedulerSpinLock);

        return(0x0);
}


/************************************************************************

 Function: void schedEndTask()

 Description: This function will end a task

 Notes:

  02/20/2004 - Approved for quality

************************************************************************/

void 
sched_yield()
{
	kpanic("sched_yield() is obsolete!\n");
}


/************************************************************************

Function: int sched_setStatus(pidType pid,tState state)

Description: Change the tasks status

Notes:

************************************************************************/
int sched_setStatus(pidType pid,tState state)
{
  kTask_t *tmpTask = schedFindTask(pid);
  if (tmpTask == 0x0)
    return(0x1);
  tmpTask->state = state;
  return(0x0);
  }

int sched_setStatus2(kTask_t *task, tState state)
{

	if(task == 0x0)
		return 0x1;
	task->state = state;
	return 0x0;
}

/***
 END
 ***/