Skip to contentSkip to conversation

why does this program crash while using setcontext?

DISCUSSION Lee Chin 1 participant 1 message Jan 20, 2003

lore
Share & tools
lore

Lee Chin

author
#0 lore raw

Thanks Steven... this works great... I now understand this api well thanks to you!

Best Wishes,
Lee
----- 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) Call foo() indirectly through one().
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 from foo() to main() 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 use makecontext() rather than getcontext().

This means the design of the program looks more like this:

1) Have main() record its context. Call this the main context.
2) Have main() construct a context which will invoke foo() on a different stack. Call this the foo context.
3) Have main() 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_t mainucp;
ucontext_t fooucp;
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 than setcontext() so as the foo context resumes from here, rather than the entry to one(), which would cause an infinite loop.

Quoted 4 lines
    }
    printf("(3) foo done\n");
    return 0;
}

<snip deeply nested call to foo() from one()>

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_link line says to return the main context if the foo context ever returns. The uc_stack lines are just setting up the stack, and the makecontext() modified the foo context so that it calls one() with 0 arguments.

For various reasons, primarily historical, contexts which are passed to makecontext() must first be initialised with getcontext(), even though makecontext() overwrites or makes redundant 95% of the work which getcontext() did.

Quoted 5 lines
    getcontext(&mainucp);
    if (!flag)
    {

        one();

Replace this line with

	setcontext(&fooucp);

Note that this is setcontext() and not swapcontext(); if we used swapcontext(), then the main context would resume from here rather than the call to getcontext(), 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 than setcontext(), because we want the main context to resume here rather than at the getcontext(), 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 than setcontext() 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