Page 1 of 1

Implementing 'yield()' by faking hardware interrupt.

Posted: Thu Jul 18, 2013 8:09 pm
by skeen
First of all; This question is asked out of curiosity.

My kernel currently schedules tasks on the PIT interrupt (IRQ0).
Which issues would there be in causing a software interrupt on IRQ0, in order to implement yield?

Re: Implementing 'yield()' by faking hardware interrupt.

Posted: Thu Jul 18, 2013 8:17 pm
by Nessphoro
Your code will expect that when an IRQ happens it needs to send an end-of-interrupt, which might have some issues.

Re: Implementing 'yield()' by faking hardware interrupt.

Posted: Thu Jul 18, 2013 10:41 pm
by Brendan
Hi,
skeen wrote:First of all; This question is asked out of curiosity.

My kernel currently schedules tasks on the PIT interrupt (IRQ0).
This is bad design. Most task switches are caused when the currently running task blocks for some reason (e.g. terminates, waits for disk IO, waits for network, waits for key press, etc); or are caused a higher priority task starting or unblocking for some reason (e.g. new task spawned, disk IO completes, network packet arrives, a key press occurs, etc). The timer is relatively unimportant, and only really exists so that when there's 2 or more "CPU bound" tasks they can share the CPU's time.

A better design would be to start implement the scheduler by writing a "switch_to_task(taskID)" function. Then write a "find_task_to_switch_to(void)" function that decides which task to switch to and calls the "switch_to_task(taskID)" function. Your timer IRQ handler would just call the "find_task_to_switch_to(void)" function (but it's not the only thing that would call this function).

Next would be a "make_current_task_block(reason)" function (that ends up calling "find_task_to_switch_to(void)"); which would be used whenever a task blocks for any reason. Then you'd have a "make_task_ready_to_run(taskID)" function that checks if the task that has become ready to run is higher priority than the currently running task and calls "switch_to_task(taskID)" if it is.
skeen wrote:Which issues would there be in causing a software interrupt on IRQ0, in order to implement yield?
It depends what other things the timer is being used for. Typically it's also used for keeping track of the current time (so the current time would be messed up), and also used to unblock tasks that have called "sleep()" (so if a task does "sleep(123)" it might only sleep for 10 seconds instead of 123 seconds).

Of course Nessphoro is also correct - the timer IRQ handler will send an EOI; and this can/will cause other IRQs to be lost. For example, a disk controller might send an IRQ to the PIC chip, and you send an unwanted EOI (from the IRQ0 handler) at the wrong time, so the PIC chip thinks you've finished handling the disk controller's IRQ when you haven't. Now the disk controller is waiting for you to handle its IRQ, and the device driver for the disk controller is waiting for the IRQ, but the IRQ got lost so they both just wait for each other forever and all disk IO grinds to a halt until the user realises the OS has locked up and resets/reboots.


Cheers,

Brendan

Re: Implementing 'yield()' by faking hardware interrupt.

Posted: Fri Jul 19, 2013 6:15 am
by sortie
Right, you should not send IRQs, user-space programs must not be allowed to do that because it would interfere with correct driver operation (sending EIOs, etc). Simply allocate an otherwise unused interrupt number and allow user-space to call it.