avr-gcc-list
[Top][All Lists]
Advanced

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

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


From: Richard Urwin
Subject: Re: [avr-gcc-list] Sub-Function Pointer
Date: Mon, 28 Jun 2004 09:48:27 +0100
User-agent: KMail/1.5.3

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?

No.

> 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:
top->dataF
     dataE
     setjmpY
     dataD
     dataC
     setjmpX
     dataB
     dataA

If you execute a longjmp(X,v), then the stack looks like this:
top->dataB
     dataA

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

Note that the stack actually looks like this:
     dataF
     dataE
     setjmpY
     dataD
     dataC
     setjmpX
top->dataB
     dataA

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:

setjmp(TASKA);
longjmp(TASKB,v);

It wont work.

-- 
Richard Urwin


reply via email to

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