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:
Code:
static void timer_irq0(struct registers * r) {
timer_tenths++;
if(timer_tenths > 100) {
Scheduler::next(r);
timer_tenths = 0;
}
}
This is call from within the "isr_handler" function, based on Brendan's code:
Code:
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;
}
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:
Code:
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;
}
}
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:
Code:
class Thread {
public:
size_t thread_id;
registers state_reg;
uintptr_t entry_ptr;
bool ran;
Thread() : ran(false) {}
};
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:
Code:
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++;
}
I have been banging my head against the wall trying to figure this out, it *almost* works, but only runs through ONCE!