I would like to know whether Cgo implementing functions are allowed to arbitrarily manipulate the stack pointer. The motivation for this is to allow the use of coroutines on the C side of the call. For example, coroutines may be created that utilize additional stacks (that may be themselves stack-allocated or statically allocated) and computation may be carried out by communicating coroutines.
However, my concern is that the coroutines implementation will necessarily need to change the stack pointer of the thread from coroutine to coroutine (and away from the stack originally associated with the thread). There is the possibility that the Go runtime inspects the stack pointer, for example, during the preemption step before garbage collection. It is not clear how the preemption interrupt handler would know it is still associated with the original thread if the stack pointer has changed to some other arbitrary location that the Go runtime does not know about.
Does this, or any other part of the Go runtime, care about the stack pointer value?
FWIW, the code will never call back into Go
from C
.
By experiment, the runtime for the mainstream Go implementation seems to work with coroutines. My initial attempt had a memory corruption bug on the C side causing eventual deadlocks of the Go runtime, but it now appears to work.
Regarding the preemption (and signal handlers in general), there is an explanatory comment in the source code indicating that TLS (thread-local storage) is used to handle this. So as long as the C code does not engage in saving and restoring TLS it should be fine:
IOW, it will work with lightweight coroutine implementations that propagate TLS from the initial thread into all coroutines. Preemption may not work properly if TLS is not propagated from the initial thread, or if it is fully managed whereby each coroutine has its own TLS.