[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Sub-Function Pointer

From: René Liebscher
Subject: Re: [avr-gcc-list] Sub-Function Pointer
Date: Mon, 28 Jun 2004 12:08:53 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040617

Richard Urwin wrote:
On Monday 28 Jun 2004 7:47 am, Nick Brent wrote:

Hello All,

   I'm trying to write a small RTOS and I'm having a bit of trouble
with re-enabling tasks when they're ready. The question,
specifically, that I have is what happens when you call a
sub-function from main or another function? If I had to guess, I'd
assume the new address of the function being called is pushed onto
the stack, and when the function exits, the address is popped off and
the original address is loaded. Am I right?


I'm sure it's a little more involved than that.

No ;-)

I couldn't seem to find an explanation in the avr-libc user manual,

You wont. It might be in the datasheet for the processor, or the instruction set, though.

so I'm hoping someone can explain it to me.

When a function is called some of the parameters are pushed onto the stack, others may be passed in registers. Then the CALL instruction pushes the currently executing address onto the stack and then jumps to the new function.

When the function finishes the RET instruction pops the currently executing address off the stack. This means the processor jumps to the instruction after the CALL instruction in the original function. The original function then removes any parameters it had pushed.

   The problem that I'm running into is that I'm using lngjmp() to
restore the context of a task, which is working just fine, but when
it leaves the sub-function it just jumped back to, it goes to the
last function that was left, not the one that was left before the
context was saved. I don't know if that makes much sense, but a brief look at setjmp() and lngjmp() in the avr-libc user manual should
explain it a little better.

I'm not convinced that you can use setjmp and longjmp like that. setjmp remembers the stack state as it is. Subsequently a longjmp will return to that state, but if you return from the function that called setjmp, or longjmp up past it, then that setjmp data is no longer valid.

Say your stack looked like this:

If you execute a longjmp(X,v), then the stack looks like this:

So you can never thereafter execute longjmp(Y,v).

Note that the stack actually looks like this:

So longjmp(Y,v) might still appear to work, (depending on how it was implemented.) But any interrupts and any pushing onto the stack between the longjmp(X,v) and the longjmp(Y,v) would corrupt the stack. Never, ever, use data that has been popped off the stack. (By Murphy's Law, it may work while you're testing, but it wont work in the field, and it's a really nasty bug to find.)

So if your code for context switching looks like:


It wont work.

You have to use another stack frame for the other tasks, then it works.
So if you want to create a new task (TASKB), get a piece of memory for it, set the stack pointer into it, make setjmp(TASKB) and then back to the creating task with longjmp(TASKA) (you must made a setjmp(TASKA) before staing creating the new task.)

Then it should work

and back

Because both use different stacks there is no problem. Interrupts use the current stack. Interrupts should be disabled if you are switch the context and interrupts should not switch the context.

Have a look at
there is a section "Implementation"
(it is documention to http://www.gnu.org/software/pth/)
I'm sure you can find more documentation about this topic in other thread libraries too.

Kind regards

reply via email to

[Prev in Thread] Current Thread [Next in Thread]