Talk:Setcontext

message: 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);
 
 void 
 traverse (const char *root, traverse_cb_func traverse_cb, void *data) {
 	DIR *dirstream;
 	struct dirent entry, *res;
 
 	if (!(dirstream = opendir (root)))
 		return;
 	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);
 
 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);
 }
 
 int 
 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)
thread_title: Untitled

message: 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)
replies: text: 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)
replies: text: 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.
*:Yes.
*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?
*: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?
*:Indeed.
*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)

text: 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)
replies: text: 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)
replies: text: 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)
replies: text: 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)

text: 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)
replies: text: 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)
thread_title: Example

message: by iterator, does the text mean generator?  —Preceding unsigned comment added by 208.60.11.41 (talk) 16:55, 7 June 2008 (UTC)
replies: text:  Yes  —Preceding unsigned comment added by Adityazutshi (talk • contribs) 00:44, 18 November 2009 (UTC)
thread_title:  iterator 

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

message: 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 (talk • contribs) 14:09, 24 August 2009 (UTC)
thread_title:  Standards 

message: 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)
thread_title:  Example