I think ucontext is an excellent starting point for a general implementation. You just abstract it with a thin veneer and adopt faster implementations as needed where applicable.
I would love to be wrong though...
[1] https://github.com/spc476/C-Coroutines
[2] In my not-so humble opinion, using signals at all is not wise.
xchg %rsp, %rdx
leaq 1f(%rip), %rax
jmp *%rsi
1:It it expect the target stack ptr/ip pair to be in rdx/rsi and saves the current stack ptr and ip in rdx/rax. It does not save any register and uses gcc asm clobbers to instruct the compiler to save any other register.
Code at [1]. The comments about hacks and ub is because I'm trying to transparently propagate exceptions across coroutines, otherwise the stack switching us fairly robust (although GCC specific).
[1] https://github.com/gpderetta/delimited/blob/master/delimited...