The secret of stackless coroutines is that they can suspend themselves only from the top-level function. For all other functions their data is allocated on the callee stack, so all functions called from the coroutine must finish before suspending the coroutine. All the data that coroutine needs to preserve its state is allocated dynamically on the heap. This usually takes a couple of local variables and arguments, which is far smaller in size than the whole stack allocated in advance.
кстати, нашёл кусок в осуждении. дишние файберы *можно* переносить в другую нить, но только, если на момент переноса они не активны. в приниципе, логично
For me language being TLS by default is enough to not even try this madness. If we allow moves a typical fiber will see different "globals" depending on where it is scheduled next.
For instance, if a thread local connection is used (inside of some pool presumably) then:
Socket socket;
first_part = socket.read(...); // assume this yields second_part = socket.read(...); // then this may use different socket