deleting a task

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
finda

deleting a task

Post by finda »

I have implement my task manager and task switching code. I can add new tasks to my task queue. But my probem is to catch a task when it finishes. I mean all my tasks must be infinite. if a task finishes, my kernel couse an invalid opcode. How can I delete a task from my queue after task returns?(I implement my delete task function, but dont know how to understand if a task finishes...)
BI lazy

Re:deleting a task

Post by BI lazy »

Well: you need to have the task inform the kernel about exit with some call like: exit(0). Immediately after this call, you have to put the task in some kind of infinite loop to take care that it doesnt stroll out of its adress space. It is caught in this loop and just sits and waits for deletion.

Additionally, you can move the task to some queue like "tasks_to_delete" and have some kernel thread take care of it, when nothing else is to do in the system: it triggers all the clean up stuff, claims the tasks adress space back for system, moves pages back to the free pages stack, eventually zeroes them out ... one can imagine many many way. The idea of a "buffy - the dead thread slayer" kernel thread stems not from me originally. But it is a good idea.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:deleting a task

Post by Pype.Clicker »

for someone that is used to Unix programming, killing a task may sound weird, because under unix, you needn't to call "exit(0)" explicitly: returning from main() function is sufficient.

What you need to know is that your unix C code is not naked when the system executes it: it has been wrapped into a cute "crt.o" binary file that contains something like

Code: Select all

__start:
     ; prepare args & argv on the stack
     call main
     mov ebx,eax (keep C function result)
     mov eax, SYS_EXIT_CODE
     int SYSTEM_CALL_INTERRUPT
BI lazy

Re:deleting a task

Post by BI lazy »

hmmm ... and who takes care the task doesn't stroll out of bounds if not slayed immediately?

I've seen somewhere, that after performing the exit epilogue the processes/tasks are caught in an endless loop untill they are dropped to the graveyard - ere they become zombies and you have to take the wooden stanchion of kill to get rid of 'em.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:deleting a task

Post by Pype.Clicker »

BI lazy wrote: hmmm ... and who takes care the task doesn't stroll out of bounds if not slayed immediately?
Err ... what i was showing was not intended to replace the good 'Thread Slayer' of the system, just to replace the "main() {exit(0);}" by "main() {return 0;}" ...

I suspect i do not have the simplest solution, but in Clicker, when a thread want to die (or is killed), its id is sent to a special thread that can go to that address space and cleanup what has to be cleaned (kernel and user stack for this thread, for instance).

It's especially hard to have a thread killing itself properly, if you think about it a few minutes ...
proxy

Re:deleting a task

Post by proxy »

the way i handled this, was when i am setting up the task for entry in the task queue, i setup the stack in such a way that it will jump to a "thread_finish" function when it returns from the outermost function. This function marks the thread as finished, calls the threads terminiation code (unblock waiting threadsd, etc), then the scheduler will delete it at a later time.

i found this to be simplest, as it "just works"

proxy
Tim

Re:deleting a task

Post by Tim »

In Mobius, all user-mode threads have their entry point set to a function within libsys.dll, which looks like: (from memory)

Code: Select all

void ThrStartup(void)
{
    thread_info_t *info = ThrGetThreadInfo();
    ThrExitThread(info->entry(info->param));
}
ThrExitThread is a system call which frees most of the thread's resources, makes the thread unrunnable, then switches threads. The thread's kernel stack ought to be given to a special kernel thread for later disposal, but I haven't written that yet.
proxy

Re:deleting a task

Post by proxy »

call me crazy, but i don't understand the "need" for a reaper thread at all, or these wrapper functions.

my code to setup a thread basically looks like this: (C++, not C, but clear enough, also using setjmp switch technique for now)

Code: Select all

   setName(name);
   
   // get a resonable snapshot of the system state to start...
   setjmp(m_State);
   
   // allocate a stack (remember it for destruction)
   stack_ptr = calloc(MAX_THREAD_STACK, 1);
   
   // get a 32-bit pointer to end of stack
   uint32 *stack = (uint32 *)((char *)stack_ptr + MAX_THREAD_STACK);
         
   // push on some objects (return address, etc)
   // args start here (reverse order)
   *--stack = (uint32)func_arg;
   
   // return address here
   *--stack = (uint32)Scheduler::thread_finished;
   
   // setup stack pointer (grows down)
   m_State[0].esp      = (uint32)stack;
   
   // set the address to the function we want to run
   m_State[0].eip      = (uint32)func_ptr;
   
   // interrupts enabled
   m_State[0].eflags   = 0x0200;
   
   // set to runable
   m_Status = RUNNABLE;
   
   // add to scheduler
   Scheduler::instance()->enqueue(this);
the important thing is:

Code: Select all

*--stack = (uint32)Scheduler::thread_finished;
that places the address of the thread_finished function in a spot on the stack so that when the outer most function returns, it just jumps to that which changes the thread to a FINISHED state, unblocks any waiting threads, and calls my yield function to continue execution.

then the scheduler wil actually delete the object next time it tries to schedule it because it is marked as finished.

no need for "reaper threads", or infinite loops to keep it all sane, just a return address ;)

perhaps there is some advantage to these other techniques i dont see, if so please let me know.

proxy
Tim

Re:deleting a task

Post by Tim »

A reaper thread is needed because as soon as the kernel frees the thread's kernel-mode stack, that memory is available for reuse. So the thread must not be current when its kernel-mode stack is freed.

There is the same problem with exiting a process: the kernel can't free the page directory while the process is current.
proxy

Re:deleting a task

Post by proxy »

oh i agree it cannot be freed while it is currently in use, this is why i have my scheduler do the actual deleting, basically when it picks the next task, if it is in a "finished" state, it get's deleted and it picks again.

You might say, that this is inefficient because there is redundant thread selection, but compared to the amount of context switches, the number of delete ones hit is pretty rare.

i guess you could sort of call my scheduler my "reaper thread" in that sense, it is sort of doing the same thing.

proxy
BI lazy

Re:deleting a task

Post by BI lazy »

@pype: ok.

@proxy: The scheduler shouldn't have to do this. It sounds like too much overhead ere a new task is selected.

In my opinin it is way better to drop the task to a dedicated thread which takes it, triggers all the necessary clean up work (sends messages to other tasks...) and then removes it from the system. I also think it is not under all circumstances necessary to catch it in an endless loop after doing the exit system call - especially when the task is marked as not runnable or moved to a dedicated queue say "zombie tasks" which is kept by buffy the grim reaper thread.
Slasher

Re:deleting a task

Post by Slasher »

Why no have system call, like task_destroy or something. Then the tasks can destroy themselves directly by calling it or indirectly by the stack return method.
I think a task or thread dedicated to destroying tasks is overkill.
After all it is just
close Files,release resources - memory,dedicated devices, and remove pcb from system.
Tim

Re:deleting a task

Post by Tim »

Code Slasher: The reaper thread is still necessary at least for the thread's kernel stack. This is because the ThrExitThread (in my case) system call runs in the context of the calling thread, which like any other interrupt uses the current thread's kernel stack. You can't free the kernel stack pages if the code that's doing the freeing is using them at the time.
Post Reply