Hello! I decided to ask for help here, for i honestly am not sure what to do.
I have been trying to implement cooperative multitasking in my OS, and am having a weird problem involving interrupts.
For some reason, while two tasks are active (taskA and taskB, constantly yielding between eachother), only the PIT interrupts get handled, i therefore see a blinking cursor. However, keyboard and mouse interrupts do not get handled, and i get nothing when i press keys and move my mouse.
The handlers get installed all the same.
The code can be viewed here https://github.com/theoriginalgrasshopp ... ltitasking
QEMU keyboard trace shows that events ARE fired while the two tasks are yielding.
Weird bug involving interrupts and multitasking
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Weird bug involving interrupts and multitasking
Please ignore my dumb and now deleted comment. Anyway, you are only getting timer interrupts IRQ0 at the point of your test. I can only really see this happening if you are attempting to run your `yield` code while you are still processing an existing keyboard interrupt (IRQ1). Until you send an EOI to acknowledge the keyboard interrupt you won't get any further keyboard interrupts (or anything >= IRQ1). You will get IRQ0 since it is higher priority.
Looking through your code it seems your `keyboard_handler` processes keystroke directly . You receive characters in the interrupt handler and put them into an input buffer. When you find ENTER has been pressed you call `command_init` (your shell) and then call `yield` if the command entered was `multitasking-test` . When `yield`is called you are still in the keyboard interrupt handler for IRQ1 (and no EOI has been sent) so you will only get higher priority IRQ0 interrupts.
You shouldn't be running your shell at interrupt context. You should be putting scan codes into a buffer and exiting the interrupt. You'd then have to process the keyboard buffer when not in an interrupt to see if there are scancodes and if there are do whatever is appropriate like calling `command_init` when the proper command is found. You could query the scan code buffer as part of your `main_task` or create a new task to act as your shell.
As an experiment (this isn't a solution) do a `PIC_eoi (1);` just before you call `yield` in shell.c to signal the EOI for the keyboard. If you receive interrupts like keyboard and mouse with this change then what I suggest above is your problem.
Looking through your code it seems your `keyboard_handler` processes keystroke directly . You receive characters in the interrupt handler and put them into an input buffer. When you find ENTER has been pressed you call `command_init` (your shell) and then call `yield` if the command entered was `multitasking-test` . When `yield`is called you are still in the keyboard interrupt handler for IRQ1 (and no EOI has been sent) so you will only get higher priority IRQ0 interrupts.
You shouldn't be running your shell at interrupt context. You should be putting scan codes into a buffer and exiting the interrupt. You'd then have to process the keyboard buffer when not in an interrupt to see if there are scancodes and if there are do whatever is appropriate like calling `command_init` when the proper command is found. You could query the scan code buffer as part of your `main_task` or create a new task to act as your shell.
As an experiment (this isn't a solution) do a `PIC_eoi (1);` just before you call `yield` in shell.c to signal the EOI for the keyboard. If you receive interrupts like keyboard and mouse with this change then what I suggest above is your problem.
Re: Weird bug involving interrupts and multitasking
Hello! Thank you very much for your response! Sorry for the weirdly named functions. The problem is indeed what you described!
Calling an EOI before yield() does actually make keyboard interrupts work !
Could you please elaborate, though, on how i could put the shell into a task? (like... taskB)
Right now, what is happening, is that the keyboard driver stores keystrokes into a buffer and then on enter it processes the buffer and does something. How could that be changed?
Calling an EOI before yield() does actually make keyboard interrupts work !
Could you please elaborate, though, on how i could put the shell into a task? (like... taskB)
Right now, what is happening, is that the keyboard driver stores keystrokes into a buffer and then on enter it processes the buffer and does something. How could that be changed?
Re: Weird bug involving interrupts and multitasking
think about this:
what if some program other than the shell wants keyboard input? how would that happen?
right now, you are tying your shell directly into the keyboard driver, which prevents any other program from receiving input
what is generally done, is your keyboard interrupt handler puts the input into a circular buffer, and then when a program (like your shell) wants input, it calls an OS function or syscall to get input, which removes a single character from the buffer, and gives it to the program
the program can then do whatever it wants with that input, including putting it into its own buffer, checking for and processing enter, or even directly responding to the keystroke itself without any buffer or enter required (such as providing help if the user presses F1, inserting something typed earlier if the user pressed a "repeat" or "paste" keystroke, or exiting when the user presses esc)
note: you will need either (ultimately, you probably want to provide both options):
what if some program other than the shell wants keyboard input? how would that happen?
right now, you are tying your shell directly into the keyboard driver, which prevents any other program from receiving input
what is generally done, is your keyboard interrupt handler puts the input into a circular buffer, and then when a program (like your shell) wants input, it calls an OS function or syscall to get input, which removes a single character from the buffer, and gives it to the program
the program can then do whatever it wants with that input, including putting it into its own buffer, checking for and processing enter, or even directly responding to the keystroke itself without any buffer or enter required (such as providing help if the user presses F1, inserting something typed earlier if the user pressed a "repeat" or "paste" keystroke, or exiting when the user presses esc)
note: you will need either (ultimately, you probably want to provide both options):
- a way for the function to return "keyboard buffer is empty, there is no key to return"
- a way for the function to not return to the program until there is something in the buffer to return
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Weird bug involving interrupts and multitasking
Thanks to Jaaman for his response. I was busy much of the day. I have made a pull request to your Github repo that splits the interrupt handling from the key processing using a lockless ring (circular) buffer.
There are some peculiarities in your multitasking code that I didn't attempt to fix. At first I thought I had introduced the bugs but noticed that the same problems exist even with your original code.
There are some peculiarities in your multitasking code that I didn't attempt to fix. At first I thought I had introduced the bugs but noticed that the same problems exist even with your original code.
Re: Weird bug involving interrupts and multitasking
Thanks to you two who replied. I will take a look at your PR shortly, however, i have tinkered my own, (probably simpler) implementation, it is a LOT cleaner now, and lives in a separate task, like it is supposed to