Hacker News new | past | comments | ask | show | jobs | submit login

> Windows has the CreateFiber() API that creates "fibers", which act like threads, but use "cooperative multitasking". For POSIX, using a combination of setjmp(), longjmp(), sigaltstack(), and some signal (e.g. SIGUSR2) will provide coroutine support though it is "pretty awful". While it is "horrible", it does actually work.

I do this, and it works perfectly well. Here's a full implementation demonstrating this approach: https://gitlab.com/higan/higan/blob/master/libco/sjlj.c

It's been successfully used on x86, amd64, ppc32, ppc64, mips, arm and sparc in several projects.

However, it still has a good bit of overhead. But you can implement this concept absolutely trivially on any platform for maximum speed. All you need to do is save the non-volatile registers, swap the stack pointer, restore the non-volatile registers from the swapped-in stack, and return from the function. If you haven't realized, one function can reciprocally save and restore these contexts. Here's an x86 implementation, for example:

    co_swap: ;ecx = new thread, edx = old thread
    mov [edx],esp
    mov esp,[ecx]
    pop eax  ;faster than ret (CPU begins caching new opcodes here)
    mov [edx+4],ebp  ;much faster than push/pop on AMD CPUs
    mov [edx+8],esi
    mov [edx+12],edi
    mov [edx+16],ebx
    mov ebp,[ecx+4]
    mov esi,[ecx+8]
    mov edi,[ecx+12]
    mov ebx,[ecx+16]
    jmp eax
This turns out to be several times faster than abusing setjmp/longjmp.

I turned this into the simplest possible library called libco (public domain or ISC, whichever you prefer.) The entire API is four functions, taking 0-2 arguments each: create, delete, active, switch.

The work's already been done for several processors. Plus there's backends for the setjmp trick, Windows Fibers and even the slow-as-snails makecontext.

If Python does decide to go this route, I'd certainly appreciate if the devs could be directed at libco for consideration. It'd save them a lot of trouble making these, and it'd get us some much-needed notoriety so that we could produce more backends and finally have a definitive cothreading library.




FYI, greenlet already includes stack switching code, so it would make more sense to use that.

https://github.com/python-greenlet/greenlet/tree/master/plat...


Ah, neat. Looks like they have even more backends than me. I've never even heard of S390 before. Okay, nevermind then. Thanks for the link.

That's the downside of these libraries, there's as many libraries as there are people wanting to do this. I've been hoping for a standard to emerge, even if it's not mine. This looks a bit too tied into Python to be general purpose, though.


libco seems pretty interesting. Do you alswo have some code to show which uses it? Just to get an idea of what you use it for typically. Have you used it with Python alreday?


The code that uses it is pretty complex (go up two folders in my gitlab link for that), so here's a minimal example of the full API:

  cothread_t a, b;  //cothread_t is a typedef to void*
  int main() {
    a = co_active();  //get a handle to the main thread
    b = co_create(entrypoint, stacksize_in_bytes);
    printf("a");
    co_switch(b);
    printf("c");
    co_delete(b);  //no need to delete a
  }
  void entrypoint() {
    printf("b");
    co_switch(a);
  }
  //output: "abc"
We've only been using it in emulators so far. It's in MESS, higan, twoMbit and a few others.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: