Why does the implementation of user level thread (fiber) require a new allocated stack per fiber?

574 views Asked by At

In C fibers can be coded using setjmp() and longjmp() to implement context switches at user level.
As described in evanjones.ca and Portable Multithreading(pdf) it is also required that each fiber has a newly allocated stack.
Since a fiber lives in a thread context, when it is invoked will have automatically a stack frame associated to it, so why is it required this new allocated stack? : when a fiber wants to switch to another one, the following approach could be used :

 cpu_context[N] :global array where the i-th entry is the cpu context(jmp_buffer) of the i-th fiber 

fiber_ith :
   [...]
   if ( setjmp(cpu_context[i]) == 0 ){
        longjmp(cpu_context[j])
   }
   [...]

The necessity of a new stack is due to the fact that as written here, it is not possible to use longjmp()to go back to a fiber execution whose stack frame is not anymore valid from the instant that fiber calls longjmp() ?

EDIT : these fibers must be non preemtive and can voluntary switch from one fiber to another one

2

There are 2 answers

5
David Schwartz On BEST ANSWER

Suppose a fiber has a function that calls another function that calls another function that then causes that fiber to be switched for another fiber. When we resume this fiber, we need to ensure that all local variables are back the way they were when the fiber switched and we need to ensure that returning from this function goes back to the calling function. Thus the following rules emerge:

  1. While a fiber is running, it can change its stack.
  2. When a fiber is resumed, the stack must be back where it was when the fiber was switched.

It immediately follows from these two rules that every fiber must have its own stack.

3
Eric Postpischil On

First, threads are not intended to manually control their own dispatching. That is, it is not intended that a thread will decide to end or suspend its execution and start another thread. Rather, threads are available to run simultaneously, and the system may run several threads on different physical or virtual processors simultaneously or may start and stop threads so they share available time on a processor.

Because threads may run simultaneously, they must have separate stacks. Each thread will be altering and using its own stack possibly at the same time as other threads are altering and using theirs. These stacks must be separate to avoid conflicts.

Second, setjmp and longjmp are not intended for jumping to arbitrary points in thread state. A program may use longjmp only to return to a previous setjmp in its current call stack, in the same thread. You could not, for example, do some work, remember state A with setjmp, do some more work, remember state B with setjmp, then longjmp to state A, and later longjmp to state B. After the longjmp to A, B is no longer available—whatever was saved for it by setjmp is no longer valid.