Terminating current 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
glauxosdever
Member
Member
Posts: 501
Joined: Wed Jun 17, 2015 9:40 am
Libera.chat IRC: glauxosdever
Location: Athens, Greece

Terminating current task

Post by glauxosdever »

Hi,


I am not really sure how should I implement current thread termination. The steps needed to be done are (in a random order):
  • Remove the thread structure from the thread list.
  • Free the thread structure and the stack of this thread.
  • Switch to another thread.
The problem arises when trying to design this. When I free the thread structure and the stack of the thread before I switch to the next thread, then it will crash because the stack will be not present. When I switch to the next thread before I free the thread structure and the stack of the thread, then freeing will never be run, since the other thread will not know that something irrelevant to itself needs to be cleaned. Maybe I should have a thread dedicated to freeing stacks and thread structures (though I would prefer having as less as possible worker threads)?

It would be nice if anybody enlightened me on this matter.


Thanks in advance,
glauxosdever
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: Terminating current task

Post by mariuszp »

I just have a special thread called a system management thread, and when a thread wants to exit, it puts its thread description onto a queue for the SMT, and the SMT is responsible for then removing the (now sleeping) terminating thread from the process list, releasing its stack, etc. The SMT never exits so the problems you've describe cannot occur.
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: Terminating current task

Post by mariuszp »

My apologies, I didn't notice the note about how you prefer less worker threads. Here's another solution, which may or may not work depending on your design. This assumes that your kernel stacks are allocated on the kernel heap.

1. ensure that the handle of the thread description, and the stack base, are placed in registers.
2. disable interrupts
3. remove the thread from the queue.
4. free the thread description.
5. free the stack, by marking its heap block as free (without actually using the stack to do this; in my case this would work since the block header, which stores whether or not the block is free, is placed right before the start of the block, so it's just a constant offset).
6. switch to the next process without using the stack; this includes actually jumping onto another thread's stack.
7. you may now safely enable interrupts, and the thread was removed :)

if your stack is allocated not on the kernel heap, but as a list of pages, then you'd have to unmap the pages, again using only registers, and not the stack.
Boris
Member
Member
Posts: 145
Joined: Sat Nov 07, 2015 3:12 pm

Re: Terminating current task

Post by Boris »

Hi,
If you can, do not allocate kernel stacks in the kernel heap.
Using pages to allocate stack gives you the opportunity to set up non present " guard pages". Small stack overflow ( less than a page size) will be caught by page faults, instead of corrupting the kernel heap,which can be catastrophic
glauxosdever
Member
Member
Posts: 501
Joined: Wed Jun 17, 2015 9:40 am
Libera.chat IRC: glauxosdever
Location: Athens, Greece

Re: Terminating current task

Post by glauxosdever »

Hi,


It seems that not having a worker thread is much more complex and involves doing tricks that are not straightforward for code readers, though it would be probably easier to achieve it if my OS was written in assembly for the whole part.

Maybe I will reconsider not liking worker threads (though I will definitely think about it).


Regards,
glauxosdever
MollenOS
Member
Member
Posts: 202
Joined: Wed Oct 26, 2011 12:00 pm

Re: Terminating current task

Post by MollenOS »

So how I solved thread termination;

1. Thread calls ThreadingExit
2. Thread marks itself with a flag that indicates that it's done and needs cleanup
3. Thread yields control instantly after this
4. Scheduler sees the current thread for the current cpu is done, removes it from thread list, adds it to cleanup list and signals to the garbage collector thread (which sleeps when np cleaning is needed) that new cleanup is possible.
5. Scheduler gets a new thread

To be honest you only need one worker thread, and that worker thread can be kept off scheduling when no cleaning is needed, thus making it pretty efficient anyway.
glauxosdever
Member
Member
Posts: 501
Joined: Wed Jun 17, 2015 9:40 am
Libera.chat IRC: glauxosdever
Location: Athens, Greece

Re: Terminating current task

Post by glauxosdever »

Hi,


This looks as a more convenient way, although I will let the scheduler clean up the thread information when it sees that "done" is set to true. I might change it later.

Thank you all for your ideas!


Regards,
glauxosdever
MollenOS
Member
Member
Posts: 202
Joined: Wed Oct 26, 2011 12:00 pm

Re: Terminating current task

Post by MollenOS »

That is not possible, the threads stack is in use even in the scheduler untill the scheduler has actually switched tasks. You can't clean the thread untill you have switched away from its context
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: Terminating current task

Post by Rusky »

Unix leaves old threads as "zombies" until their parent threads call wait() on them, at which point their resources can be freed from there. This gives parents a chance to retrieve the child's exit status, etc.

If you don't want to leave anything laying around for parent threads to pick up with a wait()-like call, you can just switch to the next thread before freeing the old one's resources.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Terminating current task

Post by xenos »

Another option (the one I am using in my kernel) is that threads don't have their own kernel stacks. In this approach, kernel stacks are per CPU, not per thread. That means that interrupts and syscall entries must be designed differently, as the thread's data such as register values is not saved on the kernel stack, but in some data structure belonging to the thread. But it makes it easier to terminate a thread. Since the kernel stack is per CPU, it is never freed, and just stays in use while being in kernel mode. The structures holding the thread's data can simply be freed, because they are not used by anything while being in kernel mode (they are only written on kernel entry and read on exit, to restore the state of the thread chosen to run).
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
Post Reply