Ask HN: What languages have true native cooperative multitasking?
and also, "how well did it work?"

But let me clarify exactly what I'm asking here, because concepts like "coroutines" or "cooperative multitasking" or "multiprocessing" get heavily influenced by their implementation in each language, and I'm asking for a very specific implementation.

In a stack-based function-call language, there is usually a simple API of blocking I/O where the state of each in-progress function is preserved on a stack as the entire thread of execution is paused until the completion of the I/O. This leads to very clear and easy-to-debug programs, usually with the added convenience of throwing and catching exceptions, but you can only process one I/O sequence (client/server conversation, etc) per thread. Moving to multiple threads or parallel processes lead to complex concurrency problems, and often don't scale well.

Languages usually also provide more complex secondary APIs for non-blocking I/O that allows a function to start an I/O operation and continue doing other things while checking the status of the I/O, or blocking on an event API to wake up when something is ready. Taken to its logical conclusion, the program becomes structured around an event loop, but the programmer must now track the on-going state of a particular I/O sequence in their own data structures without the convenience of a stack-based tree of function calls. You can no longer use normal language exceptions to abort a single I/O conversation because it is interleaved with other conversations and the logical call-tree is gone. The program must also avoid using any library which makes use of blocking APIs, dividing the library ecosystem into "blocking" and "nonblocking-compatible" halves.

One solution is to add co-routines to a language, where multiple function-call tree stacks are held in memory, and executed on a single thread. Any time a blocking API is used, the language starts the I/O operation then switches to another co-routine that is ready to run. In other words, the language manages the event loop hidden in the background while presenting the user with what appears to be normal threads, but without most of the hard synchronization that you need from true multithreading. The downsides are that an infinite loop on one "thread" will hang all others, and there might still be synchronization issues if I/O operations are interleaved with changes to data structures.

Most scripting languages provide something for co-routines, but usually requiring some invasive changes to the code that are not just the simple blocking APIs presented by the stock language. This leads to further fragmentation of the library ecosystem for the things that are "async compatible" or "coro compatible" etc.

Python: the generators act like independent call stacks, and were made into "co-routines" with a send() call, but these do not tie into the native blocking API read/write/sleep to perform event-driven I/O like I described above. The co-routines are also used like objects rather than called like normal functions.

JavaScript: JS has the Async/Await system which is almost what I describe, but they are exposed as keywords which must be used in the code, not passively compatible with other code using blocking I/O.

Perl: there is a Coro library that switches the interpreter stacks, but does not intercept the blocking I/O. There are several "AsyncAwait" modules, with the same caveat as JS.

There are so many languages out there, I'm sure that someone has already implemented intrinsic co-routines + non-blocking I/O exposed to the user as a simple blocking cooperative threads. I want to know which languages have tried this, and maybe more importantly, if you have worked on a project that used them, how well the idea works in practice.