Process/Thread object lifetime

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
proxy

Process/Thread object lifetime

Post by proxy »

ok, so I have been trying to figure out how I want to do this, and just can't figure out a scheme which i like.

processes/threads are handled in the following way:

a Process is an address space which may own 0 or more threads at any point in ttime, upon successful construction, it will register itself with the "ProcessManager" which is really just a glorified list of Process * objects and some lookup/managment routines.

a Thread is a unit of execution and must have a single owner (the kernel itself has a "KernelProcess" which has no user mode pages). Threads have both "joinable and non-joinable" options.

So my question is this: given that we should keep a both threads and processes around post death for the goal of being able to get the status and potentially "wait for termination". When should the objects be officially destroyed.

clearly a non-joinable thread should be destroyed upon termination, since there is no way to wait for it to terminate and thus get it's status code. but what about joinable, how long should it be around?

Here's my current idea: a joinable thread must be joined at some point and can only be joined by one other thread (you can't have 3 threads waiting on 1). Once thread A successfully waits for B to terminate, B is cleaned up since noone else may join on it. This does leave the issue of the main thread of a process (if there is one) when is it destroyed? upon Process::destroy() call?

Then there is the issue of when do I destroy a Process object? I do plan on enforcing the idea that a thread from process A cannot wait for a thread in process B (it could wait for process A to complete though). So I could safely destroy all threads in a process when it is officially destroyed...but when is this? not when the "exit_process(int);" syscall is executed, because I still at the very least need the basics of the process object in order to get it's information. I suppose exit_process(int) could destroy the address space itself (reclaim pages) and destroy all child threads..but that still leaves the Process object still lying around...do I just leave it until I NEED the memory/pid?

what do you guys do?

proxy
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Process/Thread object lifetime

Post by Brendan »

Hi,

A process has no threads while it's being created, but immediately after process creation a thread is spawned for it (a process can't "execute" without a thread).

The process itself is never terminated explictly. Instead, it's only ever terminated when the number of threads using it reaches zero. Basically, when the last thread is terminated the process itself is also terminated.

This means that (for me) the "exit_process(int);" syscall only terminates one thread (the caller) and sends a "shutdown" message to any other threads in the same process. When the other threads receive this shutdown message they terminate themselves (although there's also a kernel-enforced time limit - they are "force terminated" if they aren't quick enough to either terminate or ask for more time).

When a thread is terminated the OS frees any resources it can (memory, file handles, I/O ports, IRQs, etc), leaving kernel structures that describe the thread and nothing else. If it's the last thread in the process then the process's resources are also freed (leaving the kernel structure for the process). After freeing resources the thread is marked as "terminated" and the threadID is put on a "terminated FIFO queue".

Then messages ("obituaries" :) ) are sent out to who-ever requested them. These messages include the thread ID, it's exit value (from the C "exit()" function) and the reason for it's termination (crashed, exit(), killed, etc).

After a time delay (30 seconds) the threadID reaches the top of the "terminated FIFO queue" and kernel structures are freed. At this point the thread (and the process, if it was the last thread) officially doesn't exist. This time delay just prevents the same threadID from being re-used before other software knows that the thread was terminated. Without this delay, if some software is sending data to a thread, the thread is terminated and another thread with the same threadID is created, then the software sending data may not know that it's not talking to the original/terminated thread and continue sending data.

A thread from process A can wait for a thread in process B to terminate just by asking to receive the "obituary" message. This is important for client/server software (for example, a server might listen for all obituaries and cancel any requests that it's performing for terminated threads. This isn't a "blocking" thing though (everything uses aynchronous messaging) - the thread from process A would wait for any message to be received (regardless of whether it's an obituary or not), which is also (IMHO) important for client/server software (as a single "server thread" may be watching for hundreds of "obituaries" while handling hundreds of normal requests).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
proxy

Re:Process/Thread object lifetime

Post by proxy »

yea, when last thread dies is a good thought, but here's my problem. In my design, sometimes a process can have 0 threads. Here's an example:

my VideoDriver_VESA code creates a Process object once, maps in some code/data to do an interrupt with the intent of being executed by a V8086 mode thread. Whenever i need to fetch the list of video modes or change modes, I just add a new thread to that process with the appropriate initial register state. So most of the time, this process has no threads at all. I suppose I could special case this one, but I really try to avoid special casing things in general.

proxy
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Process/Thread object lifetime

Post by Brendan »

Hi,
proxy wrote:yea, when last thread dies is a good thought, but here's my problem. In my design, sometimes a process can have 0 threads. Here's an example:
I guess you could have a flag somewhere to indicate that the process should never be terminated by "exit_thread(int);" (but should still be terminated by "exit_process(int);").
proxy wrote:my VideoDriver_VESA code creates a Process object once, maps in some code/data to do an interrupt with the intent of being executed by a V8086 mode thread. Whenever i need to fetch the list of video modes or change modes, I just add a new thread to that process with the appropriate initial register state. So most of the time, this process has no threads at all. I suppose I could special case this one, but I really try to avoid special casing things in general.
For this example, why are you spawning and terminating the thread instead of just giving it no CPU time until it's needed again (and saving yourself the cost of spawning/terminating)?

For my design, all device drivers are CPL=3 processes that behave like "servers". For e.g. the video driver would be waiting for a message, then it'd receive a message saying "set a video mode" or "get the mode list" and would perform the request, return a status message and then wait for another message.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
proxy

Re:Process/Thread object lifetime

Post by proxy »

Good point aout the thread spawning, I suppose I just did that out of convinience. It was simpler to write:

(new V86Thread(owner, thread, args)->wait();

then to have a single threads which loops and worry about blocking it and unblocking it as needed. I would likely change it in the future.

So I suppose I could alter my model to destroy any process which has it's last thread die. But I'm kinda on the fence about it.

proxy
Post Reply