Does anyone have a REALLY simple multitasking example? I can't seem to get it working.
What does the GDT entry for the TSS look like?
Once you are in protected mode, don't you just have to
do a LTR with the selector of the TSS? And the TSS selector's base address should point to an area of memory where you set a 120-byte table with the correct EIP, SS, CS, DS, etc, correct?
Right after a do the LTR, I just jump forever. waiting
for a task switch.
I've tried so many different things and the only results I've ever gotten were either a GPF at EIP 0x18 (which is, incidentally my TSS descriptor!!!) or it just hangs.
It never gets to the EIP I plugged into the TSS.
Hopefully someone has a small SIMPLE example
thanks!
Paul
Multitasking
Re:Multitasking
Most people use stack-based task switching and not TSS based task switching so most examples use stack-based. I have actually found stack-based task switching easier than TSS task switching, plus stack-based is WAY faster. If you would like a stack-based example, email me @ [email protected] and I'll send it to you.
K.J.
K.J.
Re:Multitasking
I have been trying to get stack-based task-switching to work without any luck. I found some crappy example on the Internet and used it as a guide.
I'm a bit confused about it. The example does the task switching from the IRQ0 interrupt service routine (which is INT 20h in my o/s) When this interrupt is triggered, I handle the interrupt as I normally do, but before my IRET, I switch tasks.
The way it switches tasks is like this: It pushes all of registers on the stack except the flags register and ESP and SS. It then saves SS and ESP in a table. It then determines the next task it needs to switch to and loads its SS and ESP from a table. Then, it pops all of the reigisters from that task's stack (except ESP and SS). Then, it uses IRETD to get the last EIP, CS and flags register.
I keep getting GENERAL PROTECTION FAULTS when I try to run it!! What my program does is set up a couple of stacks and then enables multitasking. (So, the timer interrupt isn't trying to switch tasks before I get my stuff set up.)
The way I set up the stacks is I manually fill the appropriate areas of memory with the appropriate data as though I pushed all of the registers on each process's stack (including EIP, CS, and the flags register) I just use dword 0x202 for the flags. I adjust the saved version of ESP in the tables too.
Do you know what the problem could be?
Maybe I'm not understanding IRETD. I don't get it...When a hardware interrupt is triggered, how do you know when to use IRETD or IRET. I'm pretty sure that IRETD also pops CS from the stack (in addition to EIP and FLAGS) So, if it works the way I think it does, IRET pops 8 bytes from the stack and IRETD pops 12 bytes.
All of my ISR's return with IRET and they seem to work okay. It seems strange to suddenly use IRETD to return from the timer interrupt (but that is how they do it in that example I found.)
I'm a bit confused about it. The example does the task switching from the IRQ0 interrupt service routine (which is INT 20h in my o/s) When this interrupt is triggered, I handle the interrupt as I normally do, but before my IRET, I switch tasks.
The way it switches tasks is like this: It pushes all of registers on the stack except the flags register and ESP and SS. It then saves SS and ESP in a table. It then determines the next task it needs to switch to and loads its SS and ESP from a table. Then, it pops all of the reigisters from that task's stack (except ESP and SS). Then, it uses IRETD to get the last EIP, CS and flags register.
I keep getting GENERAL PROTECTION FAULTS when I try to run it!! What my program does is set up a couple of stacks and then enables multitasking. (So, the timer interrupt isn't trying to switch tasks before I get my stuff set up.)
The way I set up the stacks is I manually fill the appropriate areas of memory with the appropriate data as though I pushed all of the registers on each process's stack (including EIP, CS, and the flags register) I just use dword 0x202 for the flags. I adjust the saved version of ESP in the tables too.
Do you know what the problem could be?
Maybe I'm not understanding IRETD. I don't get it...When a hardware interrupt is triggered, how do you know when to use IRETD or IRET. I'm pretty sure that IRETD also pops CS from the stack (in addition to EIP and FLAGS) So, if it works the way I think it does, IRET pops 8 bytes from the stack and IRETD pops 12 bytes.
All of my ISR's return with IRET and they seem to work okay. It seems strange to suddenly use IRETD to return from the timer interrupt (but that is how they do it in that example I found.)
Re:Multitasking
hi, do a search with the keyword 'stack task switch' in this forum. this topic has been presented a lot of times ;D there are over 16 threads on the topic alone
Re:Multitasking
I got stack-based multitasking to work. Thanks everyone! How do you write a good scheduler? My scheduler just gives all processes equal CPU time (and it changes tasks 28 times per second, or whatever the interval of IRQ 0 is.)
There is one cool feature about it though. There is a kernel function called SLEEP that takes a parameter for the number of milliseconds to sleep. Instead of having a tight loop that keeps checking to see if the sleep time as ellapsed yet, it will cause a task-switch (theirby giving up the rest of its time slice.) And then the scheduler will not switch to that task again until its sleep time has ellapsed. So this way, it only checks to see if the time is up once every IRQ0 interrupt. (Or not even that -- only when it's time to task-switch to that task.)
One really annoying effect that can happen is this... Lets say you start 28 tasks and all of them have a tight loop without a sleep call. Each task get a burst of CPU time only ONCE A SECOND. If you had 56 tasks running concurrently, they will all get a burst of CPU times every 2 seconds. I noticed that doesn't happen under Windows 2000. Any clever ideas?
There is one cool feature about it though. There is a kernel function called SLEEP that takes a parameter for the number of milliseconds to sleep. Instead of having a tight loop that keeps checking to see if the sleep time as ellapsed yet, it will cause a task-switch (theirby giving up the rest of its time slice.) And then the scheduler will not switch to that task again until its sleep time has ellapsed. So this way, it only checks to see if the time is up once every IRQ0 interrupt. (Or not even that -- only when it's time to task-switch to that task.)
One really annoying effect that can happen is this... Lets say you start 28 tasks and all of them have a tight loop without a sleep call. Each task get a burst of CPU time only ONCE A SECOND. If you had 56 tasks running concurrently, they will all get a burst of CPU times every 2 seconds. I noticed that doesn't happen under Windows 2000. Any clever ideas?
Re:Multitasking
Now you've got that to work, recognise that not all threads need to run all the time. If you look at a typical Windows 2000 system, most of the threads don't need to be running all the time since they are waiting for some external event, usually user input or I/O. So when a thread does need to run, it can do so fairly quickly and for a reasonable length of time, because most of the other threads don't need to run.
The situation you have is 28 or 56 threads stuck in tight loops. If you wrote a Windows program that spawned 28 threads consisting of while (1) ; then you'd get a similar situation: they'd each run once a second.
The situation you have is 28 or 56 threads stuck in tight loops. If you wrote a Windows program that spawned 28 threads consisting of while (1) ; then you'd get a similar situation: they'd each run once a second.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Multitasking
if you have threads that keeps using the CPU without doing anything that can make them suspended (I/O, page miss, ...), they are likely to be batch (not user-reactive) CPU-bound process. Except badly-behaved programs (here: jmp here ), the only programs i can see that would fall in this category is heavy-computing programs like raytracers, renderers, etc.
Such threads should not make responsiveness decrease (imho), thus i suggest they receive a lower priority and be interruptible by event-responding threads.
if they're purely CPU-bound (i.e. no synchronization of any kind), there's no reason to continue interlapping them rather than executing them serially (run raytracing task 1 to completion, then task 2 to completion ...), which can lead to faster global completion time as it reduces context switches ... moreover, users are likely to prefer a finished task after 50% of the total time and the other task after the other 50% than having to wait the whole completion time for the first byte of results ...
maybe this could be a user choice (whether & when to turn process to batch mode, ...)
The same kind of operation can be done with I/O-bound process (serializing big disk copies to avoid the disk to seek seeek seeeeeek and seeeeeek again problem you have if you start 2 copies from a CDROM in parallel with windows)
does it make sense ?
Such threads should not make responsiveness decrease (imho), thus i suggest they receive a lower priority and be interruptible by event-responding threads.
if they're purely CPU-bound (i.e. no synchronization of any kind), there's no reason to continue interlapping them rather than executing them serially (run raytracing task 1 to completion, then task 2 to completion ...), which can lead to faster global completion time as it reduces context switches ... moreover, users are likely to prefer a finished task after 50% of the total time and the other task after the other 50% than having to wait the whole completion time for the first byte of results ...
maybe this could be a user choice (whether & when to turn process to batch mode, ...)
The same kind of operation can be done with I/O-bound process (serializing big disk copies to avoid the disk to seek seeek seeeeeek and seeeeeek again problem you have if you start 2 copies from a CDROM in parallel with windows)
does it make sense ?
Re:Multitasking
The NT scheduler does something similar to this: it gives a temporary boost to threads that have just finished some I/O. Hence if you have two threads, one of which is heavily CPU-intensive and one which waits for keypresses, the keypress one will run every time you press a key since it receives a temporary boost.Such threads should not make responsiveness decrease (imho), thus i suggest they receive a lower priority and be interruptible by event-responding threads.
This kind of thing comes into the class of dynamic priorities: NT threads have a static priority (i.e. the priority it a thread given when it started) and a dynamic priority (decided by the scheduler according to various factors).