8infy wrote:
I've been trying to make this work for like 5 hours today, my brain is too weak to comprehend why it constantly breaks, e.g if 1 process sleeps it works ok, if 2 sleep everything breaks, interrupts get randomly disabled even though iret should clearly always reenable them, scheduler queue ends up empty randomly, the same threads end up being in the sleeping queue twice, restarting qemu sometimes randomly makes everything work (as if there was a race condition even though interrupts are disabled all the way until I enqueue all 3 threads), even with extensive logging i still can't figure it out. I'm starting to think my approach is completely wrong.
The exact type of list structure is not going to be a panacea; this sounds like you have more basic problems, like your interrupt handling or something. I have frequently found it helpful in such cases to (1) take a break and come back later (your head already hurts from banging it against a wall all day, so you are not going to bring your A-game anymore), and (2) step back and analyze if the sequence of log messages is anticipated. And if not, where things start to go wrong.
8infy wrote:
Should I just switch to a doubly linked circular list? So to block the current thread I would pop it off the ready list and put it in a circular sleeping list, and then pop it off there when its done and insert back into the ready list right? Do you think it's a better approach?
Sounds half good. I don't see a reason to have a list of sleeping processes (if you want a list of all processes, maintain one separately). If you want to block a process, you are usually waiting for an event, optionally with timeout, and optionally interruptible. You already need a way to find a process by PID alone, no matter its state, so you already need a list of all processes, somehow. (If you are writing something approaching POSIX compatible, at least.) For scheduler purposes, have a circular doubly linked list of ready processes that is never empty (you can always idle). To block a process, remove it from the ready list. To unblock it, add it to the list again. Simple as. Scheduling advances the head pointer to the next node, and if you remember to add new nodes always behind the head pointer, no process can starve no matter how many processes get ready (More exactly: Once queued, a process is N nodes in front of the head pointer, and no event will ever increase the number of nodes between the head and the newly ready node, and a lot of events decrease that number). Since the list is circular, you will never reach the end, and since it's never empty, you can always do something when scheduling, even if it is just wasting time.