Coroutines in C (2000)
chiark.greenend.org.uk
chiark.greenend.org.uk
- [0] https://byuu.org/library/libco/
- [1] https://fluentbit.io
Rust actually had stackless coroutines in the past (libgreen), but moved from it due to the overhead it brought for code that didn’t require it.
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.
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 < argc) {
K->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 < argc) {
K->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)CoroutineTS uses coroutines that are implemented on the LLVM-IR level, as a result they get optimized away in many cases.
Unfortunately the CoroutineTS has also some design flaws around allocations and ownership
accountname @gmail.com
if you're interested we can go over the interrupt path, its pretty straightforward at that point. by flipping the control flow around, the virtio virtqueue support for example becomes nice and self-contained. it provides an interrupt continuation to the interrupt layer, and each queue is initialized with a continuation to call on a dequeue. vector assignment is still a bit cross-cutting.
I would still encourage that you put it up somewhere with a license of your choice. Many would get an opportunity to learn a thing or two.
There are implementations that use the GCC goto and label pointer, which then avoid the need for a switch statement.
In lining the answer.
> 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)
if (c == 0xFF) {
len = getchar();
c = getchar();
while (len--)
emit(c);
}The code snippet itself is run length encoding with 0xff as an escape.
Not on 27" with browser in full screen.
I have a 24" (16:9) screen turned 90°, which works wonders for full screen web pages.
Admittedly we would all lose this habit quicker if resizing windows wasn't such a finicky process in most OSs
sadly abandoned it seems, and not well-known, but is well-working in both win7 and win10. With a keyboard shortcut it's easy to resize any window and at the same time position them on the screen.
Also makes it easy to "save" windows that have slightly bad size or position so it's hard to position the mouse pointer in the resize corner.
On my wish list is that after bringing up the application, instead of using the mouse to select grid, I should be able to use eg arrow keys and shift to select them.
That way it's easy for everyone to make their own choices. If you want 27" wide lines of text, go ahead and full-screen that browser and have at it. If you want the text you're reading to take up less horizontal real estate than that, then you can easily make the browser itself as wide or narrow as you like.
If you're viewing documents, they're typically more vertically than horizontally oriented. That is, the parts you need to see more of are above/below of the viewable portion, not left/right of the viewable portion. So a browser being used for reading is often more useful when it takes up maybe half the screen on a high-res/large monitor.
If you're accessing webapps, that have more objects arranged horizontally, then going fullscreen may be more useful (think Trello boards and other things).
CMD and + to zoom in on Mac
or CTRL/CMD and scroll wheel to zoom in/out depending on direction scrolled.
Or are you using an ancient browser without zoom?
If you add {max-width: 60em; margin: auto;} to the body tag it looks much better.
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 it CodeWarrior?) open in another.
I haven't found something similar for Windows, but I'm sure there is one.
And it also works when I want to play games, or watch anything recorded in landscape, which is most media.
def function():
for i in range(10):
yield i