About the ESP0 field...
So you basicly call your scheduler something like below?
edit: actually that's what Voix did in the clock interrupts interrupt handler until recently, without the prints ofcourse. Now there's a slightly more advanced scheme where you aren't allowed to call scheduler from interrupt/deferred context, but instead just mark that it should be called as soon as it's allowed again...
Code: Select all
printf("ok going to call scheduler\n");
schedule();
printf("ok I got scheduled again\n");
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
No, it works via the clock interrupt. And inside the scheduler is where the text is printed.
I currently have a simple loop:
Without any multitasking (but interrupts enabled) this will throw an invalid opcode instruction. Any ideas why?
Woah... If I take out the timer install function (ie. no timer interrupt) I have no problems. Now I have to figure out why.
I currently have a simple loop:
Code: Select all
while( true );
Woah... If I take out the timer install function (ie. no timer interrupt) I have no problems. Now I have to figure out why.
This is a bit lengthy so I will just attach it:
I tried to cut out as much of the code that is irrelevant to basic multitasking as possible but some may still be in there. Also I hope that it is easy to understand but if not just ask more questions.
I tried to cut out as much of the code that is irrelevant to basic multitasking as possible but some may still be in there. Also I hope that it is easy to understand but if not just ask more questions.
- Attachments
-
- help.txt
- (9.46 KiB) Downloaded 97 times
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
Hey, wow, thanks! This code works really well, apart from one thing. I still can't use function calls inside functions (at least not if they get preempted by the IRQ).
For instance, the following task will execute without any problems:
But this code will throw a GPF after each process has run and it's back to the first process again:
It'll print out lots of 'a' characters then die with a GPF. Bochs log at time of crash:
Any ideas why this happens?
Edit: wait. It seems to be fixed ... I don't get it.
For instance, the following task will execute without any problems:
Code: Select all
void task()
{
while( true )
*(unsigned short*) ( 0xB8000 + ( 79 * 2 ) ) = ( 0x1F << 8 ) | 'M';
}
Code: Select all
void task()
{
while( true )
{
kprintf( "a" );
}
}
Code: Select all
00043354249e[CPU0 ] fetch_raw_descriptor: GDT: index (a407)1480 > limit (77)
00107478000p[WGUI ] >>PANIC<< POWER button turned off.
00107478000i[SYS ] Last time is 1177919982
00107478000i[CPU0 ] protected mode
00107478000i[CPU0 ] CS.d_b = 32 bit
00107478000i[CPU0 ] SS.d_b = 32 bit
00107478000i[CPU0 ] | EAX=00000016 EBX=00157d07 ECX=000b8f28 EDX=870003d5
00107478000i[CPU0 ] | ESP=00157caf EBP=00157cb7 ESI=00000000 EDI=00000000
00107478000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af PF cf
00107478000i[CPU0 ] | SEG selector base limit G D
00107478000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00107478000i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | EIP=00107b0a (00107b0a)
00107478000i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00107478000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00107478000i[CPU0 ] >> jmp .+0xfffffffe (0x00107b0a) : EBFE
00107478000i[ ] restoring default signal behavior
00107478000i[CTRL ] quit_sim called with exit code 1
Edit: wait. It seems to be fixed ... I don't get it.
You probably aren't restoring ESP correctly. If you inline the printing, it won't need ESP, whereas a function call obviously needs a return address, which is probably where it fails.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
For kernel threads or for user threads?pcmattman wrote:Well, I just did a test and I found that the timeslice I was giving each process was massive, and once I reduced it the problem went away (I think).
One question, how do I setup another function to be called when the task itself exits?
For kernel threads, make a function like die() or something that kills the currently running thread. It can be a bit tricky as you can't free the stack while you still need it, so easiest thing is to have a separate "killer task" or something, and have die() send it a message that the task should be killed. You don't want die() to take any parameters if you want to have it called automatically upon return.
For user threads, add a system call like _exit() which calls die() internally.
For kernel threads then, if you want them to automatically return when the function they run returns, just build a suitable stack before starting the thread: put the address for die() as the return address. As long as die() needs no parameters, this'll work, even if it sounds funny. You can then put any parameters to your thread-function below the return address, if you want.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
I did that, it worked perfectly.
One more question I have: where do I push arguments in this code:
I think the arguments may have to be pushed after the line
Am I right?
One more question I have: where do I push arguments in this code:
Code: Select all
// return addy
esp--;
*esp-- = 0x10;
*esp-- = ( unsigned int ) userstack1 + 1024; // not sure this is necessary...
*esp-- = 0x0202;
*esp-- = 0x08;
*esp-- = (unsigned int) ¨ // kills the process
/** arguments pushed here? **/
*esp-- = 0x0202;
*esp-- = 0x08;
*esp-- = (unsigned int) &task;
/** arguments pushed here? **/
/** registers pushed on stack, segments etc... **/
Code: Select all
*esp-- = (unsigned int) &task;
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
OK, I still haven't figured out the whole arguments thing... But I'm getting there
The good news is, everything that didn't work in my old multitasker is working now! Thanks everyone for all your help, especially mystran and frank - your code really helped!
As a test, I setup a thread in my kernel called 'udp:4000' as a udp server on port 4000 that sends 'woot' back to anyone who sends it data. The other thread is the system procedure that prints an 'M' in the top right corner.
It didn't crash
The good news is, everything that didn't work in my old multitasker is working now! Thanks everyone for all your help, especially mystran and frank - your code really helped!
As a test, I setup a thread in my kernel called 'udp:4000' as a udp server on port 4000 that sends 'woot' back to anyone who sends it data. The other thread is the system procedure that prints an 'M' in the top right corner.
It didn't crash
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
Yeah, I've been testing the whole argument thing and it turns out that if I run a task that takes two arguments, the two arguments I receive are the CS and EFLAGS pushed onto the stack before EIP...
Any ideas why?
Code: Select all
// base of the task
*esp-- = EFLAGS_IF | EFLAGS_IOPL0 | EFLAGS_ALWAYS1; // second?
*esp-- = 0x08; // task thinks this is first argument
*esp-- = base;
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
It's a kernel thread.
Is that why, in your code, you do this?
Edit:
I did this:
And then when I got the argument from my task, it came out as 0x10? Why is it the stack segment, and not the actual data?
Is that why, in your code, you do this?
Code: Select all
*esp-- = 32 + 3; // user stack segment
*esp-- = (DWORD)user_stack;
I did this:
Code: Select all
// user stack
*esp-- = 0x10;
*esp-- = ptable[i].ustack;
// base of the task
*esp-- = EFLAGS_IF | EFLAGS_IOPL0 | EFLAGS_ALWAYS1;
*esp-- = 0x08;
*esp-- = base;