Pre-Question, Question: When in my scheduler, interrupts should be disabled right?
Actual Question:
So I am trying to figure out how to create a higher level kyb driver. What I mean is, I have the interrupts setup, and can "echo" keypress, but I want to make it more aware of whats going on... I currently have task switching enabled via timer interrupt...
This is what I was thinking:
I have a couple of tasks:
Task 1 (AVERAGE Priority)- CLI
Task 2 (VERY_LOW Priority)- Kernel IDLE
Task 3 (HIGH Priority)- Kernel Interpeter
Task 4 (VERY_LOW Priority)- Keyboard Driver
When a key is pressed, the task handler finds out when Task is currently running, and adds an entry to the kernel Interpreter Saying something like: "KEYPRESS Ascii:34 Modifiers:None Active Task:Task1" howerver, this would be in enumerators, and not actual text. From there, the kernel Interprepeter would send the keypress over to the CLI, and the next time the CLI would ask for a key, one would be in its buffer.
Or am I totally off the mark on the Keyboard driver thing...
Please help me figure out how the heck I am going to create a simple, but effective driver modal.
Thanks,
Rich
Higher Level Keyboard Driver
You don't necessarily want to send any keypress to the task that is currently running. For example, if the shell is just sitting there doing nothing except displaying a prompt and a cursor, then it will not actually be running and it is likely that either the idle task or a background task is running. You want to keep track of which task has the 'focus' and send the keypress to that process.
In text-based UIs there is normally one full screen application per virtual terminal. That is the one which has the focus. In a GUI then it is the process owning the selected window.
Additionally, you want to intercept certain keypresses before sending them to the focused application. You may want to either process them in-kernel or dispatch them to another process. For example, Windows handles Ctrl-Alt-Delete as a special case which activates the security window or task manager. Ctrl-Esc is dispatched to the start menu.
Deciding how you deal with keystrokes is dependent on whether you're implementing a monolithic or microkernel. I'll assume, from the fact you have a keyboard driver as a separate process, that you're making a microkernel. In that case, you still need to decide how much interpretation of keystrokes goes on in the keyboard driver and how much goes on within the user-space library linked to each process.
In theory, you could create a workstation driver, which deals with both input and output to a particular monitor/keyboard/mouse setup, and have that on top of your lower level drivers, so that calls to both getch() and putch() go to it. The alternative is to deliver keypress data to a buffer within the address space of the process which has the focus.
On a separate note, it isn't sensible to have the keyboard driver (or any application) at the same priority as the idle task. If the keyboard driver is woken up by a keypress, it is still not guaranteed that it will execute instead of the idle task, or that it will not be preempted by the idle task before it has finished processing. Make your idle task the lowest possible priority, and have nothing else at that level.
Regards,
John.
In text-based UIs there is normally one full screen application per virtual terminal. That is the one which has the focus. In a GUI then it is the process owning the selected window.
Additionally, you want to intercept certain keypresses before sending them to the focused application. You may want to either process them in-kernel or dispatch them to another process. For example, Windows handles Ctrl-Alt-Delete as a special case which activates the security window or task manager. Ctrl-Esc is dispatched to the start menu.
Deciding how you deal with keystrokes is dependent on whether you're implementing a monolithic or microkernel. I'll assume, from the fact you have a keyboard driver as a separate process, that you're making a microkernel. In that case, you still need to decide how much interpretation of keystrokes goes on in the keyboard driver and how much goes on within the user-space library linked to each process.
In theory, you could create a workstation driver, which deals with both input and output to a particular monitor/keyboard/mouse setup, and have that on top of your lower level drivers, so that calls to both getch() and putch() go to it. The alternative is to deliver keypress data to a buffer within the address space of the process which has the focus.
On a separate note, it isn't sensible to have the keyboard driver (or any application) at the same priority as the idle task. If the keyboard driver is woken up by a keypress, it is still not guaranteed that it will execute instead of the idle task, or that it will not be preempted by the idle task before it has finished processing. Make your idle task the lowest possible priority, and have nothing else at that level.
Personally I would say yes, as you don't want to preempt the scheduler. Preemptable kernels are possible, but require careful coding and use of critical sections where interrupts are disabled. As the scheduler updates critical parts of memory to perform a task switch, it needs to complete that update before another task switch can take place. Therefore, you really don't want the timer interrupt firing and starting another task switch in the middle. You may be able to process other interrupts during a task switch, but that would involve selectively disabling the timer interrupt, and programming the PIC is a lot slower than just doing 'cli', and is probably not worth the hassle. If you can make your scheduler tidy enough, it shouldn't spend too long with interrupts disabled anyway.astrocrep wrote:Pre-Question, Question: When in my scheduler, interrupts should be disabled right?
Regards,
John.
If you need to disable the timer during the timer... you have serious issues. That would mean the Scheduler actually takes longer than a single Quotum to complete... wheras you should be aiming at it only taking as small a portion of it as possible.jnc100 wrote: Personally I would say yes, as you don't want to preempt the scheduler. Preemptable kernels are possible, but require careful coding and use of critical sections where interrupts are disabled. As the scheduler updates critical parts of memory to perform a task switch, it needs to complete that update before another task switch can take place. Therefore, you really don't want the timer interrupt firing and starting another task switch in the middle. You may be able to process other interrupts during a task switch, but that would involve selectively disabling the timer interrupt, and programming the PIC is a lot slower than just doing 'cli', and is probably not worth the hassle. If you can make your scheduler tidy enough, it shouldn't spend too long with interrupts disabled anyway.
Regards,
John.
I agree, but it doesn't make sense to assume this for every single call to the scheduler. Certain calls might require creating new structures, with calls to malloc and maybe a page fault as well. I don't personally think a scheduler should do such things, but then I can't speak for other people's code.Tyler wrote:If you need to disable the timer during the timer... you have serious issues. That would mean the Scheduler actually takes longer than a single Quotum to complete... wheras you should be aiming at it only taking as small a portion of it as possible.
Regards,
John.
User apps may voluntarily block just before an IRQ0 timer tick fires -- so this is a case that needs to be handled.
But I don't use a cli myself, I have an "atomic flag." If the IRQ0 handler sees that flag set, it just updates the system clock and then does an iret -- it does not try to generate a task switch. Only trusted tasks can go atomic, and they only get one extra timeslice. If they are still atomic the next time IRQ0 fires, they are terminated with extreme prejudice.
But I don't use a cli myself, I have an "atomic flag." If the IRQ0 handler sees that flag set, it just updates the system clock and then does an iret -- it does not try to generate a task switch. Only trusted tasks can go atomic, and they only get one extra timeslice. If they are still atomic the next time IRQ0 fires, they are terminated with extreme prejudice.
Would using the Gate that disables interupts (can't remember if that is Interupt Gate or Trap Gate), prevent the clock from firing again in such a situation? Else, would it be necesary to disable interupts as soon as you enter the scheduler, causing problems if it fires just before the code completes.bewing wrote:User apps may voluntarily block just before an IRQ0 timer tick fires -- so this is a case that needs to be handled.
the clock will continue to fire even if interrupts are disabled, as soon as they are re-enabled, the interrupts that were waiting will fire, therefore, most of the time, this wont be a problem, except you may get another switch as soon as you iret into the user code (meaning that code doesnt get any time to execute, and a useless task-switch has occured)Would using the Gate that disables interupts (can't remember if that is Interupt Gate or Trap Gate), prevent the clock from firing again in such a situation? Else, would it be necesary to disable interupts as soon as you enter the scheduler, causing problems if it fires just before the code completes.