Page 1 of 1

End of task ?

Posted: Thu Jun 01, 2006 1:25 pm
by Aurea
Hi,

I am presently implementing pre emptive scheduling using stack based switching. It works all nice & great : I have two dummy functions, "idle_task()" and "print_task", each of them containing an endless loop to print a counter of how many times they are being switched to..

My question is the following : what happens if I replace the endless loop by a "return" ? I tried, and I get an exception "Invalid Opcode", I assume that it means that the EIP is set to some random value or something similar. How to catch the end of a task to delete it from the scheduler ?

Thanks !

Re:End of task ?

Posted: Thu Jun 01, 2006 1:41 pm
by GLneo
I?ve never really figured this out, I just tried to make a system call function "void exit ( int status );" to delete the task

Re:End of task ?

Posted: Thu Jun 01, 2006 2:08 pm
by Brendan
Hi,
GLneo wrote:I?ve never really figured this out, I just tried to make a system call function "void exit ( int status );" to delete the task
That is how it is normally done - usually it's hidden by a library or something though.

When you create a task's stack you could put a special return value on it - for CPL=0 tasks this value would be the address of the kernel's "void exit ( int status );" routine, and for CPL=3 task's it'd be something that is easy for an exception handler to check for (e.g. the general protection fault handler or the page fault handler could detect a "return to 0xFFFFFFF" and jump to the "void exit ( int status );" routine).


Cheers,

Brendan

Re:End of task ?

Posted: Thu Jun 01, 2006 2:16 pm
by Aurea
Thank you very much for your answers !

Back to the endless joy of OS coding ;p

Re:End of task ?

Posted: Thu Jun 01, 2006 2:31 pm
by rootel77
In my code, i just set the start eip for a newly created task to a special function threadMain

Code: Select all

void threadMain(Function task, void *startArg) {
   task(startArg);   
   removeThread();
   //The main thread function should not return
}
if the task has called exit() then we never reach removeThread(), if the task terminates or returns then we reach removeThread() that simply removes the current thread from the sheduler.

Re:End of task ?

Posted: Thu Jun 01, 2006 2:41 pm
by Brendan
Hi,
rootel77 wrote:if the task has called exit() then we never reach removeThread(), if the task terminates or returns then we reach removeThread() that simply removes the current thread from the sheduler.
That's the normal way (usually hidden in startup libraries).

I was thinking of something more like DOS "*.COM" programs, where you can have a "do nothing" program that is one byte long - as an assembly programmer I think there's something nice about it... :)


Cheers,

Brendan

Re:End of task ?

Posted: Thu Jun 01, 2006 3:21 pm
by Candy
Do nothing & quit would be 1 byte (0xC3). Do nothing needs 2 bytes: 0xEB 0xFE.

Re:End of task ?

Posted: Fri Jun 02, 2006 12:07 am
by distantvoices
leaving a thread you mean?

I do it this way: I put a return value to a library threadExit function onto the thread stack frame, so that, when the thread exits its main function without calling threadExit explicitly, it gets called implicitly.

you can also prepend your program with a kind of runtime stub (a la crt0.o) which prepares the stack, initializes errno & eof and fetches argc & argv ere calling main(). after the call to main there 's possibly a call to exit() so the process dies after having done its stuff.

Hope this helps :-)

Re:End of task ?

Posted: Fri Jun 02, 2006 1:21 am
by mystran
BI: I'll basicly do the same.

In fact, my threads are started with a similar trick. Lowest level thread switching function really just does a return after pushing callee saved registers, saving esp to the beginning of old thread's stack, loading new esp from the beginning of the new thread's stack, and popping callee saved registers of new thread. It's the only piece of assembler in the whole multi-threading code, and it looks like a normal C function to the caller. When a thread is started, the stack is initialized such that the return (which would normally go to scheduler) will jump to the beginning of the requested thread function.

Oh, and the function to exit the current thread just sends (using my normal messaging) a request to kill itself to a special killer task, and let's scheduler to do a (normal) switch. Killer will then take the thread out of any queues it's in (so it's essentially unreachable), mark the lifestone dead (see elsewhere), and free any thread specific objects, including the stack itself.

One more detail about my design: the whole multi-threading code itself is co-operative, although it does respect priorities. The only things that really makes it pre-emptive, are interrupt handlers calling the scheduling function. Remove those, and it's a pure co-operative system where you need to call the scheduling function manually wherever you want to allow a switch.

Re:End of task ?

Posted: Fri Jun 02, 2006 7:52 am
by Brendan
Hi,
mystran wrote:Oh, and the function to exit the current thread just sends (using my normal messaging) a request to kill itself to a special killer task, and let's scheduler to do a (normal) switch. Killer will then take the thread out of any queues it's in (so it's essentially unreachable), mark the lifestone dead (see elsewhere), and free any thread specific objects, including the stack itself.
I usually have a "terminateThread()" kernel function which frees everything it can and then broadcasts an "obituary" message to any other threads that want to receive it. There's a kernel thread (the "terminator") that receives this obituary and frees anything left over (e.g. the address space itself) except for the threadID, and puts the threadID on a timeout queue. After 30 seconds the threadID is also freed. This time delay just gives other threads a chance to realise that the thread was terminated and stop sending messages to it before the threadID can be re-used for something else.

For "terminateProcess()", it broadcasts a "shutdown" message to every thread that belongs to the process (except for the calling thread) and then sends a message to the kernel's "terminator" thread - the calling thread ends up at the "terminateThread()" kernel function. The kernel's "terminator" thread puts each thread in the process onto it's timeout queue, and if any of the threads are still running after the timeout it "force terminates" them without their permission (in case they've locked up). During this timeout a thread can send a "give me more time" message to prolong the forced termination (in case it needs to save a lot of data or something and hasn't locked up).

On top of this I need a "kill the process NOW" feature which immediately force terminates all of the threads that belong to the process. I've never really got around to implementing this though.


Cheers,

Brendan

Re:End of task ?

Posted: Fri Jun 02, 2006 9:09 am
by mystran
Maybe I should rename my killer "Arnold."