| > Other threads can have pointers into that thread's stack, so the stack must not be reclaimed until they let go. > For instance, a tread allocates a reply box on the stack and calls some message passing API to send a message, whereby it registers the reply box. That API now has a pointer into the thread's stack. Suppose the thread dies before unregistering the reply box. If that can happen, the stack has to stick around. OMG, can such thing really happen and be correct in some language? The thing is, the stack is most often used as method-local storage for that method's variables and objects that are not escaping its scope and thus can be allocated on stack instead of the heap. Basically, what happens with stack in a language like C or Java when in thread T some method A calls another method B is the following: T.stack.push(return address)
T.stack.allocateFrame(B)
Then, when B has done everything it wanted to, it clears its frame from the stack and returns by saved address into A. Similarly, when an exception is thrown, it crawls up the stack frame-by-frame clearing them out until it finds the handler.With that general scheme in mind, I see some contradictions in your example: 1. How exactly can a thread correctly die in such a way that frame of method that allocated the reply box on-stack is not cleaned up from it first? 2. Why the method even allocated shared data structure on its own stack (which it must clear on returning to caller) and not in heap? 3. If it did so because it blocks while waiting for the response to appear in stack-allocated placeholder, then why would anyone consider thread which is actively waiting for something dead and try to reclaim its stack? |
The thread could die incorrectly in that way.
> Why the method even allocated shared data structure on its own stack
Done for efficiency or when it's not desirable to have to check and recover from a failure to allocate such a structure. E.g. DECLARE_WAITQUEUE macro in Linux kernel:
https://elixir.bootlin.com/linux/v4.3/source/include/linux/w...
How blocking is implemented in Linux is that tasks declare wait queue nodes on the stack, register these into a queue, then change themselves to a sleep state and call the scheduler.
> why would anyone consider thread which is actively waiting for something dead and try to reclaim its stack?
What reclaims the stack isn't that "anyone"; it's garbage collection. It's plausible like this. Suppose the messaging API is responsible for dequeuing the waiter. The messaging API walks the queue, depositing replies into the reply boxes and dequeueing (without caring whether the associated threads are alive or dead).
When it dequeues the dead thread's reply box, that stack then becomes unreachable. Now it is eligible for reclamation.