EmbeddedRelated.com
Forums

goto across functions/isrs?

Started by galapogos December 12, 2006
Ali wrote:

> Arlet wrote: > > Arlet wrote: > > > > > It is possible to implement the effect without an OS, as long as the > > > CPU has an accessible stack. When the ISR notices that the device has > > > been disconnected, it can fix up the main stack. A relatively clean way > > > to do this, is by inserting the address of a special function on the > > > stack, so that when the ISR finished, you return to that special > > > function, where you can decide what to do (e.g. have a longjmp()). > > > > > > Something like this: > > > > > > signal( ) > > > { > > > // device disconnected, take action > > > clean_up( ); > > > longjmp( disconnect, 1 ); > > > } > > > > > > main( ) > > > { > > > setjmp( disconnect ); > > > while( 1 ) > > > { > > > wait_for_connect( ); > > > use_device(); > > > } > > > } > > > > > > In the ISR, the stack will look something like this > > > > > > 1. ISR saved registers > > > 2. CPU flags > > > 3. return address to somewhere in main > > > > > > If you notice a disconnect in the ISR, fix up the stack like this: > > > > > > 1. ISR saved registers > > > 2. CPU flags > > > 3. signal <--- insert this one > > > 4. return address to somewhere in main > > > > Forgot to mention that the signal handler may corrupt CPU state, so it > > must end in the longjmp(), or alternatively, declare it as an interrupt > > routine so it will preserve all necessary state. > > Design looks quite good but kind of overhead for saving and cleaning. > Why not use a label at the start of main routine while setting some > flag in ISR (which will be pooled in main wild loop)?
The OP wanted something like a goto, which can be implemented by longjmp(), at the cost of some memory space for the saved state. Setting a flag, and testing that in the main loop is also possible, but if the use_device() function is complicated, it may be necessary to test it at multiple places, which may cause a bigger overhead, both in time and space, and may clutter up the code. For cases which are considered to be exceptional, like a surprise device removal, using the signal/longjmp() method works well. With some extra code, it's even possible to pass some arguments to the signal() function, so it can react to specific types of events.
galapogos <goister@gmail.com> wrote:
> Hi, > Is it possible to goto a label that's not in the same functions? I've > always been taught that gotos are evil so I don't have much experience > with it, but I'm currently in a situation where I think I might have to > use it. > > I have an ISR that triggers when I detect an event, and based on that > event I want to unconditionally goto a label that's in main(). Is that > possible? If so what's the syntax? >
This sounds very dodgy. You're jumping out of an ISR without doing a proper return from the interrupt. A definite case for the Ministry of Dodgy Coding Practices and their Stack Abuses Police ;) pete -- pete@fenelon.com "he just stuck to buying beer and pointing at other stuff"
galapogos wrote:
> Vladimir Vassilevsky wrote: >> galapogos wrote: >> >>> Hi, >>> Is it possible to goto a label that's not in the same functions? >> Yes. >> >> I've >>> always been taught that gotos are evil >> No. >> >> so I don't have much experience >>> with it, >> I can see that. >> >> but I'm currently in a situation where I think I might have to >>> use it. >> No. >> >> >>> I have an ISR that triggers when I detect an event, and based on that >>> event I want to unconditionally goto a label that's in main(). Is that >>> possible? If so what's the syntax? >> longjmp() >> >> However what are you trying to do does not make much sense. > > OK what I'm trying to do is as follows. > > I have an isr that is called every 20ms that checks if something is > connected. If so it changes a global state variable to "connected". In > my main() I have a loop that checks if the device is connected. If it's > not it keeps looping doing nothing. If it is, then it will start to > talk to the device. This works fine if the device is connected and > stays connected, but it doesn't work so well if a stupid user decides > to suddenly disconnect the device halfway. What I'm trying to do is > that on disconnection detection in my ISR, I can unconditionally jump > to the beginning of the main() loop where it does the state checking so > that my main() doesn't continue to try and talk to the device only to > suddenly find it not there and getting all sorts of weird errors. If I > don't use goto, I'd have to check the state of the connection at > multiple locations within the loop(basically at every > instruction/command that I try to send to the device), which is quite a > hassle I think. >
Your ISR could simply force a reset if there is a disconnection. Easy to understand, and no overhead (in either programming time or run time).

Tim Wescott wrote:

> Vladimir Vassilevsky wrote: > >> galapogos wrote: >>> >>> I have an isr that is called every 20ms that checks if something is >>> connected. If so it changes a global state variable to "connected". In >>> my main() I have a loop that checks if the device is connected.
>> >> Implement the processing function as a thread. Kill the thread if the >> device gets disconnected. >> > That assumes that the OP is using an OS. If he's got a task loop in > main() that kind of implies no OS.
This can be done by a manipulation with the CPU context in SST-like pseudo RTOS or even without RTOS. A hack just for mental exercise. :)
> He should just bite the bullet and test all over the place, or pay some > $$ for an RTOS.
You betcha. The question indicates the design or concept level problems. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
Vladimir Vassilevsky wrote:

> > > Tim Wescott wrote: > >> Vladimir Vassilevsky wrote: >> >>> galapogos wrote: >>> >>>> >>>> I have an isr that is called every 20ms that checks if something is >>>> connected. If so it changes a global state variable to "connected". In >>>> my main() I have a loop that checks if the device is connected. > > >>> >>> Implement the processing function as a thread. Kill the thread if the >>> device gets disconnected. >>> >> That assumes that the OP is using an OS. If he's got a task loop in >> main() that kind of implies no OS. > > > This can be done by a manipulation with the CPU context in SST-like > pseudo RTOS or even without RTOS. A hack just for mental exercise. :) >
Actually, if he had decided to use an SST-like pseudo RTOS (or real time pseudo OS, to be more precise), it wouldn't be a problem because he would never stop in the middle of the loop -- the function would do one operation, change its state, and return. So checking for a disconnect would be simple. One of the responses in this thread did make me think that you could arrange the ISR to load the stack with just the right evil combination of stuff such that when you hit the 'iret' instruction you'd be in main() right before the while loop. Once you've done this and debugged it you may as well have used an RTOS, however.
> >> He should just bite the bullet and test all over the place, or pay >> some $$ for an RTOS. > > > You betcha. The question indicates the design or concept level problems. >
I think you are correct. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Posting from Google? See http://cfaj.freeshell.org/google/ "Applied Control Theory for Embedded Systems" came out in April. See details at http://www.wescottdesign.com/actfes/actfes.html
On 12 Dec 2006 19:47:25 -0800, "visweswara" <r.visweswara@gmail.com>
wrote in comp.arch.embedded:

> You can unconditionally branch to any label using inline asm code. ( > Few compiler support it).As like gotos it is very poor practice to call > a function from ISR. It is a always advisable to keep ISR very short. > You can use flag polling. > > Visweswara R
It doesn't make any difference what a compiler supports. You are jumping into the middle of foreground code that expects a particular stack frame with particular data on it, particular values in registers, and quite a few other things. If you enter foreground code from an ISR, the context and the stack are all wrong. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
On Wed, 13 Dec 2006 17:03:14 -0800, Tim Wescott <tim@seemywebsite.com>
wrote:

>Vladimir Vassilevsky wrote: > >> >> >> Tim Wescott wrote: >> >>> Vladimir Vassilevsky wrote: >>> >>>> galapogos wrote: >>>> >>>>> >>>>> I have an isr that is called every 20ms that checks if something is >>>>> connected. If so it changes a global state variable to "connected". In >>>>> my main() I have a loop that checks if the device is connected. >> >> >>>> >>>> Implement the processing function as a thread. Kill the thread if the >>>> device gets disconnected. >>>> >>> That assumes that the OP is using an OS. If he's got a task loop in >>> main() that kind of implies no OS. >> >> >> This can be done by a manipulation with the CPU context in SST-like >> pseudo RTOS or even without RTOS. A hack just for mental exercise. :) >> >Actually, if he had decided to use an SST-like pseudo RTOS (or real time >pseudo OS, to be more precise), it wouldn't be a problem because he >would never stop in the middle of the loop -- the function would do one >operation, change its state, and return. So checking for a disconnect >would be simple. > >One of the responses in this thread did make me think that you could >arrange the ISR to load the stack with just the right evil combination >of stuff such that when you hit the 'iret' instruction you'd be in >main() right before the while loop. Once you've done this and debugged >it you may as well have used an RTOS, however.
Isn't that what setjmp and longjmp is basically supposed to do ? The only problem one probably have to take care of otherwise in this context is the fact that one is jumping from an ISR to a non ISR routine. If the architecture uses a single stack for calls and interrupts, then one probably just need to take care of the actual interrupt state.
>>> He should just bite the bullet and test all over the place, or pay >>> some $$ for an RTOS.
Using an RTOS does not automatically prevent such a problem. If the program was structured incorrectly then one can still end up having to check all over the place to see if the device is still present. For me it is clear that the OP did not forsee the consequences of the device suddenly dissappearing. If he had , he would probably have changed his design so that his current ptoblem would not have had existed.
>> >> You betcha. The question indicates the design or concept level problems. >> >I think you are correct.
I agree as well. Regards Anton Erasmus

Tim Wescott wrote:

>>>> galapogos wrote: >>>>> I have an isr that is called every 20ms that checks if something is >>>>> connected. If so it changes a global state variable to "connected". In >>>>> my main() I have a loop that checks if the device is connected. >> >>>> >>>> Implement the processing function as a thread. Kill the thread if >>>> the device gets disconnected. >>>> >>> That assumes that the OP is using an OS. If he's got a task loop in >>> main() that kind of implies no OS. >> >> This can be done by a manipulation with the CPU context in SST-like >> pseudo RTOS or even without RTOS. A hack just for mental exercise. :) >> > Actually, if he had decided to use an SST-like pseudo RTOS (or real time > pseudo OS, to be more precise), it wouldn't be a problem because he > would never stop in the middle of the loop -- the function would do one > operation, change its state, and return. So checking for a disconnect > would be simple.
Here is another solution: run the processing loop as the very bottom task in the SST, and run everything else as the different SST tasks. In this case, one can alter the context of main() while keepeng everything else alive. This requires hacking of the stack frame.
> One of the responses in this thread did make me think that you could > arrange the ISR to load the stack with just the right evil combination > of stuff such that when you hit the 'iret' instruction you'd be in > main() right before the while loop.
That would be difficult if there are any other interrupts and tasks. Also it is very position dependent. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
Vladimir Vassilevsky wrote:

> Here is another solution: run the processing loop as the very bottom > task in the SST, and run everything else as the different SST tasks. In > this case, one can alter the context of main() while keepeng everything > else alive. This requires hacking of the stack frame. > > > > One of the responses in this thread did make me think that you could > > arrange the ISR to load the stack with just the right evil combination > > of stuff such that when you hit the 'iret' instruction you'd be in > > main() right before the while loop. > > That would be difficult if there are any other interrupts and tasks. > Also it is very position dependent.
That's why I suggested hacking the stack frame to insert a call to a signal handler instead. The signal handler has a well defined label, so there are no position dependency issues. For maximum flexibility, the handler could even be registered at run-time. On a multitasking system, it is possible to rewrite the stack frame of a particular task, rather than the interrupted one. You can even stack multiple signals for the same task. A bitmask in the task struct could be used to avoid duplicates.
visweswara wrote:
> You can unconditionally branch to any label using inline asm code. ( > Few compiler support it).As like gotos it is very poor practice to call > a function from ISR. It is a always advisable to keep ISR very short. > You can use flag polling.
Sorry, but what are the pittfalls of calling functions from ISR? Anyway, thanks for all the help so far. A lot of this is over my head, I'm still pretty new to embedded programming. Anyway, I think I'm fine with just checking for the flag all over the place :)