lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

David Given wrote:
> There are some very handy but little-known functions called 
> setcontext()/getcontext()/makecontext()/swapcontext() that make
> implementing coroutines a doddle.

Yes, I know them.  Unfortunately, they are not widely available.
I.e. not on my system and afaik not under Windows either.

The major downside I see with the ucontext functions is that they
perform system calls during swapcontext (to change signal masks).
Performance goes down the drain...

The setup_jmpbuf function I posted earlier is the absolutely
minimal code[1] required to implement coroutines or userspace
threads.  I.e. an implementation of the ucontext functions with
all features required for Lua comes down to this:

| typedef jmp_buf mcontext_t;  // our mcontext is a jmp_buf
| // setcontext/getcontext are not really needed but
| // to show their implementation:
| #define setcontext(uc) longjmp((uc)->uc_mcontext, 1)
| #define getcontext(uc) (setjmp((uc)->uc_mcontext), 0)
| int swapcontext(ucontext_t *ouc, ucontext_t *nuc)
| {
|     if (setjmp(ouc->uc_mcontext) == 0)
|         longjmp(nuc->uc_mcontext, 1);
|     return 0;
| }
| void makecontext(ucontext_t *uc, void (*func)(), int argc, ...)
| {
|     assert(argc == 0);  // makecontext only allows int args
|                         // which makes them useless for Lua.
|     setup_jmpbuf(uc->uc_mcontext, func,
|                  uc->uc_stack.ss_sp,
|                  uc->uc_stack.ss_sp + uc->uc_stack.ss_size)
| }

Maybe one could use the ucontext functions to implement the
C-level coroutines for Lua.  If there is no native implement-
ation or it is too slow because of the sigmask stuff one could
fall back to the trivial version based on setup_jmpbuf.

Ciao, ET.

[1] I.e. the implementation for x86-linux libc5 (my system):

| void
| setup_jmpbuf(jmp_buf buf, void (*func)(void), void *stack, void *stackend)
| {
|     setjmp(buf);  // initialize jmp_buf with some sane values
|     buf->__sp = stackend;
|     buf->__pc = func;
| }