Weird bug involving interrupts and multitasking

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
qwr
Posts: 5
Joined: Wed Oct 16, 2024 10:29 am
Libera.chat IRC: qwr

Weird bug involving interrupts and multitasking

Post by qwr »

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.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Weird bug involving interrupts and multitasking

Post by MichaelPetch »

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.
qwr
Posts: 5
Joined: Wed Oct 16, 2024 10:29 am
Libera.chat IRC: qwr

Re: Weird bug involving interrupts and multitasking

Post by qwr »

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 :D !

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?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Weird bug involving interrupts and multitasking

Post by JAAman »

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):
  • 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
in this way, you completely separate the program from the input mechanism, allowing the same input mechanism (generally called a driver) to be used for all programs running under the OS
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Weird bug involving interrupts and multitasking

Post by MichaelPetch »

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.
qwr
Posts: 5
Joined: Wed Oct 16, 2024 10:29 am
Libera.chat IRC: qwr

Re: Weird bug involving interrupts and multitasking

Post by qwr »

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 :D
Post Reply