Live data from Hacker News

Coroutines in C (2000)

chiark.greenend.org.uk

41–50 of 61 posts

Re: Coroutines in C (2000)

#41
post #30

Earlier quoted context omitted.

Back in the day, we had multiple windows on the screen at one time, so this wasn't a problem. I think it was Windows which defaulted to full-screen, and led to the plague of sites assuming that the browser would be full-width on a landscape screen, but I could be wrong. Although I love using a tiling window manager now, I kinda miss my old System 8 Macintosh setup, with Netscape open in one window & Think C (or was i…

On a Mac, Spectacle gets you pretty much there. I haven't found something similar for Windows, but I'm sure there is one.

I'm a very happy user of Amethyst, a tiling WM https://github.com/ianyh/Amethyst Makes OSX actually usable.

Re: Coroutines in C (2000)

#42
post #27

I guess one of the applications of Coroutines could be WebAssembly. When you run WebAssembly on a website which needs 100% of the CPU for more than a few ms, you have to use the "setTimeout(fn, 0)" trick to prevent the "this website stopped responding" message. That means you have to store the current state at some point and continue in the function fn (after waiting 0 ms). Languages which support coroutines out of t…

Aren't Web Workers (which can run WASM) supposed to fill that role?

The web worker helps a little bit. You can send data to the UI thread whenever you want. However on the receiving side you have the same problem. The web worker only receives data when it is idle. For example if you want to send key presses to the web worker, the web worker has to idle. The utilization of the CPU to 100% with simultaneous responsiveness is quite difficult to implement. Actually you have to play an endless game of message ping pong so that the message queue is always filled.

Re: Coroutines in C (2000)

#43
post #7

I really like that trick. It's very powerful. But I wonder what the difference is between this and protothreads?

Protothreads is a library implementation of this trick. In fact, the protothreads creator even references the linked site in their explanation of protothreads (very last paragraph) [1].

[1] http://dunkels.com/adam/pt/expansion.html

Re: Coroutines in C (2000)

#44
post #39
post #26

Earlier quoted context omitted.

The only issue of these websites is the width: using the full width of the screen is just too much for reading. If you add {max-width: 60em; margin: auto;} to the body tag it looks much better.

Not too wide for my browser windows, which are a bit under 50% of screen width.

Likewise I would say not enough people put their monitors in portrait. It's amazing for coding.

Re: Coroutines in C (2000)

#45
post #39

Earlier quoted context omitted.

Not too wide for my browser windows, which are a bit under 50% of screen width.

Likewise I would say not enough people put their monitors in portrait. It's amazing for coding.

I like landscape — I can comfortably fit 3 80-column code tabs with linter columns (vim :vsplit) in landscape mode, or a vertical term (with 2 80-col code tabs, uncomfortably) and browser side by side.

And it also works when I want to play games, or watch anything recorded in landscape, which is most media.

Re: Coroutines in C (2000)

#46
As an OOP dev this kind of horrifies me, even though it works okay (though it's surely not thread-safe?)

Nevertheless, even in C, I'd find it conceptually simpler to understand if the functions were written as pure functions, returning a tuple with (c, state) and passing the state back into the caller. Using non-idiomatic tricks and macros in this way is harder to read and understand.

Re: Coroutines in C (2000)

#48

As an OOP dev this kind of horrifies me, even though it works okay (though it's surely not thread-safe?) Nevertheless, even in C, I'd find it conceptually simpler to understand if the functions were written as pure functions, returning a tuple with (c, state) and passing the state back into the caller. Using non-idiomatic tricks and macros in this way is harder to read and understand.

Here's a POSIX compliant portable getopt() routine I wrote which uses this style. Is this hard to read? Note that it's several times shorter than every other implementation I've ever seen, and if I do say so myself I think it's eminently readable.

  static int
  u_getopt_r(int argc, char *const argv[], const char *shortopts, struct u_getopt_r *K)
  {
    K->optarg = NULL;
    K->optopt = 0;
  
    GETOPT_ENTER;
  
    while (K->optind cp = argv[K->optind];
  
      if (!K->cp || *(K->cp) != '-' || !strcmp(K->cp, "-")) {
        break;
      } else if (!strcmp(K->cp, "--")) {
        K->optind++;
        break;
      }
  
      for (;;) {
        char *shortopt;
  
        if (!(K->optopt = *++K->cp)) {
          K->optind++;
          break;
        } else if (!(shortopt = strchr(shortopts, K->optopt))) {
          getopt_err(argc, argv, shortopts, K, "illegal option -- %c\n", K->optopt);
          GETOPT_YIELD('?');
        } else if (shortopt[1] != ':') {
          GETOPT_YIELD(K->optopt);
        } else if (K->cp[1]) {
          K->optarg = &K->cp[1];
          K->optind++;
          GETOPT_YIELD(K->optopt);
          break;
        } else if (K->optind + 1 optarg = argv[K->optind + 1];
          K->optind += 2;
          GETOPT_YIELD(K->optopt);
          break;
        } else {
          getopt_err(argc, argv, shortopts, K, "option requires an argument -- %c\n", K->optopt);
          K->optind++;
          GETOPT_YIELD((*shortopts == ':')? ':' : '?');
          break;
        }
      }
    }
  
    GETOPT_LEAVE;
  
    return -1;
  }
  
Here's macro magic, the complexity of which is more than made up for by the readability of the core code:

  #define GETOPT_ENTER \
    do { \
    static const int pc0 = __LINE__; \
    switch (pc0 + K->pc) { \
    case __LINE__: (void)0
  
  #define GETOPT_SAVE_AND_DO(do_statement) \
    do { \
      K->pc = __LINE__ - pc0; \
      do_statement; \
      case __LINE__: (void)0; \
    } while (0)
  
  #define GETOPT_YIELD(rv) \
    GETOPT_SAVE_AND_DO(return (rv))
  
  #define GETOPT_LEAVE \
    GETOPT_SAVE_AND_DO(break); \
    } \
    } while (0)

Re: Coroutines in C (2000)

#49

Earlier quoted context omitted.

For those wondering how it works, libdill keeps track of context between function calls and does some clever stack modification in assembly.

I wonder if it would work from Rust. I was looking at something minimal like this.

I haven't used it at all, but doesn't Rust have experimental support for coroutines?

https://github.com/rust-lang/rust/issues/43122

Re: Coroutines in C (2000)

#50

Has anyone used these to write interrupt service routines? Seems like there's an opportunity here. You can take your existing synchronous code and not have to rewrite it into something like continuation-passing style. This is a source of a lot of bugs.

I have, it's not pretty either: https://github.com/nraynaud/webgcode/blob/gh-pages/interpola...

i have done cps plumbing in C with poor mans closures for the entire interrupt path, and given its natural event-like nature, it really all comes out pretty nice.
Post reply on HN