I have been working on a scheduler and am running into a page fault issue.
I have a yield function, shown below, that is called by the PIT handler every 10ms. It is also called within a spinlock. At the moment, when it is called from the spinlock, a page fault occurs on return from the yield function. In this situation, it loads in a task that was yielded normally through the timer, so the page fault is occuring in my irq common function when it attempts to check the registers pushed onto the stack.
Even if I disable interrupts in the spinlock before yielding, the page fault still occurs leading me to believe that it is not a synchronization issue occuring within the yield function itself.
Here is the yield function:
Code: Select all
static volatile uint8_t yield_lock = 0;
void yield()
{
if (currProc == 0) // Tasking not yet installed
return;
if (__sync_lock_test_and_set(&yield_lock, 1))
return;
// Reschedule current task if running and NOT idle task
if (currProc->state == TASK_RUNNING && currProc != kidle_task)
{
sched_queueRunnable(currProc);
}
//Get next process, or idle if nothing (could very well be the task we just rescheduled ;) )
list_node_t* nextProcNode = list_dequeue(processReadyQueue);
process_t* nextProc = 0;
if (!nextProcNode) // If no ready processes, load idle task
nextProc = kidle_task;
else
nextProc = nextProcNode->data;
//Debug
if (nextProc->state != TASK_RUNNING)
kprintf("Scheduling a non-running task...\n");
// Save state
fpu_switch();
virtmem_switchcontext(nextProc->virtPD); // Don't do function calls after we start stack switch, for safety reasons...
uint32_t esp, ebp, eip; // Stack context stored, EIP never stored, but is used to jump to idle because it doesn't initially have a stack setup. Also, for forking, not an issue because we can just copy the stack!
asm volatile ("mov %%esp, %0" : "=r" (esp));
asm volatile ("mov %%ebp, %0" : "=r" (ebp));
currProc->thread.eip = 0; // Idle should return here normally now because of context switch
currProc->thread.esp = esp;
currProc->thread.ebp = ebp;
//Next Process -- Address space already loaded, fpu handled when fpu instruction executed
esp = nextProc->thread.esp;
ebp = nextProc->thread.ebp;
eip = nextProc->thread.eip;
currProc = nextProc;
asm volatile ("mov %0, %%esp" : : "r" (esp) : "%esp");
asm volatile ("mov %0, %%ebp" : : "r" (ebp));
if (eip)
{
__sync_lock_release(&yield_lock);
IRQ_RES;
asm volatile ("mov %0, %%ebx\n"
"jmp *%%ebx" : : "r"(eip) : "%ebx");
}
__sync_lock_release(&yield_lock);
return;
}