From Wikipedia, the free encyclopedia
Jump to: navigation, search
WikiProject C/C++  
WikiProject icon This article is within the scope of WikiProject C/C++, a collaborative effort to improve the coverage of C/C++ on Wikipedia. If you would like to participate, please visit the project page, where you can join the discussion and see a list of open tasks.
 ???  This article has not yet received a rating on the quality scale.
 ???  This article has not yet received a rating on the importance scale.


Here's a slightly more complex example. It illustrates the idea that coroutines can be used to convert a callback-based library function to one employing an iterator pattern, thus allowing both sides of the function call to enjoy natural control flow and automatic memory management.

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

/* Implementation of a callback-oriented library function for traversal of a 
 * directory tree */

typedef void (*traverse_cb_func) (const char *path, struct stat *st_buf, 
                void *data);

traverse (const char *root, traverse_cb_func traverse_cb, void *data) {
        DIR *dirstream;
        struct dirent entry, *res;

        if (!(dirstream = opendir (root)))
        while ((readdir_r (dirstream, &entry, &res) == 0) && (res != NULL)) {
                char path[NAME_MAX + 1];
                struct stat st_buf;

                snprintf (path, NAME_MAX + 1, "%s/%s", root, entry.d_name);
                stat (path, &st_buf);
                traverse_cb (path, &st_buf, data);
                if (entry.d_type == DT_DIR && entry.d_name[0] != '.')
                        traverse (path, traverse_cb, data);
        closedir (dirstream);

/* Generic code to transform a callback-oriented library function to use the 
 * iterator pattern */

typedef struct {
        ucontext_t finish_uc, loop_uc, iterator_uc;
        char iterator_stack[SIGSTKSZ];
        int has_started;
        void *user_return;
} cb_iter_t;

typedef void (*cb_cb_func) (void);
typedef void (*cb_begin_func) (void *user_data, 
                cb_cb_func cb_func, cb_iter_t *cb_iter);
typedef void (*cb_collect_func) (void);

cb_collect_func_complete (void *user_return, cb_iter_t *data) {
        data->user_return = user_return;
        swapcontext (&data->iterator_uc, &data->loop_uc);

cb_iter_t *
cb_iter_begin (cb_begin_func begin_func, cb_collect_func collect_func, 
                void *user_data) {
        cb_iter_t *cb_iter = malloc (sizeof (cb_iter_t));

        cb_iter->iterator_uc.uc_link = &cb_iter->finish_uc;
        cb_iter->iterator_uc.uc_stack.ss_sp = cb_iter->iterator_stack;
        cb_iter->iterator_uc.uc_stack.ss_size = sizeof cb_iter->iterator_stack;
        getcontext (&cb_iter->iterator_uc);
        makecontext (&cb_iter->iterator_uc, (void (*) (void)) begin_func, 
                        3, user_data, collect_func, cb_iter);
        cb_iter->has_started = 0;
        return cb_iter;

void *
cb_iter_next (cb_iter_t *cb_iter) {
        if (!cb_iter->has_started) {
                volatile int has_run = 0;
                getcontext (&cb_iter->finish_uc);
                if (has_run) {
                        free (cb_iter);
                        return NULL;
                has_run = 1;
        swapcontext (&cb_iter->loop_uc, &cb_iter->iterator_uc);
        return cb_iter->user_return;

/* Main code */

typedef struct {
        const char *root;
        cb_iter_t *cb_iter;
        const char *path;
        struct stat *st_buf;
} tr_data;

static void
begin_cb (tr_data *data, void (*cb_func) (void), cb_iter_t *cb_iter) {
        data->cb_iter = cb_iter;
        traverse (data->root, (traverse_cb_func) cb_func, data);

static void
collect_cb (const char *path, struct stat *st_buf, tr_data *data) {
        data->path = path;
        data->st_buf = st_buf;
        cb_collect_func_complete (data, data->cb_iter);

main (void) {
        cb_iter_t *cb_iter;
        tr_data data;

        data.root = "/tmp";
        if ((cb_iter = cb_iter_begin ((cb_begin_func) begin_cb, 
                                        (cb_collect_func) collect_cb, 
                                        &data)) != NULL)
                while (cb_iter_next (cb_iter) != NULL)
                        printf ("%s %ld\n", data.path, data.st_buf->st_size);
        return 0;

EdC 00:30, 18 July 2006 (UTC)

Diaeresis on "coöperative"[edit]

It's a variant spelling, favoured by the Economist and the New Yorker – oh, and by the first significant contributor. Me. It stays. EdC 01:29, 5 August 2006 (UTC)

For the record, The Economist has no diaeresis in sight. The New Yorker uses it, but not consistently; and according to the relevant commentary on the web[1][2][3][4][5], and Wikipedia itself, this usage is considered an unconventional idiosyncracy of The New Yorker's house style, and not at all a feature of common English. No dictionary I could find even mentions the spelling. (They acknowledge the co-operative variant, but that's about it).
So, i think this spelling clearly fails the Manual of Style's most basic requirements. The policy is intended to prevent senseless edit wars over commonly-accepted (national, regional) spelling variants, not to give equal footing to orthographic oddities used self-consciously by individual publications, in defiance of global convention. --Piet Delport 15:19, 5 August 2006 (UTC)
Yeah, I was just feeling combative; I like that spelling. Sorry for putting you to so much research. EdC 19:33, 5 August 2006 (UTC)
I like it too, to be honest. :) My other native language, Afrikaans, uses the diaeresis for this purpose in all spellings. --Piet Delport 22:59, 5 August 2006 (UTC)


Is the example on this page really the best we can come up with? I'm not familiar with the functions and after looking at the example I'm not really much wiser. Anyone more familiar want to tidy it up a bit and add some comments? NicM 22:31, 10 December 2006 (UTC).

Well, it makes sense to me, but that just signifies that I'm beyond saving. I could pepper it with comments, but I'm not sure whether that'd help all that much -- which particular line(s) are you having trouble with? EdC 19:33, 11 December 2006 (UTC)
Looking at it more closely, I think I can mostly see what it is doing :-). It isn't just specific lines, you just have to look closely to see what is happening and this could be helped using comments, or a brief description before the code, particularly for the non-C programmer:
  • I think the code iterates over a loop and prints each item, but this isn't explicitly mentioned anywhere.
  • Why are half the variables volatile?
    Because otherwise, the compiler might perform constant propagation (on has_run) or other tricks.
  • What is yield_path for?
    Oops. It shouldn't be there. I'll remove it.
  • The makecontext call could definitely do with a comment explaining what it is doing.
    Sure, but I don't know what that comment would be, other than reiterating the spec of makecontext above.
  • has_run is there to prevent the loop being rerun when we get back to main_uc, right?
  • We get back to the getcontext line just outside the if, right? I presume this happens via uc_link when loop_iter exits normally rather than calling swap_context, am I right?
  • Is there any way to express how this form of code would be of practical use? I know it is meant to be a simple illustration, but it does seem a bit contrived, a few /* In a real program, X would happen here. */ or /* Here Z could be added to make Q happen in real use. */ wouldn't go amiss.

I know these are complicated functions to use, but a few comments would definitely help. I expect I know C a lot better than most Wikipedia readers so if I need a few minutes to figure it out, it is probably a lost cause for many others. NicM 08:16, 12 December 2006 (UTC).

Does the example on this page help much? The thing is, setcontext is so versatile it's difficult to pick out a single pattern that it enables. Iterator pattern? Parser? Responsiveness during complex calculations? EdC 21:42, 13 December 2006 (UTC)
I think the example on this page is probably too long, and I see your point about multiple uses: I think the current example demonstrates how it works fine, it might just be nice to show something that you couldn't do trivially without setcontext. Anyway, I've reformatted the article a lot (combine tiny sections/paragraphs, wikifying etc), and added comments to the example. If you would take a look and fix anything that is misleading it would be great. It is rather a pity about lack of return value from getcontext, you'd think at least one of the designers would have used fork(2) at some point in their life. Maybe the implementation makes it difficult. NicM 11:37, 14 December 2006 (UTC).
Yep, looks good. I've squashed the code to fit into 80 columns and added a few more comments to make things clear. I believe the lack of return value from getcontext is related to the problems with setjmp, which has a return value but places rigid restrictions on how it can be used in an expression or conditional. EdC 20:37, 14 December 2006 (UTC)
Looks good. Yeah, those conditions are part of why setjmp is such a pain in the ass. I guess they decided that having nothing was better than having something weird. NicM 21:05, 14 December 2006 (UTC).

The given example does not work on amd64, because makecontext can only pass int (32bit on amd64), not pointers (64bit). It is merely luck if that example does not crash. (talk) 21:42, 4 February 2009 (UTC)

I've reorganized the warning text to be in one place, after the example. This gives a better overall effect within the article. I also tuned it to be more encyclopedic in phrasing and linked to the architecture that is problematic. Donal Fellows (talk) 09:43, 9 February 2009 (UTC)
Could the example be rewritten to use C99 stdint.h constructs to remove the discussed bug, and then the note could be removed? Also, perhaps a smaller/simpler example could be constructed by translating the Scheme example from the Continuations article to C and using setcontext? MrSteve (talk) 13:05, 15 May 2009 (UTC)


by iterator, does the text mean generator? —Preceding unsigned comment added by (talk) 16:55, 7 June 2008 (UTC)

Yes —Preceding unsigned comment added by Adityazutshi (talkcontribs) 00:44, 18 November 2009 (UTC)

Should mention "continuations"?[edit]

Should this page mention continuations? MrSteve (talk) 13:05, 15 May 2009 (UTC)


The foocontext family of functions were obsolescent in POSIX.1-2004 and in POSIX.1-2008 they were removed. —Preceding unsigned comment added by PedroLamarao (talkcontribs) 14:09, 24 August 2009 (UTC)

Anyone planning on mentioning this fact in the actual article? — Preceding unsigned comment added by (talk) 12:38, 6 October 2013 (UTC)


I don't understand the example currently given in the article. What does it do, what is it good for? What is the thread of execution, i.e. what gets called in which order? Thank you for help. --Abdull (talk) 15:32, 31 January 2010 (UTC)