Linux Newbie help
 help / color / mirror / Atom feed
From: Steven Smith <sos22@cam.ac.uk>
To: Lee Chin <leechin@mail.com>
Cc: linux-newbie@vger.kernel.org
Subject: Re: why does this program crash while using setcontext?
Date: Mon, 20 Jan 2003 14:32:40 +0000	[thread overview]
Message-ID: <20030120143236.GB2523@cam.ac.uk> (raw)
In-Reply-To: <20030120061001.72340.qmail@mail.com>

[-- Attachment #1: Type: text/plain, Size: 3920 bytes --]

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.

> ucontext_t mainucp;
> ucontext_t fooucp;
> int flag = 0;
char stack[SIGSTKSZ];

> int foo()
> {
>     printf("(2) foo setting context\n");

>     getcontext(&fooucp);
Kill this line - the foo context has already been constructed.

>     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.

>     }
>     printf("(3) foo done\n");
>     return 0;
> }

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

> 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.

>     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.

>     }
>     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.

>     }
Insert:
	return 0;
:)
> }

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.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

  reply	other threads:[~2003-01-20 14:32 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-01-20  6:10 why does this program crash while using setcontext? Lee Chin
2003-01-20 14:32 ` Steven Smith [this message]
  -- strict thread matches above, loose matches on Subject: below --
2003-01-20 16:12 Lee Chin
2003-01-21  8:13 Lee Chin
2003-01-21 16:39 ` Steven Smith

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030120143236.GB2523@cam.ac.uk \
    --to=sos22@cam.ac.uk \
    --cc=leechin@mail.com \
    --cc=linux-newbie@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox