I recently posted here about my "sort of" #async / #await implementation in #C, for the exact same purpose as you might know from #csharp ... (of course with a much less "elegant" usage)

I finally attempted to really explain it over here on reddit, in case anyone is interested:

https://www.reddit.com/r/C_Programming/comments/1lkv2f1/an_asyncawait_sort_of_implementation_in_c_using/

#POSIX #C #coding

@zirias This is super clever! Turning C into async mode with just macros? Loved the breakdown on Reddit. Quick question: how does it hold up with nested async calls or errors?

@codegax Hey, thanks! Although there are no macros involved, no idea how that misunderstanding could happen? But the code is indeed quite small ... because the technical complexity is hidden by whatever implements the POSIX user context switching, which needs assembler code.

I just realized some example how it is *used* should also be shown, so I added a comment over there.

Regarding your questions, errors is easy to answer, they need explicit handling, as usual in C. Completion of the task gives a generic "void *result" back to where the task is awaited, so if errors are possible, it's the callers responsibility to define a type for the result that can transport them.

Regarding nested async calls, they would make no sense here, I'll try to explain. The scenario is some event-driven #C code. This typically works using function pointers for callbacks. So, the code doing that is already "async", but explicitly: To wait for some I/O, you trigger it, and register a callback for when it completes, which then contains whatever has to happen next. And IMHO, that's fine as long as you can think of your logic that way, IOW it's by nature reacting on I/O. Waiting for some HTTP request, parsing it when it arrives, I'm fine with having all of that written in this callback style.

But then, a common pattern for *handling* requests in a flexible way is to build a *pipeline* for that, which is typically just a stack of function calls that can be configured. And that's fine as long as you don't need any additional I/O while handling the request. My awaitable async task aims at keeping the logical code structure for cases when this *is* necessary. But once you're awaiting such a task, it's implementation is executed as a callback on a thread following this classic event-driven model, so if you'd need to "nest" there, you wouldn't need another async task, instead just more callbacks. 😉 This is very different from "modern" async #csharp code, which would use the awaiting mechanism for everything, completely hiding any event/callback scheme.