why does this program crash while using setcontext?
Steven
One thing I dont understand is why if I use setcontext instead of swapcontext in the following program, I crash? Look at where I commented out my swapcontext
Thanks
Lee
#include <ucontext.h>
#include <stdio.h>
#include <setjmp.h>
ucontext_t mainucp;ucontext_t fooucp;
char stack[SIGSTKSZ];
int flag = 0;
int foo()
{
printf("(2) foo setting context\n");
if (!flag)
{
flag = 1;
swapcontext(&fooucp, &mainucp);
}
printf("(3) foo done\n");
return 0;
}void eleven()
{
printf("(1) calling foo\n");
foo();
printf("(4) foo now finished\n");
}void ten()
{
eleven();
}void nine()
{
ten();
}void eight()
{
nine();
}void seven()
{
eight();
}void six()
{
seven();
}void five()
{
six();
}void four()
{
five();
}void three()
{
four();
}void two()
{
three();
}void one()
{
two();
}int main()
{
getcontext(&fooucp);
fooucp.uc_link = &mainucp;
fooucp.uc_stack.ss_sp = stack;
fooucp.uc_stack.ss_size = sizeof(stack);
makecontext(&fooucp, one, 0);
getcontext(&mainucp);
printf("(1, 2.2) main checking flag flag\n");
if (!flag)
{
setcontext(&fooucp);
}
else
{
printf("(2.5) main again\n");
// HERE IS WHERE I COMMENTED OUT
// swapcontext(&mainucp, &fooucp);
setcontext(&fooucp);
}
}~
~
----- Original Message -----
From: Steven Smith <[email protected]>
Date: Mon, 20 Jan 2003 14:32:40 +0000
To: Lee Chin <[email protected]>
Subject: Re: why does this program crash while using setcontext?
Quoted 126 lines
I think this problem is largely my fault; I should have been more clear last time I posted. Feel free to insult me.
I think the program below is trying to:
1) have
main()record its context immediately. Call this the main context.
2) Callfoo()indirectly throughone().
3) Record foo()'s context. Call this the foo context.
4) Switch back to the main context.
5) Switch back to the foo context.
6) Return back fromfoo()tomain()and then exit.Now, the problem is that the various contexts are all running on the same stack. This means that the bit of
main()which runs between steps 4 and 5 is mangling the foo context, and so step 6 doesn't work.The way to avoid this is to have the two contexts operating on different stacks. The main context can happily run on the process stack, but one will need to be allocated for the foo context. An array of chars is perfectly good for this; the usual size is SIGSTKSZ, defined in
signal.h. In addition, we need to tell the ucontext functions to use this stack. Unfortunately, there's no (easy) way to copy the current stack onto the context stack, and so we need to usemakecontext()rather thangetcontext().This means the design of the program looks more like this:
1) Have
main()record its context. Call this the main context.
2) Havemain()construct a context which will invokefoo()on a different stack. Call this the foo context.
3) Havemain()invoke the foo context.
4) Switch back to the main context.
5) Switch back to the foo context.
6) Let the foo context return. This will cause the context library to automatically switch back to the main context, which can then return and exit the program.I've shown these changes below.
Quoted 3 lines
ucontext_tmainucp;ucontext_tfooucp;
int flag = 0;char stack[SIGSTKSZ];
Quoted 5 lines
int
foo(){ printf("(2) foo setting context\n"); getcontext(&fooucp);Kill this line - the foo context has already been constructed.
Quoted 5 lines
if (!flag) { flag = 1; setcontext(&mainucp);Replace this line with:
swapcontext(&fooucp, &mainucp);We need
swapcontext()rather thansetcontext()so as the foo context resumes from here, rather than the entry toone(), which would cause an infinite loop.Quoted 4 lines
} printf("(3) foo done\n"); return 0; }<snip deeply nested call to
foo()fromone()>Quoted 2 lines
int
main()
{Insert
getcontext(&fooucp); fooucp.uc_link = &mainucp; fooucp.uc_stack.ss_sp = stack; fooucp.uc_stack.ss_size = sizeof(stack); makecontext(&fooucp, one, 0);The
uc_linkline says to return the main context if the foo context ever returns. Theuc_stacklines are just setting up the stack, and themakecontext()modified the foo context so that it callsone()with 0 arguments.For various reasons, primarily historical, contexts which are passed to
makecontext()must first be initialised withgetcontext(), even thoughmakecontext()overwrites or makes redundant 95% of the work whichgetcontext()did.Quoted 5 lines
getcontext(&mainucp); if (!flag) { one();Replace this line with
setcontext(&fooucp);Note that this is
setcontext()and notswapcontext(); if we usedswapcontext(), then the main context would resume from here rather than the call togetcontext(), above, and so the else branch of the if would never run.Quoted 6 lines
} else { printf("(2.5) main again\n"); setcontext(&fooucp);Replace this line with
swapcontext(&mainucp, &fooucp);We need
swapcontext()here, rather thansetcontext(), because we want the main context to resume here rather than at thegetcontext(), to avoid an infinite loop.Quoted 1 line
}Insert:
return 0;:)
Quoted 1 line
}
Hopefully, that's a little clearer.
In general, it's a good idea to use
swapcontext()rather thansetcontext()if at all possible, because then functions return to the same place as they were called from, which is a lot easier to think about.Steven.
Signature · 12 lines
__________________________________________________________ Sign-up for your own FREE Personalized E-mail at Mail.com http://www.mail.com/?sr=signup Meet Singles http://corp.mail.com/lavalife - To unsubscribe from this list: send the line "unsubscribe linux-newbie" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.linux-learn.org/faqs
One day, I'll learn to think before posting, and possibly check that whatever I'm suggesting actually works...
Quoted 3 lines
One thing I dont understand is why if I use setcontext instead of swapcontext in the following program, I crash? Look at where I commented out my swapcontext
The problem here is that the foo context is being invoked twice with the same set of registers, but a different stack setup.
The first time foo is invoked, it runs through one(), setting up a return stack in the stack buffer, before invoking the main context. The main context then re-invokes the foo context, which returns back through its call stack, destroying it in the process. main then invokes foo again, resulting in weird stack corruption problems and a crash. One possible fix is shown below.
Quoted 8 lines
#include <
ucontext.h>
#include <stdio.h>
#include <setjmp.h>
ucontext_tmainucp;ucontext_tfooucp;char stack[SIGSTKSZ];
Add another stack buffer:
char ostack[SIGSTKSZ];
<snip unchanged code>
Quoted 2 lines
int
main()
{
Add
volatile int count; count = 0;
This counts the number of times the main context has resumed.
Quoted 2 lines
getcontext(&fooucp);
fooucp.uc_link = &mainucp;Note that when the foo context returns, the main context is invoked immediately i.e. without trying to save foo's registers (which wouldn't actually make much sense). This means that the foo context now contains registers suitable for running foo(), but a stack suitable for running the end of one(). This is a bad thing.
Quoted 4 lines
fooucp.uc_stack.ss_sp = stack;
fooucp.uc_stack.ss_size = sizeof(stack);
makecontext(&fooucp, one, 0);
getcontext(&mainucp);Add
if (count == 1) {
memcpy(ostack, stack, sizeof(stack));
} else if (count > 1) {
memcpy(stack, ostack, sizeof(stack));
}
count++;This saves a copy of the foo context's stack the first time it switches to main, and then restores it on later occasions. This is ugly, but it's probably the only way you're going to be able to re-use contexts which have returned.
Quoted 11 lines
printf("(1, 2.2) main checking flag flag\n");
if (!flag)
{
setcontext(&fooucp);
}
else
{
printf("(2.5) main again\n");
setcontext(&fooucp);
}
}I should probably apologise for not going into nearly enough detail for such an obscure API.
Steven.