frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

Open in hackernews

Hacking Coroutines into C

https://wiomoc.de/misc/posts/hacking_coroutines_into_c.html
70•jmillikin•5h ago

Comments

mikepurvis•5h ago
FreeRTOS can also be used with a cooperative scheduler: https://www.freertos.org/Why-FreeRTOS/Features-and-demos/RAM...

That said, if I was stuck rolling this myself, I think I’d prefer to try to do it with “real” codegen than macros. If nothing else it would give the ability to do things like blocks and correctness checks, and you’d get much more readable resulting source when it came to stepping through it with a debugger.

Neywiny•5h ago
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 just need to do a lot of work. 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.

But anything is better than one person I met who somehow was programming without knowing how to define their own functions. Gross

TechDebtDevin•4h ago
I actually write a lot of Go in state machine like patterns. My state types files would make you think im schizophrenic. I just finished up a project this week that was 10k lines of comments in 18k loc. Noone else has to read it tho, they actually probably appreciate it if they did.
throwaway81523•2h ago
> 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.

duped•1h ago
> 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 reason for splitting up this code is so that the person writing it doesn't fuck up, the input/output is expressed as types and validated before they push it. It's easy for me to review, because I can understand small chunks of code better than big chunks, and logically divides up the high level architecture from the actual implementation so I can avoid reviewing the latter if I find trouble with the former. It's also good as a workflow, where you can pair to write out the high level flow and then split off to work on implementation internally. And most importantly, it makes it possible to test the code.

I have had this discussion with many grumbly developers that think of the above as a "skill issue." I don't really want to work with those people, because their code sucks.

throwaway81523•5h ago
As the article acknowledges at the end, this is sort of like protothreads which has been around for ages. The article's CSS was so awful that I didn't read anything except the last paragraph, which seemed to tell me what I wanted to know.
mananaysiempre•4h ago
Right, this is more or less this blog author’s riff on (PuTTY author) Simon Tatham’s old page on coroutines using switch[1], which itself indicates that Tom Duff thought of this (which makes sense, it’s only a half-step away from Duff’s device) and described it as “revolting”. So in this sense the idea predates the standardization of C.

[1] https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

hecanjog•3h ago
> The article's CSS was so awful

Small text sizes? What is the problem for you?

shakna•3h ago
Whilst I wouldn't call it "awful", the spacing between the lines isn't helping any.
userbinator•2h ago
Of course, the project didn’t allow us to use an RTOS.

That tends to just make the project eventually implement an approximation of one... as what appears to have happened here.

How I'd solve the given problem is by using the PWM peripheral (or timer interrupts if no PWM peripheral exists) and pin change interrupts, with the CPU halted nearly 100% of the time. I suspect that approach is even simpler than what's shown here.

adinisom•1h ago
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_state;
    uint64_t now = get_ticks();
    
    switch(s->pc) {
      while(true) {
        turn_on_LED();
        s->timer = now;
        while( now - s->timer < 1000 ) { YIELD(); }
        
        turn_off_LED();
        s->timer = now;
        while( now - s->timer < 1000 ) { YIELD(); }
      }
    }
  }
  #undef YIELD
Can, of course, abstract the delay code into it's own coroutine.

Your company is probably using hardware containing code I've written like this.

What's especially nice that I miss in other languages with async/await is ability to mix declarative and procedural code. Code you write before the switch(s->pc) statement gets run on every call to the function. Can put code you want to be declarative, like updating "now" in the code above, or if I have streaming code it's a great place to copy data.

csmantle•1h ago
Yeah. Protothreads (with PT_TIMER extensions) is one of the classics libraries, and also was used in my own early embedded days. I was totally fascinated by its turning ergonomic function-like macros into state machines back then.
fjfaase•52m ago
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 implement a queue. Last year, I worked a bit on a tiny cooperative polling OS, including a transpiler. I did not finish the project, because it was considered too advanced for the project I wanted to use it for. Instead old fashion state machines documented with flow-charts were required. Because everyone can read those, is the argument. I feel that the implementation of state machines is error prone, because it is basically implementing goto statements where the state is like the label. Nasty bugs are easily introduced if you forget a break statement at the right place is my experience.

adinisom•42m ago
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.

Agreed re: making the state a static variable inside the function. Great for simple coroutines. I made it a pointer in the example for two reasons:

- Demonstrates access to the state variables very little visual noise... "s->"

- For sub-coroutines that can be called from multiple places such as "delay" you make the state variable the first argument. The caller's state contains the sub-coroutine's state and the caller passes it to the sub-coroutine. The top level coroutine's state ends up becoming "the stack" allocated at compile-time.

Nursie•1h ago
Cooperative multithreading via setjmp and longjmp has been around in C since the 80s at least.

I’m not sure this is so much hacking as an accepted technique from the old-old days which has somewhat fallen out of favour, especially as C is falling a little outside of the mainstream these days.

Perhaps it’s almost becoming lost knowledge :)

ajb•2m ago
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)

Bypassing Google's big anti-adblock update

https://0x44.xyz/blog/web-request-blocking/
584•deryilz•11h ago•502 comments

Switching to Claude Code and VSCode Inside Docker

https://timsh.org/claude-inside-docker/
71•timsh•1d ago•25 comments

Hacking Coroutines into C

https://wiomoc.de/misc/posts/hacking_coroutines_into_c.html
70•jmillikin•5h ago•16 comments

Kimi k2 largest open source SOTA model?

https://github.com/MoonshotAI/Kimi-K2
304•ConteMascetti71•13h ago•75 comments

MacPaint Art from the Mid-80s Still Looks Great Today

https://blog.decryption.net.au/posts/macpaint.html
843•decryption•21h ago•178 comments

Zig's New Async I/O

https://kristoff.it/blog/zig-new-async-io/
117•afirium•7h ago•76 comments

Chrome's hidden X-Browser-Validation header reverse engineered

https://github.com/dsekz/chrome-x-browser-validation-header
132•dsekz•2d ago•28 comments

Nuclear Explosion for Carbon Sequestration

https://arxiv.org/abs/2501.06623
19•energy123•2h ago•10 comments

Aeron: Efficient reliable UDP unicast, UDP multicast, and IPC message transport

https://github.com/aeron-io/aeron
8•todsacerdoti•10h ago•1 comments

Edward Burtynsky's monumental chronicle of the human impact on the planet

https://www.newyorker.com/culture/photo-booth/earths-poet-of-scale
25•pseudolus•3h ago•3 comments

Parse, Don't Validate (For C)

https://www.lelanthran.com/chap13/content.html
38•lelanthran•3d ago•10 comments

Experimental imperative-style music sequence generator engine

https://github.com/renoise/pattrns
5•bwidlar•3d ago•0 comments

Programming Affordances That Invite Mistakes

https://thetechenabler.substack.com/p/programming-affordance-when-a-languages
13•ingve•2d ago•1 comments

Lost Chapter of Automate the Boring Stuff: Audio, Video, and Webcams in Python

https://inventwithpython.com/blog/lost-av-chapter.html
143•AlSweigart•13h ago•8 comments

Light exposure at night predicts incidence of cardiovascular diseases

https://www.medrxiv.org/content/10.1101/2025.06.20.25329961v1
96•gnabgib•7h ago•61 comments

The fish kick may be the fastest subsurface swim stroke yet (2015)

https://nautil.us/is-this-new-swim-stroke-the-fastest-yet-235511/
203•bookofjoe•18h ago•137 comments

Two-step system makes plastic from carbon dioxide, water and electricity

https://phys.org/news/2025-06-plastic-carbon-dioxide-electricity.html
53•PaulHoule•3d ago•13 comments

A better Ghidra MCP server – GhidrAssistMCP

https://github.com/jtang613/GhidrAssistMCP
79•jtang613•12h ago•13 comments

Show HN: I made a JSFiddle-style playground to test and share prompts fast

https://langfa.st/
26•eugenegusarov•13h ago•3 comments

HNSW as abstract data structure: video intro to Redis vector sets

https://www.youtube.com/watch?v=kVApsFUeuEA
20•antirez•2d ago•0 comments

Second Variety, by Philip K. Dick (1953)

https://www.gutenberg.org/files/32032/32032-h/32032-h.htm
53•djoldman•3d ago•16 comments

Malware found in official gravityforms plugin indicating supply chain breach

https://patchstack.com/articles/critical-malware-found-in-gravityforms-official-plugin-site/
209•taubek•23h ago•43 comments

Supreme Court's ruling practically wipes out free speech for sex writing online

https://ellsberg.substack.com/p/free-speech
551•macawfish•12h ago•690 comments

New Date("wtf") – How well do you know JavaScript's Date class?

https://jsdate.wtf
312•OuterVale•22h ago•175 comments

Working through 'Writing A C Compiler'

https://jollygoodsw.wordpress.com/2025/03/13/working-through-writing-a-c-compiler/
135•AlexeyBrin•18h ago•32 comments

Exposing a web service with Cloudflare Tunnel (2022)

https://erisa.dev/exposing-a-web-service-with-cloudflare-tunnel/
95•sturza•3d ago•38 comments

New Windows 11 build adds self-healing "quick machine recovery" feature

https://arstechnica.com/gadgets/2025/07/new-windows-11-build-adds-self-healing-quick-machine-recovery-feature/
15•thunderbong•2h ago•4 comments

Proposed NOAA Budget Kills Program Designed to Prevent Satellite Collisions

https://skyandtelescope.org/astronomy-news/proposed-noaa-budget-kills-program-to-prevent-satellite-collisions/
330•bikenaga•14h ago•191 comments

Vibe-Coding a PCB – surprisingly good

https://atomic14.substack.com/p/vibe-coding-a-pcb-surprisingly-good
139•iamflimflam1•14h ago•60 comments

Show HN: DesignArena – crowdsourced benchmark for AI-generated UI/UX

https://www.designarena.ai/
70•grace77•15h ago•20 comments