Help with very persistent scheduler bug
Posted: Fri Apr 28, 2017 1:38 pm
Hello
I have issues with my scheduler. It switches the first few times until it gets back to the start, then the registers get trashed and stop working. I've tried a multitude of different ways to capture the registers and save them, but nothing I try seems to be working, so I need a little help with getting this final issue resolved. I will give a quick run-down of the code,
My scheduler is linked to my PIT, and each timer tick runs the following code:
This is call from within the "isr_handler" function, based on Brendan's code:
So the registers get pulled through and passed to my isr_handler function. This then calls the corresponding handler (which, for my PIT handler, alters the registers), and then finally returns the registers which then restores the state of the system.
The Scheduler then runs this function:
which handles a LOT of the inner details in one place; this is where I have been trying lots of different options. Each task is an element of a std::vector<Thread*>, and has the following schema:
as you can see, it's very minimal (I've cut it right down to debug the class). "entry_ptr" is the memory address of the function that is ran upon thread execution.
Finally, to start a thread I run this function:
I have been banging my head against the wall trying to figure this out, it *almost* works, but only runs through ONCE!
I have issues with my scheduler. It switches the first few times until it gets back to the start, then the registers get trashed and stop working. I've tried a multitude of different ways to capture the registers and save them, but nothing I try seems to be working, so I need a little help with getting this final issue resolved. I will give a quick run-down of the code,
My scheduler is linked to my PIT, and each timer tick runs the following code:
Code: Select all
static void timer_irq0(struct registers * r) {
timer_tenths++;
if(timer_tenths > 100) {
Scheduler::next(r);
timer_tenths = 0;
}
}
Code: Select all
extern "C" struct registers * isr_handler(registers_t* registers) {
if ((registers->isr_num >= IRQ0) && (registers->isr_num <= IRQ15)) { // IRQ
if (registers->isr_num >= IRQ8) { // IRQ originated from the slave PIC
outportb(PIC2_COMMAND, PIC_EOI);
}
outportb(PIC1_COMMAND, PIC_EOI);
}
if (isr_handlers[registers->isr_num] != 0) {
isr_handlers[registers->isr_num](registers);
}
return registers;
}
The Scheduler then runs this function:
Code: Select all
void Scheduler::next(registers* r) {
if(!has_initialised) {
memcpy(&base_state, r, sizeof(registers));
has_initialised = true;
return;
}
if(!thread_list[task_idx]->ran) {
// if this is the first time the thread has been scheduled,
// we need to initialize it's state register beforehand
thread_list[task_idx]->state_reg.eflags = base_state.eflags;
thread_list[task_idx]->state_reg.cs = base_state.cs;
thread_list[task_idx]->state_reg.ss = base_state.ss;
thread_list[task_idx]->ran = true;
}
int lastThread = task_idx - 1;
if(task_idx == 0)
lastThread = thread_list.size()-1;
// save the previous threads state
if(thread_list[lastThread]->ran) {
memcpy(&(thread_list[lastThread]->state_reg), r, sizeof(registers));
}
// set the registers from the current thread's saved state
memcpy(r, &(thread_list[task_idx]->state_reg), sizeof(registers));
task_idx++;
// Loop around 0 -> 1 -> 2 -> 0 -> ...
if(task_idx >= thread_list.size()) {
task_idx = 0;
}
}
Code: Select all
class Thread {
public:
size_t thread_id;
registers state_reg;
uintptr_t entry_ptr;
bool ran;
Thread() : ran(false) {}
};
Finally, to start a thread I run this function:
Code: Select all
void start_thread(void_fn entry) {
Thread* thread = new Thread();
thread->thread_id = next_tid;
thread->entry_ptr = reinterpret_cast<uintptr_t>(entry);
thread->state_reg.eax = 0;
thread->state_reg.ebx = 0;
thread->state_reg.ecx = 0;
thread->state_reg.edx = 0;
thread->state_reg.esi = 0;
thread->state_reg.edi = 0;
thread_list.push_back(thread);
next_tid++;
}