Live data from Hacker News

Hacking Coroutines into C

wiomoc.de

21–30 of 46 posts

Re: Hacking Coroutines into C

#21
[State machines] lacked a linear flow

That's because you need a state machine when your control flow is not linear. They are represented by graphs, remember? This is actually a case where using gotos might be clearer. Although not drastically better because the main problem is that written source code is linear by nature. A graph described by a dedicated DSL such as GraphViz has the same problem, although at least you can visualize the result.

But control flow is only one term of the equation, the other being concurrency. One typically has more than one state machine running; sometimes one use state machines that are actually essentially linear because of that. Cooperative multitasking. I would question trying to solve these two problems, non-linearity and concurrency. Sometimes when you try too hard to kill two birds with one stone you end up with one dead bird and a broken window.

One lecturer of the conference announced earlier [1] made that point too that visualization helps a lot, and that reminded me of Pharo's inspection tools [2]. Seeing what's going on under the hood is more important that one usually thinks.

One issue with state machines is that they are hardly modular: adding a state or decomposing a state into multiple states is more work than one would like it to be. It is the inverse problem of visualization: what you draw is what you code. A good tool for that would let the user connect nodes with arrows and assign code to nodes and/or arrows; it would translate this into some textual intermediate language to play nice with Git, and a compiler would transform it to C code for integration in the build system.

[1] https://bettersoftwareconference.com/ [2] https://pharo.org/features

Re: Hacking Coroutines into C

#22
A colleague of mine did this much more elegantly by manually updating the stack and jmping. This was a couple of decades ago and afaik the code is still in use in supercomputing centres today.

Re: Hacking Coroutines into C

#23
post #3

The intent here is nice. I historically hate state machines for sequential executioners. To me they make sense in FPGA/ASIC/circuits. In software, they just get so complicated. I've even seen state managers managing an abstracted state machine implementing a custom device to do what's ultimately very sequential work. It's my same argument that there should be no maximum number of lines to a function. Sometimes, you j…

> there's no point in making a function that's only called in one place. There's nothing wrong with doing that if it helps make your code clearer. The compiler's optimizer will inline it when appropriate so there's no runtime overhead either.

Not only that, the compiler's optimizer might actually do a better job if you split up a big function. Because the smaller functions have less register pressure.

Re: Hacking Coroutines into C

#24
post #15

Earlier quoted context omitted.

I have used this approach, with an almost similar looking define for YIELD myself. If there is just one instance of a co-routine, which is often the case for embedded software, one could also make use of static variables inside the function. This also makes the code slightly faster. You need some logic, if for example two co-routines need to access a shared peripheral, such as I2C. Than you might also need to impleme…

Yes, 100%. State transitions are "goto" by another name. State machines have their place but tend to be write-only (hard to read and modify) so are ideally small and few. Worked at a place that drank Miro Samek's "Practical Statecharts in C/C++" kool-aid... caused lots of problems. So instead I use this pattern everywhere that I can linearize control flow. And if I need a state machine with this pattern I can just us…

Worked at a place that drank hiearchical state machines kool-aid. Yeah.

https://en.wikipedia.org/wiki/UML_state_machine#Hierarchical...

Re: Hacking Coroutines into C

#25

My favorite trick in C is a light-weight Protothreads implemented in-place without dependencies. Looks something like this for a hypothetical blinky coroutine: typedef struct blinky_state { size_t pc; uint64_t timer; ... variables that need to live across YIELDs ... } blinky_state_t; blinky_state_t blinky_state; #define YIELD() s->pc = __LINE__; return; case __LINE__:; void blinky(void) { blinky_state_t *s = &blinky_…

In `proto_activities` this blinking would look like this:

  pa_activity (Blinker, pa_ctx_tm(), uint32_t onMs, uint32_t offMs) {
    pa_repeat {
      turn_on_LED();
      pa_delay_ms (onMs);
  
      turn_off_LED();
      pa_delay_ms (offMs);
    }
  } pa_end
Here the activity definition automatically creates the structure to hold the pc, timer and other variables which would outlast a single tick.

Re: Hacking Coroutines into C

#28
post #11
post #3

The intent here is nice. I historically hate state machines for sequential executioners. To me they make sense in FPGA/ASIC/circuits. In software, they just get so complicated. I've even seen state managers managing an abstracted state machine implementing a custom device to do what's ultimately very sequential work. It's my same argument that there should be no maximum number of lines to a function. Sometimes, you j…

> I comment the code blocks, maybe with steps/parts, but there's no point in making a function that's only called in one place. I encourage junior developers that get into this habit (getting worse now, with LLMs) to convert the comment into a function name and add the block as a function, thinking pretty carefully about its function signature. If you have a `typedef struct state` that gets passed around, great. The…

I think for me, and it sounds like for this author, the context lost by that abstraction makes it harder to review. In my experience it's easier for me to understand a small block of code, but it's harder to understand how it impacts the system when it's out of context.

For example:

x++;

A very easy piece of code to understand. But who wants x, and what values could they expect? Why do we ++ and under what conditions?

Those effects, again just for me your mileage may vary, tend to get much harder to understand.

Re: Hacking Coroutines into C

#29
post #11
post #3

The intent here is nice. I historically hate state machines for sequential executioners. To me they make sense in FPGA/ASIC/circuits. In software, they just get so complicated. I've even seen state managers managing an abstracted state machine implementing a custom device to do what's ultimately very sequential work. It's my same argument that there should be no maximum number of lines to a function. Sometimes, you j…

> I comment the code blocks, maybe with steps/parts, but there's no point in making a function that's only called in one place. I encourage junior developers that get into this habit (getting worse now, with LLMs) to convert the comment into a function name and add the block as a function, thinking pretty carefully about its function signature. If you have a `typedef struct state` that gets passed around, great. The…

[deleted]

Re: Hacking Coroutines into C

#30
post #20
post #17

Earlier quoted context omitted.

This isn't using setjmp/longjmp It's using Simon Tatham's method based on Duff's device ( https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html )

Sure, I guess I just wanted to point out that regardless of method, people have been building these sorts of facilities in C for a very long time. It doesn’t lessen the achievement of course, but it amuses me an in “everything old is new again” kinda way.

"everything old is new again" is so true. I see it across IT all the time, heh.
Post reply on HN